fix(mcp): recover tool calls when the shim's conversation id goes stale after host resume - #657
Conversation
…le after host resume Fixes ranxianglei#656. Claude Code resumes fork a NEW session id after MCP children are spawned, so the shim's env-captured CLAUDE_CODE_SESSION_ID goes stale and every tool call 404s with 'unknown plugin conversation' for the rest of the session while the proxy keeps serving the conversation under the new id. - mcp.ts: on that exact 404, adopt the proxy's most-recent active conversation (status?fallback=latest) and retry once. Identity-bound hosts only; BILI_MCP_NO_ORPHAN_ADOPT=1 opts out for multi-session setups. - plugin.ts: status fallback now reports the RESOLVED conversation id (it used to echo the caller's stale id back, so adoption was impossible). - plugin.ts: split the tool-endpoint 404 into its two real causes (never-registered id vs session-not-resident) and log the rejection - these 404s used to be invisible in bili.log. - tests: fallback resolution + adopted-id tool call; never-registered wording assertion.
|
接单 |
已审核 PR #657(fixes #656)。结论:修复正确,可合并(合并由人工执行)。 根因验证(#656) — issue 引用的代码路径全部属实:
修复验证
发现(次要,非阻塞)
建议:可合并。若想更稳,可补一个 identity-binding 的 resume 回归用例(非必须)。 |
|
小问题修复下 |
|
继续 |
…stale-id recovery The existing ranxianglei#656 test exercises the cooperative plugin protocol (x-bili-plugin-conversation). Add a parallel test that drives the actual Claude Code identity-binding path (x-claude-code-session-id + persistent identity register): a stale pre-resume id 404s, status?fallback=latest resolves the active conversation, and the adopted id then works.
小问题已修,已推到 PR 分支( 修了什么(对应我 review 的发现 #2:测试缺口)
这样 #656 的核心恢复逻辑在 identity-binding 场景下也有覆盖了。 预检 未处理(发现 #3,仅说明) |
Fixes #656
Problem
After a Claude Code
--resume(which forks a NEW session id after MCP children were spawned), the shim's env-capturedCLAUDE_CODE_SESSION_IDis stale forever: every tool call 404s withunknown plugin conversation (no model request has arrived with this conversation id yet)while the proxy keeps serving the conversation under the new id. Only a full CLI restart heals it.Root cause chain
src/mcp.tscaptures the conversation id once at process start and never refreshes it;Fix
src/mcp.ts— orphan adoption: when a tool call hits that exact 404, the shim asksstatus?conversationId=<stale>&fallback=latest, adopts the resolved conversation id, and retries once (one-time stderr note). Armed only for identity-bound hosts (CLAUDE_CODE_SESSION_ID);BILI_MCP_NO_ORPHAN_ADOPT=1opts out for setups where several host sessions share one proxy and a resumed one must not adopt a sibling's conversation.src/plugin.ts— fallback now reports the adopted id (required for 1): the status fallback branch picks the latest active session but used to echo the caller's stale id back, so adoption was impossible. It now reverse-resolves the session's most-recently-seen conversation id.src/plugin.ts— 404 diagnostics: the tool endpoint's single error message covered two different failures; they are now distinct (never-registered id vs registered-but-session-not-resident), and rejections are logged — these 404s were previously invisible inbili.log.Tests
#656: status fallback=latest resolves the active conversation for a stale shim id…(adoption resolution + retry with adopted id) and a wording assertion on the never-registered 404.tests/plugin-protocol.test.ts: 12/12 pass;tsc --noEmitclean.mastercheckout in this environment (verified withgit stash; environment-dependent, cf. test: resolveClientCommand codex/claude test is environment-dependent (fails when codex/claude live in /usr/bin) #642): 2×launcher-plugin-modemcp stdio shell, 1×mitmwhitelist, 2×plugin-agent.Note
The commit was uploaded via the REST git API (local network can't run
git push); tree content is identical to a normal push — 3 files, +123/−15.