Replies: 5 comments 1 reply
|
Confirmed on macOS too, not Windows-specific. This is the "exact second-load entry point" you flagged as worth investigating: found it, with a direct reproduction. Root cause
Verified directly by calling the same internal resolve hook Packages reached through the adapter's other branch ( FixOne line in - const routedParent = pathToFileURL(route.kind === 'fallback' ? route.entry.declarer : route.parent).href
+ const routedParent = pathToFileURL(canonicalPath(route.kind === 'fallback' ? route.entry.declarer : route.parent)).hrefThis fixes module identity at the source rather than at one symbol: |
|
same on my win |
|
新commit 46a7f68 正常了,但是之前出错的的对话历史记录加载不出来 |
|
Thanks for the detailed reports. We've linked the source-launch @MoonShadow1976 Your latest result distinguishes two things: tool calls work again on the newer commit, but the earlier session still cannot load because V3-to-V4 migration rejects an unresolved tool call. That means we cannot treat the affected history as recovered. We've recorded this remaining case separately within the investigation; please keep the original session log intact rather than deleting or editing its records. |
Uh oh!
There was an error while loading. Please reload this page.
Summary
In the
webprofile (dsh web), every assistant tool call fails before dispatch with:The error fires immediately after the
tool/callevent is recorded and before any tool executes. It is model/provider-agnostic — reproduced identically with deepseek-official (native adapter) and glm-5.1-zhipu (via llm-proxy). Thecliprofile does not reproduce.Side effect: the failed turn leaves a dangling
tool_useblock with notool_result, which the DeepSeek Messages serializer then rejects on the next turn ("tool calls need immediate results" —packages/llm/llm-deepseek/src/protocols/messages/serialize.ts:117), effectively bricking the session.Reproduction
Start a stock web profile on a clean 0.1.6-alpha.2 checkout (no home-layer
cordis.patch.ymlremount of@deepseek-ai/dsh-tools):In the web UI, send a greeting such as "你好啊" (this triggers the built-in
hello-worldskill → the model emits askilltool call).The turn fails with
Cannot read properties of undefined (reading 'prepare'). The skill never loads.Any tool call triggers it, not only the skill tool.
Environment
@deepseek-ai/dsh-root0.1.6-alpha.2 (release, clean git)webreproduces;clidoes notRoot cause
@deepseek-ai/dsh-toolsis loaded as two independent module copies in the web profile.TOOL_RUNTIME_SCHEDULERis declared withSymbol():Symbol(description)creates a new unique symbol on every call — the description is only a label, not identity. Each loaded copy of the module therefore holds a differentTOOL_RUNTIME_SCHEDULERinstance that merely shares a description.ToolRuntimeservice instance hangs the scheduler object on its symbol:ctx.tools[<symbol-A>] = { prepare, dispatch, finalize, finish, ... }agent-loopreads with its own symbol:ctx.tools[<symbol-B>]symbol-A !== symbol-B, the lookup returnsundefined, andundefined.prepare(...)throws at:Evidence (diagnostic instrumentation)
I wrapped the throwing call to introspect
ctx.toolsat the failure point:{ "toolCallName": "skill", "message": "Cannot read properties of undefined (reading 'prepare')", "ctxToolsCtor": "ToolRuntime", "hasSchedulerSymbol": false, "schedulerType": "undefined", "schedulerKeys": ["Symbol(cordis.tracker)", "Symbol(@deepseek-ai/dsh-tools.scheduler)"] }Key findings:
ctxToolsCtor: "ToolRuntime"— the object is the realToolRuntimeservice instance (not a facade/proxy).schedulerKeyscontainsSymbol(@deepseek-ai/dsh-tools.scheduler)— a scheduler-keyed symbol is present as an own property ofctx.tools.hasSchedulerSymbol(TOOL_RUNTIME_SCHEDULER in ctx.tools) isfalseandctx.tools[TOOL_RUNTIME_SCHEDULER]isundefined.An own-property symbol with the right description but failing
inagainst the imported constant is only possible when the two are differentSymbolinstances — i.e. the module was loaded twice and each instantiation calledSymbol()anew.Stack at failure:
Why web-only
The
cliprofile loads@deepseek-ai/dsh-toolsonce, so the symbol identity matches andprepareresolves. The web profile's loading path produces a second copy (exact second-load entry point worth investigating — likely the cordis loader resolution / plugin-packaging boundary — but the symptom is fully explained by the identity mismatch regardless of where the second copy enters).Suggested fix
Use the global symbol registry so identity is stable across any number of loaded copies:
Symbol.for(key)returns the same symbol for a given key from the global registry, regardless of how many times the module is instantiated. This is the canonical fix for cross-module symbol-identity bugs. I applied this locally (src + compiled lib); theprepareerror no longer fires and tool calls dispatch correctly.Follow-up
The deeper cleanup is to dedupe the double-load of
@deepseek-ai/dsh-toolsin the web profile so there is a single source of truth for the module. ButSymbol.foris a safe, minimal, and correct fix that unblocks all web-profile tool calls today; the dedupe can follow.All reactions