Tool dispatch fails with cryptic "Cannot read properties of undefined (reading 'prepare')" when tool runtime becomes unavailable - turn dies until restart #1974
LiuJunheng
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Note: This report was prepared and posted on behalf of a community user by an AI assistant, at the user's request. It is based on the user's real local DSH portable installation (v0.1.0-rc.6, Windows) — the diagnosis comes from actual session logs and source inspection.
Summary
When the agent tool runtime becomes unavailable, every tool call in a turn fails with the cryptic TypeError
Cannot read properties of undefined (reading 'prepare'), the turn dies withreason: { kind: "error" }, and nothing recovers until the DSH service is restarted. Session-level recovery (fork / rewind / new conversation) does not help.Environment
@deepseek-ai/dsh0.1.0-rc.6 (portable install), Node v22.20.0, Windowsdsh-find-plugin,dsh-web-plugin-manager) were installed at the time and removed laterSymptom (from the session log)
A failing turn looks like (no
tool/resultis ever recorded):Every subsequent turn that calls any tool fails the same way until the server process is restarted.
Root-cause analysis
The failure happens at
packages/core/agent-loop/src/tool-calls.ts:169:Importantly,
ctx.tools.executionMode(...)(line 88) succeeded earlier in the same dispatch — soctx.toolsitself existed, butctx.tools[TOOL_RUNTIME_SCHEDULER]wasundefined.TOOL_RUNTIME_SCHEDULERis a module-localSymbol("@deepseek-ai/dsh-tools.scheduler"). Two plausible causes:@deepseek-ai/dsh-toolsis loaded (e.g., pulled in by a profile plugin's dependency tree), the symbol constant differs between the two module instances, soctx.tools[<runtime copy's symbol>]isundefinedwhile string-keyed methods likeexecutionModestill resolve. (In our environment the profile indeed had its own@deepseek-ai/dsh-toolscopy.)cordis-plugin-loader'sinternal/update); installing / uninstalling / toggling plugins at runtime disposes and rebuilds plugin fibers, and already-running agents can resolve a torn-down or mid-rebuild tools service.Proposed fix (minimal, purely diagnostic)
Add an availability guard at the start of
executeToolCallsinpackages/core/agent-loop/src/tool-calls.ts(right afterconst { session } = agent):Benefits:
appendToolCall, so a failed dispatch no longer leaves a danglingtool/callevent in the session log.Related observation: the turn/end error code is hard-coded to
"UNKNOWN"in the agent-loop's turn-error normalization (near theturn/endappend inpackages/core/agent-loop/src/index.ts). Making this class of failure carry a stable code (e.g.TOOLS_UNAVAILABLE) would let clients detect and explain it programmatically.Impact / suggestion
@deepseek-ai/dsh-toolsinstances in profile dependency trees.中文版 (Chinese version)
概述
当 agent 的工具运行时失效时,回合中的每一次工具调用都会报晦涩的
Cannot read properties of undefined (reading 'prepare'),回合以reason: { kind: "error" }结束,且只能通过重启 DSH 服务恢复。会话级手段(派生/回退/新建对话)均无效。环境
@deepseek-ai/dsh0.1.0-rc.6(便携安装)、Node v22.20.0、Windowsdsh-find-plugin、dsh-web-plugin-manager(后来已移除)现象(来自会话日志)
失败回合形如(始终没有
tool/result):此后该服务实例中每个调用工具的回合都以同样方式失败,直到重启进程。
根因分析
报错发生在
packages/core/agent-loop/src/tool-calls.ts:169:关键在于:同一派发流程里前面的
ctx.tools.executionMode(...)(第 88 行)是成功的——说明ctx.tools本身存在,但ctx.tools[TOOL_RUNTIME_SCHEDULER]是undefined。TOOL_RUNTIME_SCHEDULER是模块级Symbol("@deepseek-ai/dsh-tools.scheduler")。两个合理成因:@deepseek-ai/dsh-tools(例如被某个 profile 插件的依赖树带进来),两份模块实例的 Symbol 常量不同,ctx.tools[运行时副本的Symbol]就是undefined,而字符串键方法(如executionMode)仍可解析。(我们的环境里 profile 确实存在第二份@deepseek-ai/dsh-tools。)cordis-plugin-loader的internal/update);运行中安装/卸载/开关插件会 dispose 并重建插件 fiber,正在运行的 agent 可能解析到被拆除或重建中的 tools 服务。建议修复(最小、纯诊断)
在
packages/core/agent-loop/src/tool-calls.ts的executeToolCalls开头(const { session } = agent之后)加可用性守卫:收益:
appendToolCall之前触发,失败派发不再在会话日志里留下悬空的tool/call事件。顺带发现:回合错误码被硬编码为
"UNKNOWN"(agent-loop 的 turn/end 错误归一化处,位于packages/core/agent-loop/src/index.ts)。若此类失败能携带稳定错误码(如TOOLS_UNAVAILABLE),客户端就能程序化识别并解释它。影响 / 建议
@deepseek-ai/dsh-tools。Reference implementation (open-sourced)
A community reference implementation of the session-recovery workflow is now open-sourced:
https://github.com/LiuJunheng/DeepSeekHarnessGreen →
plugins/dsh-session-rewindIt includes:
session.fork+sessions.open). Since the orphantool_callsonly lives inside the crashed turn, forking from the previous completed-turn boundary cleanly drops the poisoned tail while keeping all earlier history — a more convenient alternative to "start a new session" when you want to keep the conversation.tools/rewind-session.mjs— an offline rewind script (truncates a session log back to the last completed turn, with automatic backup) for maintenance windows.tools/apply-agentloop-guard.mjs— the diagnostic guard patch described above, as an idempotent re-appliable script.Built for DSH 0.1.0-rc.6; depends on
@deepseek-ai/dsh-session@0.1.0-rc.6(auto-installed into the profile). MIT licensed.All reactions