Bug: installing any plugin that depends on @deepseek-ai/dsh-tools breaks every tool call (Cannot read properties of undefined (reading 'prepare')) #1697
Replies: 6 comments
|
This is the #1486 family surfacing through the plugin install path — same-version dual module instances with module-local We maintain moonquake2004/dsh-doctor (offline diagnostic, profile/session/env) and its P5 check flags exactly this state: any real-directory copy of Worth echoing your suggested fix direction upstream: host-first resolution for the harness's own |
|
复现并确认了你的根因分析,补一个可直接落地的修复方案(已做机制级验证)。 根因(源码位置确认)
export const TOOL_RUNTIME_SCHEDULER: unique symbol = Symbol('@deepseek-ai/dsh-tools.scheduler')
修复(一行)-export const TOOL_RUNTIME_SCHEDULER: unique symbol = Symbol('@deepseek-ai/dsh-tools.scheduler')
+export const TOOL_RUNTIME_SCHEDULER: unique symbol = Symbol.for('@deepseek-ai/dsh-tools.scheduler')
回归测试新增 机制级验证(真实 npm 包 rc.6)用两个物理副本(两个独立项目各自 install 修复已放在 fork 分支,方便官方直接取用(当前仓库未开放外部 PR,等开放后可一键 cherry-pick): https://github.com/zoahdev/deepseek-harness/tree/fix/tool-runtime-scheduler-symbol-for 顺带:这个问题恰好也是 dsh-plugin-doctor(https://github.com/zoahdev/dsh-plugin-doctor)想提前兜住的场景——发布前在全新 profile 里做真安装/真调用验证,比"能加载"更接近真相。 |
|
Good catch on
So Sensible plan: land |
|
You're right — Upgraded fix: shared key + protocol version guard
Behavior matrix:
Regression tests cover all three: symbol identity across duplicate instances, Branch: https://github.com/zoahdev/deepseek-harness/tree/fix/tool-runtime-scheduler-symbol-for On host-first resolutionAgreed — that eliminates the whole class (any module-boundary symbol, not just this one), and the profile- In the meantime I'm adding the same tripwire as an optional profile check to dsh-plugin-doctor (detect a real-directory top-level |
|
Shipped as promised: dsh-plugin-doctor v1.2.0 now includes the profile-level tripwire. dsh-plugin-doctor --profile ~/.dsh/profiles/web
Happy to keep aligning the two doctors: yours is profile/session/env offline diagnostics, ours is the pre-publish plugin + profile tripwire; the checks are complementary. |
|
Verified the v1.2.0
Both directions verified, and the FAIL message is actionable. The upgraded Re: alignment — agreed. Ours stays user-side (profile/session/env offline diagnostics, 19 checks + remote catalog + fixture regression), yours covers the author-side bundle checks plus this profile tripwire; the overlap is exactly the profile-shadow precondition, which both now catch. Ping me when you want to sync the two doctor contracts (JSON schema / exit codes) so they stay interchangeable. |
Uh oh!
There was an error while loading. Please reload this page.
"### Summary\n\nInstalling any third-party plugin that depends on
@deepseek-ai/dsh-tools(e.g.@anweat/dsh-browser,@linxin666/dsh-ssh) breaks every agent tool call with:\n\n\nCannot read properties of undefined (reading 'prepare')\n\n\nThe turn ends immediately after the firsttool/call(turn/endreasonerror). This is a platform-level module-instance shadowing bug, not a plugin bug: the crash site isdsh-agent-loop's scheduler, and the plugin whose install triggered it is never even loaded into the config tree.\n\n### Environment\n\n- dsh 0.1.0-rc.6 (npm global install)\n- Profile:web(generated by dsh;pnpm-workspace.yamlusesnodeLinker: hoisted,autoInstallPeers: false)\n- pnpm 11, Windows 10, Node 24\n\n### Repro\n\n1.dsh plugin --profile web add @anweat/dsh-browser(any plugin whose dependencies include@deepseek-ai/dsh-toolsworks, e.g.@linxin666/dsh-ssh)\n2. Boot the web profile, start a session, and issue any prompt that triggers a tool call.\n3. The turn fails right after the first tool call withCannot read properties of undefined (reading 'prepare'). Repeats on every turn.\n\n### Root cause (verified)\n\n1. The profile'spnpm-workspace.yaml(dsh-generated) usesnodeLinker: hoisted, so the plugin's transitive@deepseek-ai/dsh-tools(the same version, 0.1.0-rc.6) is hoisted into the profile's top-levelnode_modules.\n2. The config tree anchorsbaseUrlat the profile directory, and bare specifiers resolve profile-first with the host as fallback (HostResolvedRootInclude.importinpackages/boot/app-boot\u2192internal.import(specifier, bareModuleBaseUrl, {})). Thetoolsentry (@deepseek-ai/dsh-tools) therefore loads the hoisted copy instead of the host's copy.\n3.dsh-agent-loopis loaded from the host copy and readsctx.tools[TOOL_RUNTIME_SCHEDULER].prepare(call.exec)using the host copy'sSymbol('@deepseek-ai/dsh-tools.scheduler')(a module-levelunique symbol). The registeredToolRuntimeinstance was created by the hoisted copy, whose prototype carries a different symbol value (Symbolidentity is per-module-instance). The lookup yieldsundefined\u2192undefined.prepare(...)\u2192 the exact TypeError above.\n\nVerified empirically: loading both copies of@deepseek-ai/dsh-tools@0.1.0-rc.6in one process yieldsTOOL_RUNTIME_SCHEDULERsymbols that are not===equal.\n\n### Impact\n\n- Any third-party plugin that importsdefineToolfrom@deepseek-ai/dsh-tools(the platform's own plugin-authoring API) and gets installed with a hoisted profile layout triggers this.\n- Two independent plugins are affected today:@anweat/dsh-browserand@linxin666/dsh-ssh(ships indsh-web-ui-all).\n- The failure is also completely non-diagnosable: nothing points at duplicate module instances.\n\n### Suggested fix directions\n\n- InHostResolvedRootInclude.import(or the nativeinternal.importfallback), resolve the harness's own scope (@deepseek-ai/*present in the host'snode_modules) from the host first, so a profile-installed duplicate can never shadow the host instance; or\n- Detect and warn/error when a profile-installed package shadows a host package of the same name+version, with an actionable message.\n\n### Workaround (verified on the affected setup)\n\nDeclare the SDK as alink:dependency in the profile so the profile resolves the host's copy (same realpath \u2192 same module instance \u2192 symbols match):\n\njsonc\n// ~/.dsh/profiles/web/package.json\n{\n \"dependencies\": {\n \"@deepseek-ai/dsh-tools\": \"link:C:/Users/<user>/AppData/Roaming/npm/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai/dsh-tools\",\n // ...other plugins\n }\n}\n\n\nthenpnpm installin the profile. After that, tool calls complete normally (verified end-to-end with a Pwsh tool call:1 \u8f6e \u00b7 2 \u6b65, no errors). Note the absolute path must be adjusted if the npm global prefix changes.\n"All reactions