fix(agent): stop shipping a delivery-shaped steer exemplar in the system prompt - #82208
Open
mattwebbio wants to merge 1 commit into
Open
fix(agent): stop shipping a delivery-shaped steer exemplar in the system prompt#82208mattwebbio wants to merge 1 commit into
mattwebbio wants to merge 1 commit into
Conversation
…tem prompt STEER_CHANNEL_NOTE embedded a syntactically complete [OUT-OF-BAND USER MESSAGE ...] block to document the /steer channel. That exemplar is byte-indistinguishable from a real delivered steer, and models have read it as a newly delivered (empty) user message and acted on it mid-turn (NousResearch#81828). Document the two marker lines individually, close-marker first, so the rendered system prompt never contains an assembled OPEN..CLOSE sequence while both markers stay quoted verbatim (the trust-teaching that NousResearch#40240 introduced for NousResearch#36934 is preserved, and real deliveries are unchanged). Refs NousResearch#81828 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Contributor
|
This was generated by AI during triage. Summary: Problems:
Solution: Checked against |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Disclosure: this fix, its tests, and this PR description were produced by Claude Code (Claude Fable 5), building on the investigation in #81828. I reviewed everything before submitting, but the work is not my own.
What does this PR do?
Stops the system prompt from shipping a complete, delivery-shaped
[OUT-OF-BAND USER MESSAGE …]block.STEER_CHANNEL_NOTEdocumented the /steer channel by embedding a full exemplar:That exemplar is byte-indistinguishable from a real delivered steer — it matches the same pattern downstream consumers use to strip consumed deliveries — and models have read it as a newly delivered (empty) user message and acted on it mid-turn. Deterministic repro and a production instance (Kimi-K2.6, with the steer path ruled out by zero steer deliveries in the gateway log) are in #81828; a second production instance on MiniMax-M3 is reported in the same thread.
The fix documents the two marker lines individually, close-marker first, so the rendered prompt never contains an assembled OPEN…CLOSE sequence. Nothing else changes:
format_steer_marker()is untouched, real deliveries keep their exact shape, and both marker strings stay quoted verbatim in the note.Why not remove or weaken the note
The note is the fix #40240 shipped for #36934: hardened models refused real steers as suspected prompt injection until the system prompt taught them to trust this exact marker. This PR keeps that trust-teaching — both markers are still quoted verbatim, with the same authority/freshness rules — and removes only the assembled block. Real deliveries still arrive as complete blocks, so recognition at delivery time is unchanged; the only thing removed is the phantom copy that made every tool-enabled session carry what looks like an already-delivered empty steer.
The existing contract tests pin this:
test_system_prompt_note_describes_the_real_marker(both markers verbatim in the note) andtest_system_prompt_scopes_freshness_to_unanswered_markerpass unchanged.Tests
Two regression tests encode the invariant from both directions:
test_note_never_assembles_a_delivery_shaped_block(tests/run_agent/test_steer.py) —format_steer_marker()output must match the delivery shape;STEER_CHANNEL_NOTEmust not.test_rendered_prompt_contains_no_delivery_shaped_steer_block(tests/agent/test_system_prompt.py) — the fully rendered tool-enabled system prompt contains the markers but no OPEN…CLOSE sequence, catching any future prompt part that reassembles a block across section boundaries.The repro from #81828 flips on this branch:
and a real delivery still matches hermes-webui's
_OOB_USER_MESSAGE_BLOCK_RE(verified against the regex verbatim fromapi/streaming.py).Full
tests/agent+tests/run_agentsweep run innousresearch/hermes-agent:main, this branch vs unmodifiedmain(9c8a235): 5337 passed / 162 failed vs 5334 passed / 163 failed. The 162 failures are identical environment-dependent failures on both trees (missing credentials, sandbox paths, etc.). The one failure unique tomainistest_build_system_prompt_records_stable_prefix, which fails in full-suite order today for an unrelated pre-existing reason: earlier tests leave context-file truncation warnings queued, andbuild_system_promptdrains them intoagent._emit_status, which the module'sSimpleNamespacetest agents don't define. The new test stubs_emit_statusso it is immune to that ordering hazard (and, by draining the queue harmlessly, happens to unbreak the downstream victim in this ordering — not a fix for that hazard, just not a new instance of it).What this does not claim
Removing the exemplar provably removes the precondition — a delivery-shaped block in every tool-enabled prompt — but the claim that models then stop fabricating markers entirely is inferential. #65339 documents models fabricating blocks under other conditions; this PR narrows the attack surface rather than closing every path to fabrication.
Refs #81828 (removes the exemplar mechanism; the issue's proposed structural fix is #82467), #58491, #65339, #36934, #40240.
🤖 Generated with Claude Code