Conversation
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the narrowly scoped provider-side implementation. One blocking issue needs redesign before it is safe to salvage.
Problems
agent/anthropic_adapter.py:2548-2561parses static delimiters from atool_resultand promotes the captured text asrole: system. The delimiters are public static strings inagent/prompt_builder.py:637-643, and current Hermes appends them to ordinary tool-result content atagent/agent_runtime_helpers.py:3739-3752. A tool can therefore return identical delimiter-shaped content and have it re-labeled as user input with system authority. This conflicts with the current trust contract inagent/prompt_builder.py:651-656; Anthropic's mid-conversation-system-message documentation also explicitly warns not to elevate raw tool output.- The new tests construct accepted markers with
format_steer_marker(tests/agent/test_anthropic_adapter.py:1408-1438, PR head) but do not test forged marker text returned by a tool.
Suggested changes
- Preserve trusted
/steerprovenance separately through the adapter; do not infer it by parsing tool-output text. - Add adversarial tests proving delimiter-shaped raw tool output stays in the
tool_resultand does not produce a system message.
Automated hermes-sweeper review.
| for block in content: | ||
| if not (isinstance(block, dict) and block.get("type") == "tool_result"): | ||
| continue | ||
| new_inner, steer_text = _extract_trailing_steer_marker(block.get("content")) |
There was a problem hiding this comment.
Blocking: _extract_trailing_steer_marker() recognizes only public static text, not provenance. A tool can return the exact marker delimiters; this path then strips that output and lines 2555-2561 elevate it to a system message labeled as user input. Carry a trusted steer flag/value separately from tool-result text and add a forged-marker regression test.
672e3f5 to
e91523e
Compare
… 5/Mythos 5/Opus 4.8
Anthropic's Messages API accepts a {"role": "system"} entry inside
messages at the exact point an instruction becomes relevant, instead of
only via the top-level system field. GA (no beta header) on Claude
Fable 5, Claude Mythos 5, and Claude Opus 4.8; not available on Sonnet 5
or third-party Anthropic-compatible endpoints. It carries the same
operator-level authority as the top-level system field, but because it's
appended at the end of the message list it doesn't invalidate the cached
prefix the way editing the top-level system string would.
Hermes already relays mid-turn /steer input as a trailing
[OUT-OF-BAND USER MESSAGE] marker appended to the last tool result
(agent/prompt_builder.py:format_steer_marker,
agent/agent_runtime_helpers.py:apply_pending_steer_to_tool_results) so it
rides a role-alternation-safe slot on every model/provider. That path is
completely unchanged and remains the only option for Sonnet 5, GPT, and
third-party endpoints.
For the three gated models on a native Anthropic endpoint, promote the
trailing marker to a real mid-conversation system message instead, at
the Anthropic API boundary in convert_messages_to_anthropic — the same
place _manage_thinking_signatures already does endpoint/model-specific
rewriting. The canonical Hermes-internal message history and every other
code path (session persistence, compression, gateway steer plumbing)
are untouched; this only reshapes the outgoing Anthropic payload for the
three gated models, mirroring Anthropic's own guidance to phrase the
injected content as context ("new input arrived...") rather than a
command overriding the user.
Only the newest marker (result[-1], the one Hermes just appended for
this turn) is ever promoted; markers already embedded deeper in history
from a prior turn are left as-is since they're already part of a cached
prefix.
24 new tests covering: model gating (including OpenRouter-prefixed and
dated model names), marker extraction from both plain-string and
multimodal tool_result content, promotion behavior end-to-end through
convert_messages_to_anthropic, and no-ops for every non-qualifying case
(wrong model, third-party endpoint, no marker present, malformed
trailing message shape).
e91523e to
b47b41f
Compare
|
Rebased onto current This was the messiest of the three: Verified locally on Python 3.11.16: Worth highlighting the second commit for reviewers, since it is the security-relevant half: live steers are now identified by structural provenance ( Broad-suite runs were skipped: this machine hit its memory ceiling and the OOM-killer was SIGKILLing pytest. The targeted numbers above are real; CI is the right place for the full sweep. |
|
Closing this one. It has gone stale and now conflicts with |
Summary
Anthropic's native Messages API supports mid-conversation
{"role": "system"}entries on Claude Fable 5, Claude Mythos 5, and Claude Opus 4.8. Hermes can use that shape for a real runtime/steerwithout rewriting the top-level system prompt or invalidating its cached prefix.Hermes still appends the visible
[OUT-OF-BAND USER MESSAGE]marker to the active tool result for role-alternation-safe fallback behavior. Marker text is presentation only and is never trusted as provenance. The runtime also records the exact steer text in private, top-level internal metadata on the canonical tool message. The Anthropic adapter promotes a steer only when that runtime-owned metadata exists and the exact corresponding marker can be removed from the exact convertedtool_resultblock.Raw tool output, web content, files, or MCP responses that imitate the public marker remain ordinary tool output.
Implementation
_hermes_trusted_steermetadata only at Hermes's two runtime steer-injection paths.tool_resultobject rather than a sanitized tool-call ID, preventing collisions such ascall.a/call_afrom cross-binding instructions.Security and cache invariants
Testing
Focused coverage includes model/endpoint gating, string and block tool-result shapes, genuine runtime metadata injection, forged-marker rejection, exact-text matching, historical replay stability, duplicate/sanitized-ID collisions, provider payload metadata exclusion, and role ordering.
An independent post-fix review found no remaining security or logic blockers.