feat(agent): declarative per-fragment system-prompt overrides - #44610
feat(agent): declarative per-fragment system-prompt overrides#44610adambiggs wants to merge 1 commit into
Conversation
0c9867d to
567827e
Compare
Add agent.prompt_overrides — a config surface to reshape any named stable-tier system-prompt fragment (replace/append/prepend/remove) without editing source. Gives full context-engineering control over Hermes's built-in guidance blocks (e.g. qualifying the "Finishing the job" / "Tool-use enforcement" persistence rules) instead of the prior all-or-nothing on/off toggles. Every stable-tier fragment now carries a stable key and is emitted through a single override-aware `emit()` choke point in build_system_prompt_parts. Overrides are pure data resolved once at build time — no callable hook, no conditional logic — so the assembled prompt stays a deterministic function of (agent, config) and the provider prefix cache stays warm. With no overrides the prompt is byte-identical to the default (covered by test). - agent/prompt_overrides.py: FRAGMENT_KEYS registry (16 keys), normalize_overrides (validation + bare-string shorthand), apply_fragment_override (mode resolution) - agent/system_prompt.py: route all 16 stable-tier append sites through emit() - agent/agent_init.py: load+normalize agent.prompt_overrides - config default, example config with worked stop-on-friction case, developer-guide docs - 25 engine unit tests + 6 end-to-end integration tests Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
567827e to
d100007
Compare
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the focused, cache-aware configuration surface. The underlying capability remains absent on current main, and #48101 is complementary rather than a replacement.
Problems
- The claimed stable-tier coverage is incomplete: PR commit
d1000077511astill hasstable_parts.append(PARALLEL_TOOL_CALL_GUIDANCE)atagent/system_prompt.py:230, butFRAGMENT_KEYSatagent/prompt_overrides.py:43-60has no corresponding key.parallel_tool_call_guidancewill be ignored as unknown. - The same branch retains
coding_system_blocks()throughstable_parts.extend()atagent/system_prompt.py:364-374. Please either model its supported override granularity or narrow the “every stable-tier fragment” claims in code and docs. tests/agent/test_prompt_overrides.py:111fixes the registry count at 16. This is a change-detector test and will not protect the coverage contract; it already permits the omitted parallel block.
Suggested changes
- Route parallel guidance through
emit()and test a real configured override; decide and document the coding-block scope. - Replace the fixed-count assertion with behavioral coverage of supported fragments.
Automated hermes-sweeper review.
| # with the ``emit(...)`` call sites in ``agent/system_prompt.py``. Surfaced to | ||
| # users for discovery (``hermes`` docs / tooling) — an override map keyed by | ||
| # string is only usable if the keys are enumerable. | ||
| FRAGMENT_KEYS: Dict[str, str] = { |
There was a problem hiding this comment.
This registry is documented as canonical, but agent/system_prompt.py:230 in this PR still directly appends PARALLEL_TOOL_CALL_GUIDANCE. Add a key and route that block through emit(), or narrow the feature/docs claim so the omission is explicit.
|
|
||
| class TestFragmentKeyRegistry: | ||
| def test_keys_present_and_documented(self): | ||
| assert len(FRAGMENT_KEYS) == 16 |
There was a problem hiding this comment.
Please remove the fixed registry-count assertion. It is a change-detector test and does not enforce the useful contract; behavioral coverage for the parallel-guidance override would have caught the currently omitted stable block.
What & why
Adds
agent.prompt_overrides— a config surface to reshape any named stable-tier system-prompt fragment (replace/append/prepend/remove) without editing source.Today the built-in guidance blocks are either hardcoded or gated by bespoke all-or-nothing booleans (
task_completion_guidance,tool_use_enforcement,environment_probe). That only lets you delete a whole block, never reshape it — so the common need to qualify a block (e.g. append a "stop and report on environment friction instead of working around it" caveat to the "Finishing the job" guidance) has no clean path short of forking. This generalizes those one-off toggles into a uniform, discoverable override map and gives users real context-engineering control.Design: pure data, cache-safe by construction
Every stable-tier fragment now carries a stable key and is emitted through a single override-aware
emit()choke point inbuild_system_prompt_parts. Overrides are pure data resolved once at build time — no callable hook, no conditional logic, by design. The assembled prompt stays a deterministic function of(agent, config), so it remains byte-stable across turns and the provider prefix cache stays warm. With no overrides configured the prompt is byte-identical to the default (covered by a regression test). An override only applies when the fragment is actually emitted this session;append/prependto an absent fragment is a no-op.Scope is intentionally the stable tier (Hermes-authored guidance/identity). Context-tier (project files, system message) and volatile-tier (memory, timestamp) are user/session data, not prompt fragments;
emit()is tier-agnostic so extending later is trivial.Example
Fragment keys (16, stable tier):
identity,hermes_help,task_completion,tool_guidance,steer_channel,computer_use,nous_subscription,tool_use_enforcement,google_operational,execution_discipline,skills,model_identity,environment_hints,environment_probe,active_profile,platform_hints. Canonical registry with descriptions lives inagent/prompt_overrides.py(FRAGMENT_KEYS).Existing on/off toggles are untouched and still work.
How to test
test_no_overrides_byte_identicalasserts the cache-warmth guarantee (empty overrides → identical prompt)._build_system_prompt()path.Manual:
…then
hermes chatand confirm the "Finishing the job" block is gone (and present again without the override).Platforms
Pure-Python config plumbing, no OS-specific code paths. Developed/tested on Linux.
Files
agent/prompt_overrides.py(new) — registry +normalize_overrides+apply_fragment_overrideagent/system_prompt.py— 16 stable-tier append sites routed throughemit()agent/agent_init.py— load + normalize confighermes_cli/config.py,cli-config.yaml.example— default + worked examplewebsite/docs/developer-guide/prompt-assembly.md— override surface docs🤖 Generated with Claude Code