Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions workspace/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
from pathlib import Path

from executor_helpers import get_a2a_instructions, get_hma_instructions
from skill_loader.loader import LoadedSkill
from shared_runtime import build_peer_section

Expand Down Expand Up @@ -68,6 +69,7 @@ def build_system_prompt(
plugin_prompts: list[str] | None = None,
parent_context: list[dict] | None = None,
platform_instructions: str = "",
a2a_mcp: bool = True,
) -> str:
"""Build the complete system prompt.

Expand Down Expand Up @@ -154,6 +156,20 @@ def build_system_prompt(
parts.append(skill.instructions)
parts.append("")

# Platform tool instructions: A2A (inter-agent communication) and HMA
# (persistent memory). These document how to call delegate_task,
# commit_memory, etc — without them, agents see the tools registered
# but have no instructions on when/how to use them. Placed between
# Skills and Peers so the A2A docs precede the peer list (which is
# the data shape the A2A tools operate over).
#
# a2a_mcp=True: MCP tool variant (claude-code, hermes, langchain,
# crewai). a2a_mcp=False: CLI subprocess variant (ollama, custom
# runtimes that don't speak MCP). Default True matches the
# MCP-capable majority; CLI-only adapters override at the call site.
parts.append(get_a2a_instructions(mcp=a2a_mcp))
parts.append(get_hma_instructions())

# Add peer capabilities with a single shared renderer.
peer_section = build_peer_section(peers)
if peer_section:
Expand Down
74 changes: 74 additions & 0 deletions workspace/tests/test_prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,3 +395,77 @@ async def test_get_peer_capabilities_exception():
result = await get_peer_capabilities("http://platform:8080", "ws-abc")

assert result == []


# Regression tests for the A2A + HMA tool-instruction injection. Pre-fix,
# get_a2a_instructions() and get_hma_instructions() were defined in
# executor_helpers.py but never called from build_system_prompt — workers
# saw the platform's delegate_task / commit_memory tools registered but
# had no documentation telling them how to use them.

def test_a2a_instructions_injected_default_mcp(tmp_path):
"""build_system_prompt embeds A2A MCP-variant instructions by default."""
(tmp_path / "system-prompt.md").write_text("Base.")

result = build_system_prompt(
config_path=str(tmp_path),
workspace_id="ws-1",
loaded_skills=[],
peers=[],
)

assert "## Inter-Agent Communication" in result
assert "delegate_task" in result
assert "list_peers" in result
assert "send_message_to_user" in result


def test_a2a_instructions_cli_variant_when_disabled(tmp_path):
"""a2a_mcp=False emits the CLI subprocess variant for non-MCP runtimes."""
(tmp_path / "system-prompt.md").write_text("Base.")

result = build_system_prompt(
config_path=str(tmp_path),
workspace_id="ws-1",
loaded_skills=[],
peers=[],
a2a_mcp=False,
)

assert "## Inter-Agent Communication" in result
assert "molecule_runtime.a2a_cli" in result
# MCP-only details must NOT leak into the CLI variant.
assert "send_message_to_user" not in result


def test_hma_instructions_injected(tmp_path):
"""build_system_prompt embeds HMA persistent-memory instructions."""
(tmp_path / "system-prompt.md").write_text("Base.")

result = build_system_prompt(
config_path=str(tmp_path),
workspace_id="ws-1",
loaded_skills=[],
peers=[],
)

assert "## Hierarchical Memory (HMA)" in result
assert "commit_memory" in result
assert "recall_memory" in result


def test_tool_instructions_precede_peer_section(tmp_path):
"""A2A docs must precede the peer list — peer IDs are operands of A2A tools."""
(tmp_path / "system-prompt.md").write_text("Base.")

peers = [{"id": "p1", "name": "Worker", "status": "active", "agent_card": None}]
result = build_system_prompt(
config_path=str(tmp_path),
workspace_id="ws-1",
loaded_skills=[],
peers=peers,
)

a2a_idx = result.index("## Inter-Agent Communication")
peers_idx = result.index("## Your Peers")
assert a2a_idx < peers_idx, "A2A instructions must come before the peer list"
Loading