Replies: 2 comments
|
tool-cordis 的 inspect-provider 注册破坏了默认 cordis 预设挂载——全新 dsh web 就踩到,说明是默认路径的问题(不是冷门配置)。 和第 3 章"预设挂载/依赖解析"的坑同类(#1415 的 Service 已注册也是单例冲突方向)。排查:确认 tool-cordis 与 cordis 预设的 provider 注册顺序。https://github.com/Electricitysheep/dsh-handbook/blob/main/docs/03-profiles.md |
|
I confirmed the collision against the current source layout:
That makes the reported process-lifetime behavior source-consistent. For operators, the least invasive recovery is to switch the default to standard and restart the whole DSH process before creating another session. A restart matters because the registry is process-owned. Avoid patching register() to silently return success: unless disposer ownership or reference counting is also defined, one fiber can unregister a provider still used by another. Moving the built-in providers to host startup, or giving each preset isolated ownership, is the safer durable direction. I added this as a tracked rc.6 boundary with the exact first evidence and workaround: |
Uh oh!
There was an error while loading. Please reload this page.
tool-cordisinspect-provider registration breaks mounting the shippedcordisagent preset (default)Summary
In a fresh
dsh webprocess, the first attempt to mount the shippedcordisagent preset (the deployment default) fails with
agent-preset-invalid: Host Cordis inspect provider "Service" is already registered.Mounting any other preset that includes
tool-cordisfirst (e.g. auser-authored preset that copies
cordis) leavescordispermanently brokenfor the lifetime of the process.
This is reproducible on the current deployment and silently breaks the UI
"New Session" button — the click resolves no session and no error toast is
shown to the user.
Reproduction
Start
dsh weband issue an RPC creating a session with the shippedcordispreset:Response:
{ "ok": false, "error": { "code": "agent-preset-invalid", "message": "agent-presets: preset \"cordis\" failed to mount: failed to apply loader entry tool-cordis (@deepseek-ai/dsh-tool-cordis): Host Cordis inspect provider \"Service\" is already registered", "details": { "agentPreset": "cordis", "reason": "failed to apply loader entry tool-cordis (@deepseek-ai/dsh-tool-cordis): Host Cordis inspect provider \"Service\" is already registered" } } }Comparing all shipped presets on the same fresh process:
tool-cordistool-cordistool-cordistool-cordistool-cordisIf a custom preset is mounted first (it succeeds),
cordiscannot bemounted later in the same process — every subsequent attempt fails with
the same error.
The browser UI silently absorbs the failure:
connectWorkspacerejects butno toast is rendered, so the user sees "click New Session -> nothing happens."
Root cause
@deepseek-ai/dsh-tool-cordis/lib/index.js:6495registers four Host inspectproviders (
Service,Event,Builtin,Tool) into the host plane'sCordisInspectRegistryService:CordisInspectRegistryService.register(
@deepseek-ai/dsh-cordis-host-runner/lib/types/inspect-registry.js:20-30)is not idempotent across fibers:
The service instance is process-global (the host registers it once via
ctx.reflect.provide), but itsprovidersMap has no fiber-scoped cleanup.The disposer returned by
register()does run when the originating fiberdisposes -- but as long as any session whose preset contains
tool-cordisremains live in the process, its effect keeps the provider registered, and
no later mount of a preset that also contains
tool-cordiscan succeed.The shipped
cordispreset attachestool-cordisat the preset root withno realm isolation:
Meanwhile
cordis.ymlitself documents the rule that a service-publishingrow either belongs in the host composition or sits inside an
isolaterealm (see the comments around
agent.cordis.yml:9-12and:25).tool-cordisviolates that rule: it mutates a host-plane Service'sinternal state from a preset, without going through
isolate.@deepseek-ai/dsh-agent-presets/lib/types/mount.js:161(leakedServices)is meant to catch preset rows that publish process-global services, but
only inspects Service registration -- it does not flag mutations of an
already-registered Service's internal state, which is exactly what
tool-cordisdoes.Expected behavior
cordispreset, being the deployment default, must bemountable in a fresh process without any prior session creation.
tool-cordisshould be able to coexist inthe same process (whether serially or concurrently).
-- silent failure makes this class of bug invisible.
Suggested fix directions
(Any of these is independently sufficient; the third is the smallest
change.)
tool-cordisshould not register its Host inspect providers as apreset row. Move the four
registration(...)calls intodsh-cordis-host-runner'sapply, so they run once on host startup,not on every preset mount.
Or: have
tool-cordisregister through an entry-localisolaterealm, mirroring the pattern
cordis.ymlitself documents forservice-publishing rows.
Or: make
CordisInspectRegistryService.registeridempotent acrossfibers -- if the same
manifest.idis already present, return theexisting disposer instead of throwing. This is the smallest code
change but treats the symptom rather than the cause.
Also:
SessionRuntime.createrejects with aSessionCreateErrorthat the web UI swallows. The shell's
startSession/connectWorkspacepath should propagate the error to a visible toast-- silent failures here are user-hostile.
Impact
cordisdefault cannot start a sessionimmediately if any preset they also use contains
tool-cordis.Session button is broken" rather than a preset configuration issue.
agent-presets.defaulttostandardin~/.dsh/settings.yaml. Thecordispreset itself remains unreachablefor the process lifetime.
All reactions