Merge pull request #1049 from Molecule-AI/feat/platform-native-hma-instructions

feat(runtime): inject HMA memory instructions at platform level (#1047)
This commit is contained in:
molecule-ai[bot] 2026-04-20 08:47:20 -07:00 committed by GitHub
commit d3b310e895
3 changed files with 48 additions and 7 deletions

View File

@ -50,6 +50,7 @@ from executor_helpers import (
commit_memory,
extract_message_text,
get_a2a_instructions,
get_hma_instructions,
get_mcp_server_path,
get_system_prompt,
read_delegation_results,
@ -211,12 +212,12 @@ class ClaudeSDKExecutor(AgentExecutor):
return CONFIG_MOUNT
def _build_system_prompt(self) -> str | None:
"""Compose system prompt from file + A2A delegation instructions."""
"""Compose system prompt from file + A2A + HMA memory instructions."""
base = get_system_prompt(self.config_path, fallback=self.system_prompt)
a2a = get_a2a_instructions(mcp=True)
if base and a2a:
return f"{base}\n\n{a2a}"
return base or a2a
hma = get_hma_instructions()
parts = [p for p in (base, a2a, hma) if p]
return "\n\n".join(parts) if parts else None
def _prepare_prompt(self, user_input: str) -> str:
"""Prepend delegation results that arrived while idle."""

View File

@ -290,6 +290,31 @@ def get_a2a_instructions(mcp: bool = True) -> str:
return _A2A_INSTRUCTIONS_MCP if mcp else _A2A_INSTRUCTIONS_CLI
_HMA_INSTRUCTIONS = """## Hierarchical Memory (HMA)
You have persistent memory tools that survive across sessions and restarts:
- **commit_memory(content, scope)**: Save important information.
- LOCAL: private to you only (default)
- TEAM: shared with your parent workspace and siblings (same team)
- GLOBAL: shared with the entire org (only root workspaces can write)
- **recall_memory(query)**: Search your accessible memories. Returns LOCAL + TEAM + GLOBAL matches.
**When to use memory:**
- After making a decision or learning something non-obvious commit_memory("decision X because Y", scope="TEAM")
- Before starting work recall_memory("what did the team decide about X")
- When you discover org-wide knowledge (repo locations, API patterns, conventions) commit_memory(fact, scope="GLOBAL") if you are a root workspace, or scope="TEAM" to share with your team
- After completing a task commit_memory("completed task X, PR #N opened", scope="TEAM") so your lead and teammates know
**Memory is automatically recalled** at the start of each new session. Use it proactively during work to share context.
"""
def get_hma_instructions() -> str:
"""Return HMA memory instructions for system-prompt injection."""
return _HMA_INSTRUCTIONS
# ========================================================================
# Misc text helpers
# ========================================================================

View File

@ -479,7 +479,8 @@ def test_build_system_prompt_combines_base_and_a2a_via_fixture():
"""Direct test bypassing the execute() path."""
e = _make_executor()
with patch("claude_sdk_executor.get_system_prompt", return_value="BASE"), \
patch("claude_sdk_executor.get_a2a_instructions", return_value="A2A"):
patch("claude_sdk_executor.get_a2a_instructions", return_value="A2A"), \
patch("claude_sdk_executor.get_hma_instructions", return_value=""):
out = e._build_system_prompt()
assert out == "BASE\n\nA2A"
@ -487,17 +488,31 @@ def test_build_system_prompt_combines_base_and_a2a_via_fixture():
def test_build_system_prompt_base_only():
e = _make_executor()
with patch("claude_sdk_executor.get_system_prompt", return_value="BASE"), \
patch("claude_sdk_executor.get_a2a_instructions", return_value=""):
patch("claude_sdk_executor.get_a2a_instructions", return_value=""), \
patch("claude_sdk_executor.get_hma_instructions", return_value=""):
assert e._build_system_prompt() == "BASE"
def test_build_system_prompt_a2a_only():
e = _make_executor()
with patch("claude_sdk_executor.get_system_prompt", return_value=None), \
patch("claude_sdk_executor.get_a2a_instructions", return_value="A2A"):
patch("claude_sdk_executor.get_a2a_instructions", return_value="A2A"), \
patch("claude_sdk_executor.get_hma_instructions", return_value=""):
assert e._build_system_prompt() == "A2A"
def test_build_system_prompt_includes_hma():
"""HMA instructions are appended when present."""
e = _make_executor()
with patch("claude_sdk_executor.get_system_prompt", return_value="BASE"), \
patch("claude_sdk_executor.get_a2a_instructions", return_value="A2A"), \
patch("claude_sdk_executor.get_hma_instructions", return_value="## Hierarchical Memory"):
out = e._build_system_prompt()
assert "BASE" in out
assert "A2A" in out
assert "## Hierarchical Memory" in out
def test_prepare_prompt_no_delegation_returns_unchanged():
e = _make_executor()
with patch("claude_sdk_executor.read_delegation_results", return_value=""):