English | 中文
Target host: DeepSeek Harness (
@deepseek-ai/dshv0.1.0-rc.x, developer preview)
Turn DSH's event-sourced sessions into debuggable assets: a waterfall trajectory view, deterministic single-step replay (zero token cost), breakpoints, sandboxed edit-and-rerun, fork comparison, and performance analytics — plus OTel GenAI trace export and trajectory_* model tools for agents to introspect their own runs.
packages/
├── trajectory-debug/ # Service Definition + wire types (pure types, no plugin entry)
├── trajectory-debug-host/ # Host provider: replay/perf/compare engines, breakpoints, projections, commands, RPC transport
├── trajectory-debug-remotes/ # dual-face typert skeleton (browser RPC actually rides the host transport)
├── client-ui-trajectory-debug/ # browser "Debug" tab: waterfall + perf dashboard + replay/breakpoint/rerun/compare console
└── trajectory-debug-bundle/ # installable bundle: dsh.bundle + cordis.patch.yml
corepack pnpm install # requires corepack; Node >= 22.19
corepack pnpm -r build # emit lib/ (lib-first manifests)
corepack pnpm -r typecheck
corepack pnpm test # 56 vitest cases
corepack pnpm check # build + typecheck + test
corepack pnpm check:publish # pre-publish manifest validation
node scripts/smoke.mjs # real dsh process load smoke (rebuilds the td-smoke profile)| Capability | Notes |
|---|---|
| Waterfall engine | buildTrajectoryPage: turn/step/tool rows, status, timing, tokens, error codes, filters, paging |
| Deterministic replay | stepContextAt: model view + action per step; ReplayCursor step/seek — zero token, zero tool execution |
| Performance analytics | analyzePerf: success rates/percentiles, failure taxonomy, token distribution, TTFT/decode, turn stats (optional price table → cost) |
| Fork compare | compareTrajectories: step alignment, tool changes, result diffs, summary |
| Breakpoints | BreakpointManager: agent/pre-step waterfall short-circuit + timeout auto-resume |
| Edit-and-rerun | rerunTool through the full ctx.tools pipeline; record|sandbox|ask (ask fails closed without a live agent) |
| Fork + live resume | sessions.fork + agents.resume + followup; cascade: truncate|preserve |
| Projections | trajectoryDebug/trajectory + trajectoryDebug/perf on the session-projection registry — the browser consumes them with zero client folding |
| Commands | /trajectory [stepIndex], /perf |
| Model tools | trajectory_search / trajectory_step / trajectory_perf (opt-in via enableModelTools) |
| Trace export | export('trace'): OTel GenAI semantic-convention spans (Langfuse/LangSmith ready) |
| Sidecar persistence | FileSidecar atomic JSON writes (sidecar: 'memory'|'file') |
| Browser UI | "Debug" conversation view tab: waterfall + perf dashboard (projection-pushed, live) + replay/breakpoint/rerun/compare console |
| Browser RPC | host registers POST /api/trajectory-debug/rpc (webserver custom route, typert-independent); the browser calls it with fetch |
| Real load | scripts/smoke.mjs installs into a standalone profile and boots in a real dsh process |
DSH's typert Remote chain depends on build-time codegen. This plugin instead uses the sanctioned webserver custom-route extension point:
- Endpoint:
POST /api/trajectory-debug/rpc— body{ method, params }, response{ ok, value | error }; - Methods:
trajectory.list / step.context / perf / replay.start|step|seek / breakpoint.set|remove|list|resume / intervention.rerunTool / variant.fork|list|compare / export; - Security: the server binds loopback by default; the route adds no extra trust.
pnpm -r build && node scripts/bundle-client.mjs produces the browser bundle:
- entry
src/client/index.ts→ esbuild (CJS) → wrapped aswindow.__ModuleLoader__.load({ id, factory })(the official DSH client format); - runtime externals: only
react(shell seed); all dsh references are type-only (erased); - output
packages/client-ui-trajectory-debug/lib/client.js, served viaexports["./client"]; - after installing into a profile, sync the bundle into the profile copy (pnpm
file:deps are copies):robocopy packages\client-ui-trajectory-debug\lib <profile>\node_modules\dsh-client-ui-trajectory-debug\lib /MIR
Published on npm — install directly (no build required):
dsh plugin --profile web add dsh-trajectory-debug-bundle
dsh web --dump-config # expect trajectory-debug-host / -remotes / ui-trajectory-debug rowsFrom a source checkout:
corepack pnpm check
node scripts\smoke.mjs
dsh plugin --profile web add ./packages/trajectory-debug-bundleRestart dsh web: the Debug tab appears in the conversation view ring; /trajectory and /perf work in the input box.
All five packages are published to npm as v0.1.0: dsh-trajectory-debug, dsh-trajectory-debug-host, dsh-trajectory-debug-remotes, dsh-client-ui-trajectory-debug, dsh-trajectory-debug-bundle.
Release pipeline:
corepack pnpm check # gates
corepack pnpm check:publish # manifest validation (no file: deps, valid versions, bundle ships patch+index.js)
corepack pnpm publish:all # pnpm -r publish: workspace:* → version ranges; prepublishOnly builds first- Internal deps use
workspace:*(pnpm rewrites to version ranges on publish);file:deps are rejected by the validator; - Add the
dsh-plugintopic to the repository (auto-listed on deepseekdocs.com/ecosystem); curated listing viadocs/awesome-submission.md.
See COMPARISON.md: positioning vs dsh-message-edit / dsh-plugin-cost / dsh-deeplink / dsh-eval, and the improvements already shipped.
- Self-contained event model: engines fold a minimal
DebugEventmodel;adapt.tsis the only boundary touching DSHSessionEvent— immune to DSH's preview-period breaking changes; - Projection state is plain JSON (records/arrays, no Maps/Sets), satisfying the projection-cache persistence contract;
- "Model-visible == recorded" invariant: branch execution only ever uses the existing agent channels; the source session log is never rewritten;
- Replay is zero-cost: engines never call the LLM or tools;
- Self-built client bundle: no dependency on DSH's tsdown chain.
- Deps:
@deepseek-ai/cordis+dsh-session / dsh-agent / dsh-commands / dsh-session-projection(all^0.1.0-rc.6, tracking rc releases); - Unloading the plugin withdraws every registration (effect-owned); source sessions are untouched.