From f1b74a35ef1fb7c464cfedf6c54aa7392d8708ce Mon Sep 17 00:00:00 2001 From: jianf <2198972886@qq.com> Date: Wed, 4 Nov 2026 17:07:48 +0800 Subject: [PATCH] feat(memory): ship the profile overlay that mounts the replacement loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 6d9ad62 added `lib/loop.js` — a subclass of the harness `AgentLoop` that moves per-turn recall out of conversation history and into the system prompt. That class was never instantiated by anything: the commit proved the pure `promoteSnapshotSections` function, not that a replacement loop can actually be mounted. This commit adds the two pieces the mount needs. `cordis.patch.yml` is the overlay that does it, and it is the only artefact that proves the swap is possible: - `- id: agent-loop / disabled: true` is mandatory and is addressed by ID, not by name. `AgentLoop`'s constructor ends with `ctx.effect(() => ctx.agents.setFactory(this))` (dsh-agent-loop/lib/index.js:1590) and `setFactory` throws when a factory is already registered (dsh-agent/lib/index.js:429-437). Leaving the base row enabled fails startup with "an agent factory is already registered". - The inserted row reuses the package itself under the `dsh-memory/loop` subpath, with no `config` block: `HologramAgentLoop` declares no `static Config`, so it inherits the parent schema and the profile's own `agent-loop` config rows keep working through the inherited constructor. `package.json` gains that subpath export plus `lib/loop.js` in `files`. Without the export the overlay resolves to nothing and the profile cannot boot — the two changes only work together, which is why they land in one commit. Measured on this machine with the overlay applied to a headless profile (`~/.dsh/profiles/headless/cordis.patch.yml`), dsh 0.2.1-rc.2: - `dsh --profile headless "回答两个字:收到了"` -> exit 0, stdout `收到了`; `--dump-config` shows `- id: agent-loop` with `disabled: true` alongside `- id: hologram-agent-loop, name: dsh-memory/loop`. - A tool round trip returns the tool's output: asking for `echo TOOL_OK_42` via bash yields `TOOL_OK_42`. - SIGINT during a long task exits in 1s with code 130, stdout empty. - The web profile's patch layer is still `[]` — untouched. npm test: 247 pass, 0 fail. --- cordis.patch.yml | 29 +++++++++++++++++++++++++++++ package.json | 4 +++- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 cordis.patch.yml diff --git a/cordis.patch.yml b/cordis.patch.yml new file mode 100644 index 0000000..6cd78d8 --- /dev/null +++ b/cordis.patch.yml @@ -0,0 +1,29 @@ +# Ship-ready overlay that swaps the harness loop for `dsh-memory/loop`. +# +# This is the ONLY artefact that proves the replacement loop is mounted: without +# it `lib/loop.js` is a subclass nobody instantiates (its unit tests exercise the +# pure `promoteSnapshotSections` function and nothing else). +# +# Apply it to a profile (a `--patch` overlay, or copied into the profile's own +# `cordis.patch.yml`); `dsh` composes it over `@deepseek-ai/dsh-base`, where the +# `agent-loop` row already exists: +# +# dsh --profile headless --patch "" +# +# ★ The disable is not optional, and it is by ID, not by name. `AgentLoop`'s +# constructor ends with `ctx.effect(() => ctx.agents.setFactory(this))` +# (dsh-agent-loop/lib/index.js:1590), and `dsh-agent`'s `setFactory` throws when a +# factory is already registered (dsh-agent/lib/index.js:429-437). Leaving the base +# row enabled makes startup fail with "an agent factory is already registered"; +# `HologramAgentLoop` inherits that constructor, so it registers exactly once — +# but only if the base row is gone. +- id: agent-loop + disabled: true + +# The replacement. No `config` block on purpose: `HologramAgentLoop` defines no +# `static Config`, so it inherits the parent schema (`maxParallelToolCalls`, +# `agents`) and the profile's own `agent-loop` config rows keep working through +# the inherited constructor. +- insert: + - id: hologram-agent-loop + name: dsh-memory/loop diff --git a/package.json b/package.json index 89d2541..47659da 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,12 @@ "type": "module", "main": "lib/index.js", "exports": { - ".": "./lib/index.js" + ".": "./lib/index.js", + "./loop": "./lib/loop.js" }, "files": [ "lib/*.js", + "lib/loop.js", "lib/types/*.d.ts" ], "engines": {