forked from molecule-ai/molecule-core
The Hermes adapter never read /configs/system-prompt.md. Any role that
switched to runtime: hermes was silently losing its role identity because
the system prompt wasn't passed to the model. This PR fixes that by:
1. HermesA2AExecutor.__init__ takes new optional `config_path` kwarg
2. `create_executor(config_path=...)` forwards to the constructor
3. `adapter.py` passes `config.config_path` through from AdapterConfig
4. `execute()` reads system-prompt.md via executor_helpers.get_system_prompt
(hot-reload-capable — reads on every turn, not just at startup)
5. `_do_inference(user_message, history, system_prompt)` — new arg threads
through the dispatch to each native path
6. Each path uses the provider's NATIVE system field:
- OpenAI-compat: prepends `{"role":"system", "content":...}` to messages
- Anthropic: top-level `system=` kwarg (NOT in messages — Anthropic
requires system at the top level)
- Gemini: `config=GenerateContentConfig(system_instruction=...)`
## Phase scoreboard
- 2a (in main) — native Anthropic dispatch infra
- 2b (in main) — native Gemini dispatch
- 2c (in main) — multi-turn history on all paths
- **2d-i (this PR)** — system prompts on all paths
- 2d-ii (future) — tool calling on native paths
- 2d-iii (future) — vision content blocks on native paths
- 2d-iv (future) — streaming
## Test coverage
46/46 tests pass (20 Phase 2 dispatch + 26 Phase 1 registry):
- Existing dispatch tests updated to assert the 3-arg call shape
`("hello", None, None)` — history + system_prompt both None
- 4 new tests:
- `dispatch_passes_system_prompt_to_anthropic` — happy path, third arg flows
- `dispatch_passes_system_prompt_to_gemini` — happy path
- `dispatch_passes_system_prompt_to_openai` — happy path
- `executor_accepts_config_path_kwarg` — constructor stores config_path
- `create_executor_forwards_config_path` — both back-compat and registry
resolution paths forward config_path through to the executor
## Back-compat
- `config_path=None` (default) → execute() skips system-prompt injection,
same behavior as pre-2d-i
- Workspaces with `runtime: hermes` but no `/configs/system-prompt.md`
file get `system_prompt=None` (get_system_prompt returns fallback),
same as before
- The 13 OpenAI-compat providers work identically — system_prompt just
adds a leading message, which every OpenAI-compat endpoint already
supports
- Anthropic + Gemini previously got zero system context; now they get
the same system prompt the workspace's system-prompt.md carries
## Why this matters
Before this PR: if someone flipped a workspace from `runtime: claude-code`
to `runtime: hermes`, the agent would act generically (no role identity,
no project conventions, no CLAUDE.md context) because the Hermes executor
never looked at system-prompt.md. That's a silent correctness regression
the test suite wouldn't catch because none of our live workspaces use
the hermes runtime today.
With this PR: Hermes workspaces get the same system prompt injection as
Claude-code workspaces, making the `runtime: hermes` switch a true drop-in
alternative.
## Related
- #267 Phase 2c (multi-turn history — in main)
- #255 Phase 2b (gemini native — in main)
- #240 Phase 2a (anthropic native — in main)
- #208 Phase 1 (provider registry — in main)
- project_hermes_multi_provider.md — Phase 2d-i was the next queued item
|
||
|---|---|---|
| .. | ||
| __init__.py | ||
| conftest.py | ||
| test_a2a_cli.py | ||
| test_a2a_client.py | ||
| test_a2a_executor.py | ||
| test_a2a_mcp_server.py | ||
| test_a2a_tools_impl.py | ||
| test_a2a_tools_module.py | ||
| test_adapters.py | ||
| test_agent_base_urls.py | ||
| test_agent.py | ||
| test_approval.py | ||
| test_audit.py | ||
| test_awareness_client_full.py | ||
| test_claude_sdk_executor.py | ||
| test_cli_executor.py | ||
| test_common_setup.py | ||
| test_compliance.py | ||
| test_config.py | ||
| test_consolidation.py | ||
| test_coordinator_parent.py | ||
| test_coordinator_routing.py | ||
| test_delegation.py | ||
| test_events.py | ||
| test_executor_helpers.py | ||
| test_first_party_plugins.py | ||
| test_governance.py | ||
| test_heartbeat.py | ||
| test_hermes_adapter.py | ||
| test_hermes_phase2_dispatch.py | ||
| test_hermes_providers.py | ||
| test_hermes_smoke.py | ||
| test_hitl.py | ||
| test_main_initial_prompt.py | ||
| test_mcp_memory.py | ||
| test_medo.py | ||
| test_memory.py | ||
| test_molecule_ai_status.py | ||
| test_namespaces.py | ||
| test_openclaw_adapter.py | ||
| test_platform_auth.py | ||
| test_plugins_builtins_drift.py | ||
| test_plugins_builtins.py | ||
| test_plugins_registry.py | ||
| test_plugins.py | ||
| test_preflight.py | ||
| test_prompt.py | ||
| test_qianfan_provider.py | ||
| test_routing_policy.py | ||
| test_sandbox.py | ||
| test_security_scan.py | ||
| test_shared_runtime.py | ||
| test_skills_loader.py | ||
| test_skills_watcher.py | ||
| test_telemetry.py | ||
| test_temporal_workflow.py | ||
| test_watcher.py | ||