Repository navigation
fix(gateway): agent-scoped session keys on the wire; end the turn on a rejected chat.send - #525
Merged
Merged
Conversation
…ted chat.send
openclaw 2026.8.35 rejects a bare sessionKey in chat.send once more than one
agent is configured ("Multiple agents are configured, but session key "main"
has no explicit owner. Use an agent-prefixed session key"). Every JamBot
tenant sends GATEWAY_SESSION_KEY=main and has two agents (openvoiceui,
openvoiceui-fast), so voice would go silent on 8.35.
- Capture snapshot.sessionDefaults.defaultAgentId from the connect hello
(res.payload; present in both 2026.5.7 and 2026.8.35) on every successful
handshake, so reconnects refresh it.
- wire_session_key(): bare alias -> agent:<defaultAgentId>:<alias> on the wire.
Unchanged when the key is already agent-scoped, is "global"/"unknown" (both
versions keep those unscoped), or the gateway announced no default.
2026.5.7 canonicalizes "main" to agent:<default>:main itself, so this is the
same session on the current fleet.
- Applied to every outbound sessionKey: chat.send (main, empty-final retry,
both subagent continuations, orphan continuation, steer), chat.abort, and
the admin install chat.send. Subscriptions, steer maps, caches and
get_voice_session_key() keep the short alias; _sk_match already matches
canonical event keys against it.
- The fast lane's agent_id stays a connection selector (it never reached the
gateway); not changed here.
A chat.send `res` with ok:false / error was treated as an ACK (and marked
QUEUED by the dispatcher), so the turn heartbeated to the 300s inner timeout
and ended as a null text_done with the reason lost. It is now terminal: the
stream emits the existing failed-turn event (text_done, response None, error)
immediately, and the dispatcher no longer marks a rejected send QUEUED.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
OpenClaw 2026.8.35 rejects a bare
sessionKeysuch asmainwhen more than one agent is configured ("Multiple agents are configured, but session key "main" has no explicit owner"). Every JamBot tenant has two agents, so voice would go silent on 8.35. OVU also treated that rejection as an ACK and heartbeated for 300 s before ending the turn with no error.What changes
snapshot.sessionDefaults.defaultAgentId(present in 2026.5.7 and 2026.8.35). OVU stores it on every successful handshake.wire_session_key()sendsagent:<defaultAgentId>:<alias>for a bare key, on the wire only. Keys that are already agent-scoped, the unscopedglobal/unknownkeys, and every key on a gateway that announces no default are sent unchanged. 2026.5.7 canonicalizes a baremainto that same prefixed key, so it is the same session on both versions.chat.send/chat.abortsites, plus the admin-install send. Internal keys (subscriptions, steer maps, caches,get_voice_session_key()) keep the short alias; inbound matching already accepts canonical event keys.reswithok: false/errorfor achat.sendnow ends the turn with the existing failed-turn event (text_done,response: None,error). The dispatcher no longer marks a rejected send QUEUED, so it cannot claim another turn's follow-up run.agent_idis a connection selector and still runs on the default agent; routing it toopenvoiceui-fastis left as a separate decision.Tests: 18 new in
tests/test_gateway_session_keys.py; gateway modules 49 -> 67 passed. The full suite has the same 70 pre-existing failures before and after (401s in route tests in a bare env). Reverting the fixes turns 7 of the new tests red.Rollout: rides the next fleet roll. Gate on test-dev (5.7) first: the log shows
Gateway default agent: openvoiceui, the same conversation history continues across the change, and a forced rejection reaches the client within seconds. Plan:docs/jambot/openclaw-upgrade-2026.8.35.md§13 WO-1 (MIKE-AI repo).