hermes - 💡(How to fix) Fix ACP cancel leaks Hermes interruption sentinel as assistant output

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Cancelling an in-flight Hermes ACP turn while Hermes is still waiting for the model/provider response can emit Hermes' internal interrupt sentinel as an ACP agent_message_chunk:

Operation interrupted: waiting for model response (3.3s elapsed).

The prompt response correctly settles with stopReason: "cancelled", but the sentinel has already been sent as assistant content. ACP clients such as Zed-style transcript views, mux clients, or vibe-textual render that chunk as assistant/model output even though the model did not produce it.

This should be treated as cancellation/status metadata, not assistant prose.

Root Cause

  • Cancelling an ACP turn before any model tokens arrive does not create an assistant message containing Operation interrupted: waiting for model response ....
  • The ACP prompt response still reports cancellation with stopReason: "cancelled".
  • Normal non-streamed model responses still appear as assistant text.
  • Transformed non-interrupted responses keep existing delivery semantics.
  • Real assistant/model text is not suppressed merely because the cancel flag is set.
  • Cancelled/interrupted sentinel text is not used for session auto-title generation; if ACP goal-continuation hooks are present, they use the same suppression guard.

Fix Action

Fix / Workaround

  • #7921 — same Operation interrupted: waiting for model response (...) sentinel leaking to users, but through Telegram/gateway rather than ACP.
  • #8633 — open gateway/home-channel wording PR; does not fix ACP sentinel emission.
  • #11947 — closed/unmerged gateway-side suppression PR for #7921; related symptom, not an ACP fix.
  • #15395 — merged interrupted-turn memory-sync PR; related sentinel poisoning class, but not ACP transcript emission.
  • #28641 — open ACP /goal PR touching nearby post-turn/final-response code; if it lands first, any continuation hook should share this suppression guard.

Code Example

Operation interrupted: waiting for model response (3.3s elapsed).

---

Operation interrupted: waiting for model response (3.3s elapsed).

---

final_response = f"Operation interrupted: waiting for model response ({api_elapsed:.1f}s elapsed)."
   interrupted = True

---

if final_response and conn and (not streamed_message or result.get("response_transformed")):
       update = acp.update_agent_message_text(final_response)
       await conn.session_update(session_id, update)

---

stop_reason = "cancelled" if state.cancel_event and state.cancel_event.is_set() else "end_turn"
RAW_BUFFERClick to expand / collapse

ACP cancel leaks Hermes interruption sentinel as assistant output

Summary

Cancelling an in-flight Hermes ACP turn while Hermes is still waiting for the model/provider response can emit Hermes' internal interrupt sentinel as an ACP agent_message_chunk:

Operation interrupted: waiting for model response (3.3s elapsed).

The prompt response correctly settles with stopReason: "cancelled", but the sentinel has already been sent as assistant content. ACP clients such as Zed-style transcript views, mux clients, or vibe-textual render that chunk as assistant/model output even though the model did not produce it.

This should be treated as cancellation/status metadata, not assistant prose.

User-visible symptom

Observed with a long Hermes ACP prompt cancelled before any model tokens arrived:

  • client shows a cancel intent/note, e.g. requested cancel: user requested cancel

  • the original user prompt remains visible

  • the assistant/agent body becomes:

    Operation interrupted: waiting for model response (3.3s elapsed).

Expected UX:

  • cancelled turns settle as cancelled
  • no fake assistant/model response appears when the model produced no text
  • if cancellation detail is useful, expose it as non-assistant status/metadata, or let clients derive it from PromptResponse.stopReason == "cancelled"

Current code path

  1. ACP session/cancel sets state.cancel_event and calls state.agent.interrupt() in acp_adapter/server.py.

  2. If the core conversation loop is interrupted while waiting for the provider response, agent/conversation_loop.py can set:

    final_response = f"Operation interrupted: waiting for model response ({api_elapsed:.1f}s elapsed)."
    interrupted = True
  3. The ACP adapter later treats any non-empty result["final_response"] as assistant text when streaming did not already send a message:

    if final_response and conn and (not streamed_message or result.get("response_transformed")):
        update = acp.update_agent_message_text(final_response)
        await conn.session_update(session_id, update)
  4. The prompt response still returns cancellation correctly:

    stop_reason = "cancelled" if state.cancel_event and state.cancel_event.is_set() else "end_turn"

So the cancellation state is available, but the internal sentinel can already leak as an agent_message_chunk.

ACP/protocol note

ACP already has the semantic signal for this case:

  • session/cancel cancels a prompt turn for a session.
  • PromptResponse.stopReason includes "cancelled" for a client-cancelled prompt turn.
  • agent_message_chunk is transcript content from the agent/assistant.

The schema does not forbid chunks before settling a cancelled turn, and agents may still need to finalize real streamed text or tool-call updates after a cancel. But this specific Hermes string is not assistant content; it is an implementation-local interruption status.

Suggested fix

Suppress final-response assistant-message emission when all of these are true:

  • the ACP turn/result is interrupted or cancelled
  • final_response matches Hermes' local API-wait interruption sentinel

Keep normal final-response delivery unchanged for real model/assistant text, including:

  • normal non-streamed responses
  • responses transformed after streaming by plugin hooks
  • real final text that races with a cancel flag

Also avoid using the interruption sentinel for ACP session auto-title generation. If ACP post-turn continuation hooks are present, such as goal continuation, they should use the same suppression guard.

Acceptance criteria

  • Cancelling an ACP turn before any model tokens arrive does not create an assistant message containing Operation interrupted: waiting for model response ....
  • The ACP prompt response still reports cancellation with stopReason: "cancelled".
  • Normal non-streamed model responses still appear as assistant text.
  • Transformed non-interrupted responses keep existing delivery semantics.
  • Real assistant/model text is not suppressed merely because the cancel flag is set.
  • Cancelled/interrupted sentinel text is not used for session auto-title generation; if ACP goal-continuation hooks are present, they use the same suppression guard.

Related activity

No exact open issue/PR was found for the ACP-specific sentinel-as-agent_message_chunk bug.

Closest related items:

  • #7921 — same Operation interrupted: waiting for model response (...) sentinel leaking to users, but through Telegram/gateway rather than ACP.
  • #8633 — open gateway/home-channel wording PR; does not fix ACP sentinel emission.
  • #11947 — closed/unmerged gateway-side suppression PR for #7921; related symptom, not an ACP fix.
  • #15395 — merged interrupted-turn memory-sync PR; related sentinel poisoning class, but not ACP transcript emission.
  • #28641 — open ACP /goal PR touching nearby post-turn/final-response code; if it lands first, any continuation hook should share this suppression guard.

Non-goals

  • Do not change provider/model cancellation semantics.
  • Do not require ACP clients to string-filter Hermes implementation sentinels.
  • Do not suppress real model text that was already streamed or generated before cancellation.
  • Do not replace session/cancel; this is about Hermes' response surfacing after cancellation reaches the agent.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix ACP cancel leaks Hermes interruption sentinel as assistant output