fix(team): fall through to cached catalog when live slash-command list is empty - #705
Closed
bbt567 wants to merge 1 commit into
Closed
fix(team): fall through to cached catalog when live slash-command list is empty#705bbt567 wants to merge 1 commit into
bbt567 wants to merge 1 commit into
Conversation
…t is empty
In team mode, sending a backend-native slash command like /compact was
silently treated as ordinary text and wrapped in the '## New Messages'
wake payload, so the agent never received the bare command and replied
conversationally instead of executing it (e.g. claude: '/compact is a
built-in command...').
Root cause: resolve_slash_catalog's degradation chain short-circuited on
ANY Ok result from the live session, including an empty list. A backend's
live slash_commands can be transiently empty before its discovery
handshake completes (e.g. claude's control_request{initialize} response
has not landed, so discovered_caps.slash_commands is still []), yet the
same commands are already present in the persisted
agent_metadata.available_commands snapshot. Returning the empty live list
yielded CatalogEmpty, which disabled every team slash command and forced
the wrapped-wake fallback — masking commands the backend genuinely
supports.
Fix: adopt the live catalog only when non-empty (extracted into
live_catalog_or_none for testability). An empty live list now falls
through to cached/static. A backend that genuinely advertises no commands
still degrades correctly (empty cached snapshot or final None).
Verified: claude's persisted snapshot advertises 'compact'; a direct
(non-team) claude session executes /compact ('Not enough messages to
compact'), proving the backend supports it when sent bare.
Closes #3750
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.
Root cause
In team mode, a backend-native slash command such as
/compactis silently treated as ordinary text and wrapped in the## New Messageswake payload, so the agent never receives the bare command and replies conversationally instead of executing it.resolve_slash_catalogdegrades live → cached → static. The live arm short-circuits on anyOkresult from the session, including an empty list:A backend's live
slash_commandscan be transiently empty before its discovery handshake completes. For the claude backend,ClaudeSessionBackend::capabilities()mergesdiscovered_caps.slash_commandsonly once thecontrol_request{initialize}control response lands (sniff_control_initialize); until then it is[]. Returning that empty live list yieldsCatalogEmpty, which disables every team slash command and forces the wrapped-wake fallback — even though the same commands are already present in the persistedagent_metadata.available_commandssnapshot (chain arm b).Evidence (real captured data, not inference)
Reproduced on v2.1.41+ with a team whose Leader is claude (
transport: CliAssumed) and a member is codex.1. The failure reply is generated by the agent, not AionCore. The string
`/compact` 是内置命令…does not exist anywhere in this repo. The persisted claudethinkingblock shows the agent reasoning about it but not executing:2. The same backend executes
/compactcorrectly when sent bare (non-team). A direct (non-team) claude conversation returnsNot enough messages to compact.— i.e. the native compact path ran. The team path differs only in that the command is wrapped, so claude never sees a bare/compact.3. The persisted snapshot already advertises
compact.agent_metadata.available_commandsfor the claude agent (2d23ff1c) contains{"name":"compact","description":"Free up context by summarizing the conversation so far"}. So arm (b) of the chain would resolve the command — it is never reached because arm (a) returns the empty live list first.Fix
Adopt the live catalog only when non-empty. An empty live list falls through to cached/static. The decision is extracted into
live_catalog_or_noneso the degradation boundary has a unit test (the chain previously had none — which is how this slipped in). A backend that genuinely advertises no commands still degrades correctly: the cached snapshot is empty or the chain ends atNone, both yielding the wrapped wake.This makes no claim about any external CLI's behavior — it only stops a transiently-empty live list from masking a populated persisted snapshot.
Verification
cargo check -p aionui-app✅cargo test -p aionui-app --lib→ 18 passed (incl. newlive_catalog_adopted_only_when_non_empty) ✅cargo test -p aionui-team --test e2e_team_flow→ 29 passed, 0 failed — all existing catalog tests (recognized_command_is_sent_bare_to_member/lead,unrecognized_slash_and_plain_text_fall_back_to_wrapped_wake,catalog_unavailable_falls_back_to_wrapped_wake,empty_catalog_logs_warn_and_falls_back_to_wrapped_wake) still green ✅Closes #3750.