Summary
Messages/streaming output from a different Hermes VS Code chat can appear in the currently open chat. This looks like a cross-posting / wrong-session routing bug.
Observed behaviour
A user reports seeing messages from one Hermes VS Code chat that is not currently open appear inside the chat that is currently open.
Expected behaviour
Each chat/history should receive only messages and tool updates for its own ACP session. If another chat/session is still running in the background, its output should either:
- stay attached to that original chat, or
- be explicitly cancelled/stopped when switching away, with any late updates ignored.
It should never append text/tool updates into the currently visible different chat.
Environment seen locally
Suspected cause / code-path notes
The current extension appears to route all ACP session/update events into the currently open webview/active local chat without checking whether the ACP sessionId belongs to that chat.
Relevant code shape in the local source:
src/sessionManager.ts parses every session/update notification and emits SessionUpdateEvent with session_id = params.sessionId.
src/chatPanel.ts registers this.session.onUpdate((event) => { ... }) and immediately posts updates to the webview, for example:
- appending text with
this.post({ type: 'append', text: converted })
- forwarding thinking/tool/todo/status updates
- on
event.done, saving the turn to this.store.active() via saveTurnToSession() / addTurnMessages(...)
- There does not appear to be a guard like
event.session_id === this.store.active()?.acpSessionId before appending or saving output.
- On chat switch,
src/chatPanel.ts resets this.session, clears lastTurnText/Tools, and loads the new chat history, but late/stale session/update events from the old ACP session can still arrive and be appended to whichever chat is now visible.
A live log pattern also shows overlapping prompt/update risk:
- VS Code log contains
session/prompt for one ACP session, then many session/update events.
- Another
[ui] run prompt appears while the prior turn still has model/tool activity logged, suggesting updates can interleave through one global SessionManager/ChatPanelProvider path.
Suggested fix
- Track the active local chat id and the ACP session id associated with that chat at prompt start.
- Route every
SessionUpdateEvent by event.session_id before mutating UI or session history.
- If
event.session_id does not match the currently visible chat's ACP id:
- ignore it, or
- append/persist it to the owning stored chat without rendering it in the open chat.
- Scope
lastTurnText, lastTurnTools, toolCallLocations, busy/done/error state, and queued messages per chat/session, or at least per active prompt token.
- Add regression tests for:
- switch from Chat A to Chat B while Chat A still has late updates;
- Chat A updates do not render in Chat B;
- Chat A
done does not save its assistant turn into Chat B history;
- stale/cancelled updates after
session.reset() are ignored.
Why this matters
This is not just visual confusion. It can mix work from separate tasks, persist assistant output into the wrong chat history, and expose unrelated task details in a different conversation.
Summary
Messages/streaming output from a different Hermes VS Code chat can appear in the currently open chat. This looks like a cross-posting / wrong-session routing bug.
Observed behaviour
A user reports seeing messages from one Hermes VS Code chat that is not currently open appear inside the chat that is currently open.
Expected behaviour
Each chat/history should receive only messages and tool updates for its own ACP session. If another chat/session is still running in the background, its output should either:
It should never append text/tool updates into the currently visible different chat.
Environment seen locally
joaompfp.hermes-ai-agent@3.2.2joaompfp/hermes-vscodeSuspected cause / code-path notes
The current extension appears to route all ACP
session/updateevents into the currently open webview/active local chat without checking whether the ACPsessionIdbelongs to that chat.Relevant code shape in the local source:
src/sessionManager.tsparses everysession/updatenotification and emitsSessionUpdateEventwithsession_id = params.sessionId.src/chatPanel.tsregistersthis.session.onUpdate((event) => { ... })and immediately posts updates to the webview, for example:this.post({ type: 'append', text: converted })event.done, saving the turn tothis.store.active()viasaveTurnToSession()/addTurnMessages(...)event.session_id === this.store.active()?.acpSessionIdbefore appending or saving output.src/chatPanel.tsresetsthis.session, clearslastTurnText/Tools, and loads the new chat history, but late/stalesession/updateevents from the old ACP session can still arrive and be appended to whichever chat is now visible.A live log pattern also shows overlapping prompt/update risk:
session/promptfor one ACP session, then manysession/updateevents.[ui] run promptappears while the prior turn still has model/tool activity logged, suggesting updates can interleave through one globalSessionManager/ChatPanelProviderpath.Suggested fix
SessionUpdateEventbyevent.session_idbefore mutating UI or session history.event.session_iddoes not match the currently visible chat's ACP id:lastTurnText,lastTurnTools,toolCallLocations, busy/done/error state, and queued messages per chat/session, or at least per active prompt token.donedoes not save its assistant turn into Chat B history;session.reset()are ignored.Why this matters
This is not just visual confusion. It can mix work from separate tasks, persist assistant output into the wrong chat history, and expose unrelated task details in a different conversation.