liangmianya/dsh-synapse
liangmianya/dsh-synapseDeepSeek Harness 的可视化非线性对话工作区:把会话、追问与分支变成可浏览、可拖拽的对话地图。
Web 设置页的「循环引擎」开关,在五套引擎间切换驱动每个 dsh 会话的 agent 循环——内置 in-process 加托管的 Claude Code、Codex、Pi、Kimi Code——无需改动 harness;每个托管引擎都把思考与工具调用写入持久会话记录,接管命令、技能与 agent 预设,并经 dsh 子进程接缝沙箱运行。
Pick dsh web's agent loop engine per session — the built-in in-process loop (the default), or one of the hosted engines claude-code / codex / pi / kimi. Sessions are independent: one chat can run Codex while another runs Kimi. Any open, idle session can move engines — between two hosted engines the handover is in place, and a move involving in-process reloads the page (the dsh web process never restarts). Nothing in the main repository changes.
dsh plugin --profile web add dsh-loop-engine
Boot dsh web once (the router retries for a bounded window while the base bundle still holds the agent-factory slot), then open Settings → Loop engine.
Install notes
cordis.patch.yml; every other byte you wrote there is preserved. Upgrading from an older release needs no hand edit.web — the Desktop app's desktop, a headless deployment, a renamed profile — needs profile: <name> in the composition entry for that profile:
- id: loop-engine
config:
profile: desktop
profile defaults to web, so without it the plugin writes its managed block into <home>/profiles/web/cordis.patch.yml while the running profile never reads it: the plugin mounts, but the base agent-loop row is never disabled, so its router cannot take the factory slot and no hosted engine is reachable. (Found by installing into the Desktop app.)dsh plugin --profile web remove dsh-loop-engine plus deleting that managed block — the block outlives the plugin, and while it is present the profile has no agent factory, so no session can be created.ERR_PNPM_IGNORED_BUILDS, naming esbuild, @google/genai, protobufjs). Run pnpm approve-builds (or add an allowBuilds entry) and retry; only the installing project can grant this.file: shims — otherwise session resume fails with agent-presets: refusing to compose an unscoped context. Steps in docs/source-checkout.md.| Engine | Needs, on the host |
|---|---|
| Claude Code | the Claude Code CLI installed and logged in |
| Codex | codex login, or a CODEX_API_KEY environment entry |
| Pi | whatever pi expects (its own ~/.pi/agent/auth.json, or the provider's API-key variable) |
| Kimi Code | the kimi CLI installed and logged in, on PATH (or pinned via kimiBin) |
standard) for the in-process loop. A child agent inherits its parent's engine.in-process: the composer asks first, then the page reloads and reopens the same session (scroll position and unsent draft are lost; the record is not).external group whose single entry, default, means "the engine decides". Picking a real dsh model hands it to the engine together with its endpoint and credential; whether the engine can serve it is the engine's business, and a refusal is reported rather than swallowed. in-process sessions use dsh's models normally.childIdleMs (composition entry, milliseconds, default 0 = off) — Kimi and Codex keep one child process per session across steps; this closes it after that much idle time and respawns it on the next step. Only the child is closed, so nothing reloads. Pi and Claude Code spawn per step and are unaffected.engineContextWindow (composition entry, tokens, default 262144) — the context window dsh assumes for the shared hosted route. It is what dsh's auto-compaction measures a hosted session against (it fires at 80% of this by default), because a hosted engine reports no capacity of its own. Set it to the smallest window among the engines you run.summarizerProvider / summarizerModel (composition entry, set together or not at all) — the real dsh model a hosted session's compaction summarizes through, e.g. deepseek-official / deepseek-flash. Compaction is dsh's own (its preset keeps the compaction group), but the summarizing call is an ordinary llm request, and a hosted session's routed model is the plugin's placeholder route — so without this pair a hosted session can never be folded down: every attempt logs a warning and the turn continues. The pair only serves that call; the engine still answers every user turn itself. Composing just one of the two (or an empty string) is refused at boot, not silently ignored./export, /feedback, /permission) keep working under a hosted engine. Its preset is a copy of standard with the dsh-native rows an external engine replaces stripped out (dsh's /plan, the goal tool and /goal, the skill rows). dsh's compaction is kept: it is what keeps the session log — and so the transcript replayed to the engine on every step — bounded, which an engine's own per-turn compaction cannot do (a fresh engine session is opened per step, so the engine's shrink is discarded while the log keeps growing). Configure summarizerProvider / summarizerModel (above) or its summarizing call has no model to run on.One release serves the 0.1.5 line (>=0.1.5-rc.1 <0.1.6-0), the 0.1.7 line (>=0.1.7-rc.1 <0.1.8-0), the 0.2.0 line (>=0.2.0-rc.1 <0.2.1-0) and the 0.2.1 line (>=0.2.1-rc.1 <0.2.2-0): the plugin detects the running generation at load and takes the matching code path. Those union ranges are what it declares in peerDependencies, and a harness outside them fails loudly at boot or session resume.
Read the version as <harness line>-rcN, where rcN is this plugin's own release counter for that line — not the harness's rc number. Within a covered line a new harness rc needs no plugin release unless an API surface moved; docs/compatibility.md §1 lists those surfaces and the diff command that decides it.
| Plugin | Harness |
|---|---|
0.2.1-rc1 | 0.2.1-rc.1, 0.2.1-rc.2 (and every earlier line it still covers) |
0.2.0-rc1 | 0.2.0-rc.1, 0.2.0-rc.2 |
0.1.7-rc1 … 0.1.7-rc5 | 0.1.7-rc.1, 0.1.7-rc.2 |
0.1.5-rc3 … 0.1.5-rc5 | 0.1.5-rc.2 |
0.1.5-rc1 / 0.1.5-rc2 | 0.1.5-rc.1 |
1.0.0-rc8 … 1.0.0-rc15 | 0.1.2-rc.1 |
1.0.0-rc7 and earlier | 0.1.1-rc.2 |
0.2.1-rc1 is the first release that serves four lines at once. Two harness changes force it: the 0.2.1 line deleted @deepseek-ai/dsh-invariants and every <package>/invariant subpath, and it republished the JSONL durability backend as a namespace plugin with no default export. The plugin's ./invariant companion now declares the host registry's shape locally, so one build mounts on every line — and, because dsh skips a whole bundle whose @deepseek-ai/dsh-* peers do not satisfy the running version, dropping that package from peerDependencies is what lets the plugin load on 0.2.1 at all.
in-process loop instead of failing to open. See docs/per-session-engine.md §6.$DSH_HOME/.loop-engine/engines.json, not part of the session log: changing machine or DSH_HOME loses it and the session falls back to its preset. See §5.5.in-process reloads the page — the harness loop neither hands over a live session nor adopts one it did not create. See §5.2/§5.4.loop-engine read as "legacy hosted engine" until rebuilt once. See §7.in-process leaves the shared external group in the model menu (the catalog is not scoped per session).file: shims a source-launched harness needs.MIT