dsh-loop-engine-allinone 0.4.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +88 -0
- package/README.md +171 -197
- package/README.zh.md +175 -157
- package/lib/client.js +28 -0
- package/lib/index.js +251 -108
- package/lib/invariant.js +28 -0
- package/lib/types/driver-acp/client.d.ts +20 -0
- package/lib/types/engine-registry.d.ts +35 -0
- package/lib/types/model-discovery.d.ts +98 -0
- package/lib/types/model-registry.d.ts +78 -0
- package/lib/types/provider-route.d.ts +8 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,94 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
8
8
|
|
|
9
9
|
Nothing yet.
|
|
10
10
|
|
|
11
|
+
## [0.7.0]
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Runtime model discovery.** A vendor shipping a model no longer needs a plugin
|
|
16
|
+
release. Two kinds of discovery, chosen so that the plugin still starts no external
|
|
17
|
+
process at boot:
|
|
18
|
+
- **free** — Kimi Code's catalog is read from its own `~/.kimi-code/config.toml` at
|
|
19
|
+
boot; an ACP engine's arrives in its `session/new` response the first time a
|
|
20
|
+
session opens (already paid for by that session).
|
|
21
|
+
- **costly** — `grok models` / `agy models` would need a new child process, so they
|
|
22
|
+
are deliberately not run: a menu render must not spawn anything. Those stay
|
|
23
|
+
declared.
|
|
24
|
+
- The provider route reads its model list through a thunk, so a catalog discovered
|
|
25
|
+
after boot appears without re-registering the route or restarting the harness.
|
|
26
|
+
- `catalogReport()` exposes each engine's catalog with its provenance
|
|
27
|
+
(`discovered` / `declared`), because "the engine told me" and "the plugin assumes"
|
|
28
|
+
are different claims.
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- **The per-engine "Custom Models" column is gone from both READMEs.** It listed
|
|
33
|
+
model ids that are now discovered, so a hardcoded list was exactly the staleness
|
|
34
|
+
this release removes — and a reader would have taken an old id for the plugin's
|
|
35
|
+
limit. MiniMax Code's region, the one fact in that column that is not a model,
|
|
36
|
+
moved into the requirements cell.
|
|
37
|
+
- The model section describes the mechanism (discovered, declared fallback, and the
|
|
38
|
+
settings page saying which) instead of naming engines.
|
|
39
|
+
- Claude Code's row no longer reads as if the bundled SDK were the only option:
|
|
40
|
+
`bins.claudeBin` runs an external install. (Pinning changes what executes; it does
|
|
41
|
+
not unload the SDK package, which the driver imports.)
|
|
42
|
+
|
|
43
|
+
### Verified
|
|
44
|
+
|
|
45
|
+
- On the reference host, `bootCatalog('kimi')` returns `origin: discovered`,
|
|
46
|
+
`source: kimi-config`, with four models read from the live config file.
|
|
47
|
+
|
|
48
|
+
## [0.6.0]
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
|
|
52
|
+
- **Kimi Code declares its model catalog** (K3, K3-256k, K2.8 Preview, K2.7 Code
|
|
53
|
+
Highspeed), read out of `~/.kimi-code/config.toml` — the file the Kimi Code
|
|
54
|
+
desktop app writes for a signed-in account. Those are the ids the app passes as
|
|
55
|
+
`model`, so they are the right vocabulary for this driver's `session/set_model`.
|
|
56
|
+
|
|
57
|
+
### Documented
|
|
58
|
+
|
|
59
|
+
- **Why ZCode has no catalog**: its GLM Coding Plan subscription has lapsed
|
|
60
|
+
(`[1309] 您的GLM Coding Plan套餐已到期`), and an expired account cannot enumerate
|
|
61
|
+
what it may use. This is an account state, not a missing CLI.
|
|
62
|
+
- **Why Pi has no catalog**: it refreshes its model list at runtime
|
|
63
|
+
(`pi update --models`) from each provider, so any list shipped here would be stale
|
|
64
|
+
by design.
|
|
65
|
+
- The model-menu section now says what a **shared** group means (the menu collapsing
|
|
66
|
+
engines whose catalogs this build has not measured) and that declaring a `models`
|
|
67
|
+
row gives an engine its own group.
|
|
68
|
+
|
|
69
|
+
## [0.5.0]
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- **Codex declares its model catalog**, so the model menu gives it a group of its
|
|
74
|
+
own instead of the shared `external` one. The ids were read out of the bundled
|
|
75
|
+
0.149.1 CLI binary — they are what `thread/start`'s `model` accepts, which the
|
|
76
|
+
driver passes straight through.
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
|
|
80
|
+
- **Installation is the first section of both READMEs.** It used to sit below a
|
|
81
|
+
ten-row requirements table, which put a gate in front of the one thing a reader
|
|
82
|
+
wants first. The requirements table is reference, so it now follows.
|
|
83
|
+
- The **local-checkout install command is gone**: it told a stranger to run
|
|
84
|
+
`dsh plugin add /path/to/dsh-loop-engine-allinone`, a path nobody has. npm is the
|
|
85
|
+
documented path.
|
|
86
|
+
- **`dsh web` was written as if it were the harness's name.** `dsh` is the CLI and
|
|
87
|
+
`web` is one of its profiles; that is now said once, where a reader meets it.
|
|
88
|
+
- The model-menu section explains what a **shared** group means: it is the menu
|
|
89
|
+
collapsing engines whose catalogs this build has not measured, not a restriction
|
|
90
|
+
on what an engine can run. A `models` row gives an engine its own group.
|
|
91
|
+
|
|
92
|
+
### Notes
|
|
93
|
+
|
|
94
|
+
- **Pi deliberately has no declared catalog.** It refreshes its model list at
|
|
95
|
+
runtime (`pi update --models`) from each provider, so any list shipped here would
|
|
96
|
+
be stale by design. Kimi and ZCode have none either: neither was installed on the
|
|
97
|
+
machine this release was measured on, so nothing could be observed.
|
|
98
|
+
|
|
11
99
|
## [0.4.1]
|
|
12
100
|
|
|
13
101
|
### Added
|
package/README.md
CHANGED
|
@@ -3,222 +3,196 @@
|
|
|
3
3
|
**English** · [简体中文](README.zh.md)
|
|
4
4
|
|
|
5
5
|
[](LICENSE)
|
|
6
|
-
[ as data
|
|
57
|
-
rather than JSX, so a test can assert that every registered engine has one.
|
|
58
|
-
|
|
59
|
-
Both tables are exhaustive over the hosted roster and pinned by tests — the
|
|
60
|
-
failure this prevents is real: when four engines were first added, every one of
|
|
61
|
-
them fell through the mark switch's `default` arm and rendered the DeepSeek fish
|
|
62
|
-
beside its name.
|
|
63
|
-
|
|
64
|
-
## Engine registry
|
|
65
|
-
|
|
66
|
-
Every engine-shaped decision derives from ONE table,
|
|
67
|
-
[`src/engine-registry.ts`](src/engine-registry.ts): the id roster, the settings
|
|
68
|
-
schema's union, the authored preset ids and display names, the browser half's
|
|
69
|
-
option list and copy keys, and the driver dispatch
|
|
70
|
-
([`src/engine-drivers.ts`](src/engine-drivers.ts)). Both tables are total over
|
|
71
|
-
the hosted ids, so a half-added engine fails the build rather than shipping an
|
|
72
|
-
engine that mounts but cannot be selected.
|
|
73
|
-
|
|
74
|
-
Each row declares what the surfaces need to know: human-readable label, source
|
|
75
|
-
repo, whether the engine is an npm-bundled dependency or an external CLI, the key
|
|
76
|
-
its executable override reads, its version/update argv, its login hint, its
|
|
77
|
-
credential paths, and its **capabilities** (`streaming`, wire `protocol`,
|
|
78
|
-
`sessionResume`, `permissionModes`, `images`, `reasoningLevels`). Capabilities are
|
|
79
|
-
declarations, not discoveries: a surface never promises more than the engine was
|
|
80
|
-
verified to do, and a driver asked for something outside its declaration refuses
|
|
81
|
-
with the user's next action rather than degrading silently.
|
|
82
|
-
|
|
83
|
-
New engines implement one method. `src/driver-cli/` supplies the rest: the
|
|
84
|
-
turn/step lifecycle (`cli-agent.ts`), the durable-log writer
|
|
85
|
-
(`session-sink.ts` — where the session format's "refuse to load" rules are
|
|
86
|
-
enforced in one place), the subprocess transport, and four protocol skeletons
|
|
87
|
-
(`ndjson`, `stream-json` for the Claude-Code dialect, `text`, plus the existing
|
|
88
|
-
engines' ACP and JSON-RPC drivers as their templates).
|
|
89
|
-
|
|
90
|
-
## Install
|
|
6
|
+
[](#version-compatibility)
|
|
7
|
+
|
|
8
|
+
**dsh-loop-engine-allinone** is an all-in-one agent loop engine switcher for **[DeepSeek Harness](https://github.com/deepseek-ai)** (`dsh`). It enables per-session engine switching across **10 hosted engines** (Claude Code, Codex, Pi, Kimi Code, Antigravity, ZCode, Qoder CN, Hermes Agent, Grok Build, MiniMax Code) alongside the built-in `in-process` loop.
|
|
9
|
+
|
|
10
|
+
> `dsh` is the harness CLI. `dsh web` boots its **web profile**, which is the UI this plugin's engine picker and settings page live in.
|
|
11
|
+
|
|
12
|
+
Sessions are fully independent: run Codex in one chat while another runs Kimi Code or Antigravity simultaneously. Handover between two hosted engines happens seamlessly in place; switching to or from the native `in-process` engine performs an in-browser reload without restarting the backend process. All without modifying the DeepSeek Harness core codebase.
|
|
13
|
+
|
|
14
|
+
> **Fork Note**: This project is a fork of [`kuun993/dsh-loop-engine`](https://github.com/kuun993/dsh-loop-engine).
|
|
15
|
+
> While the upstream plugin introduced per-session switching for 4 initial engines, this fork refactors the internals into a **unified data-driven engine registry** and **shared driver infrastructure**, expanding support to **10 distinct engines**.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
### Highlights & Comparison with Upstream
|
|
20
|
+
|
|
21
|
+
| Feature | Upstream (`kuun993`) | This Fork (`allinone`) |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| **Supported Engines** | 4 engines | **10 engines** (+ native `in-process`) |
|
|
24
|
+
| **Engine Configuration** | Hardcoded across 5+ files | **Single registry table** (`src/engine-registry.ts`) |
|
|
25
|
+
| **Adding New Engines** | Modify 5 separate files | **1 registry row + 1 driver** |
|
|
26
|
+
| **ACP Protocol** | 1 engine (Kimi) | **3 engines** (Kimi, Grok, MiniMax) on a shared ACP skeleton |
|
|
27
|
+
| **CLI Drivers** | Ad-hoc implementations | Standardized `driver-cli/` & `driver-acp/` runtimes |
|
|
28
|
+
| **Model Selection** | Global default only | **Per-engine subscription catalogs**, discovered at runtime (no release needed when a vendor ships a model) |
|
|
29
|
+
| **UI Integration** | Standard labels | **Custom branded marks & status badges** for all 10 engines |
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
91
34
|
|
|
92
35
|
```sh
|
|
93
|
-
# From
|
|
94
|
-
|
|
95
|
-
|
|
36
|
+
# From npm (recommended)
|
|
37
|
+
dsh plugin --profile web add dsh-loop-engine-allinone
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Then boot the web profile once and open **Settings → Loop engine**:
|
|
96
41
|
|
|
97
|
-
|
|
98
|
-
dsh
|
|
42
|
+
```sh
|
|
43
|
+
dsh web
|
|
99
44
|
```
|
|
100
45
|
|
|
101
|
-
|
|
46
|
+
Installing into a profile other than `web` (the Desktop app's `desktop`, a
|
|
47
|
+
`headless` deployment, a renamed profile) means naming that profile instead:
|
|
48
|
+
`dsh plugin --profile desktop add dsh-loop-engine-allinone`, **and** setting
|
|
49
|
+
`profile: desktop` in the composition entry — see the notes below, because
|
|
50
|
+
forgetting the second half is the one mistake that leaves the plugin mounted but
|
|
51
|
+
unable to run any engine.
|
|
102
52
|
|
|
103
|
-
|
|
53
|
+
### Installation Notes
|
|
104
54
|
|
|
105
|
-
- The
|
|
106
|
-
- **
|
|
55
|
+
- **Profile Configuration**: The installer automatically injects a managed configuration block into your profile's `cordis.patch.yml`. All other custom configuration in that file is preserved.
|
|
56
|
+
- **Non-web Profiles**: When installing into non-web profiles (such as `desktop` or headless), explicitly specify `profile: <name>` in the composition entry:
|
|
107
57
|
```yaml
|
|
108
58
|
- id: loop-engine
|
|
109
59
|
config:
|
|
110
60
|
profile: desktop
|
|
111
61
|
```
|
|
112
|
-
|
|
113
|
-
- **
|
|
114
|
-
- **pnpm 10
|
|
115
|
-
- **
|
|
62
|
+
*(Without this, configuration defaults to `web` and the plugin will not attach to custom profiles.)*
|
|
63
|
+
- **Uninstallation**: Run `dsh plugin --profile web remove dsh-loop-engine-allinone`, then remove the managed `loop-engine` block from `cordis.patch.yml`.
|
|
64
|
+
- **pnpm 10+**: If dependency build scripts are blocked (`ERR_PNPM_IGNORED_BUILDS` mentioning `esbuild`, `@google/genai`, etc.), run `pnpm approve-builds`.
|
|
65
|
+
- **Harness from Source**: If launching the harness directly from a source checkout, bridge peer dependencies using `file:` shims as described in [docs/source-checkout.md](docs/source-checkout.md).
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Supported Engines
|
|
72
|
+
|
|
73
|
+
| Engine | Type / Protocol | Host Requirements & Authentication |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| **Claude Code** | Bundled SDK / `ndjson` | Nothing, by default (the SDK ships a binary); set `bins.claudeBin` to run your own install instead |
|
|
76
|
+
| **Codex** | Bundled / `jsonrpc` | `codex login` or `CODEX_API_KEY` |
|
|
77
|
+
| **Pi** | Bundled / `jsonrpc` | `~/.pi/agent/auth.json`, or the provider's API-key variable |
|
|
78
|
+
| **Kimi Code** | External CLI / `acp` | `kimi` CLI installed and authenticated (`kimi login`) |
|
|
79
|
+
| **Antigravity** | External CLI / `ndjson` | `agy` CLI installed and signed in to Google |
|
|
80
|
+
| **ZCode** | External CLI / `jsonrpc` | `zcode` CLI installed, with a live GLM Coding Plan subscription |
|
|
81
|
+
| **Qoder CN** | External CLI / `ndjson` | `qoderclicn` CLI installed and authenticated |
|
|
82
|
+
| **Hermes Agent** | External CLI / `text` | `hermes` CLI installed and configured (`hermes setup`) |
|
|
83
|
+
| **Grok Build** | External CLI / `acp` | `grok` CLI installed and signed in once (`grok login`) |
|
|
84
|
+
| **MiniMax Code** | External CLI / `acp` | `npm i -g @minimax-ai/code`, `mcode login --region cn\|global`, then `mcode provider use token-plan` |
|
|
85
|
+
|
|
86
|
+
> **Model lists are discovered, not listed here.** Each engine's models come from the engine itself — Kimi Code's own config file at boot, an ACP engine's `session/new` response as soon as a session opens — so a vendor shipping a model does not need a plugin release. Engines whose catalog this build cannot read fall back to a declared list, and one with neither shows the shared `external` group. The settings page shows which is which.
|
|
87
|
+
|
|
88
|
+
> **Note**: For external CLI engines (`bundled: false`), the plugin spawns your locally installed binaries; it does not download or authenticate them automatically. Please install and log in on your host machine beforehand.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Configuration
|
|
95
|
+
|
|
96
|
+
Custom settings can be configured under your profile's composition entry:
|
|
97
|
+
|
|
98
|
+
```yaml
|
|
99
|
+
- id: loop-engine
|
|
100
|
+
config:
|
|
101
|
+
# 1. Custom executable paths (optional - overrides default PATH / bundled binaries)
|
|
102
|
+
bins:
|
|
103
|
+
claudeBin: 'D:/tools/claude.exe'
|
|
104
|
+
kimiBin: 'D:/tools/kimi.exe'
|
|
105
|
+
agyBin: 'D:/tools/agy.exe'
|
|
106
|
+
qoderclicnBin: 'D:/tools/qoderclicn.exe'
|
|
107
|
+
grokBin: 'C:/Users/user/.grok/bin/grok.exe'
|
|
108
|
+
minimaxcodeBin: 'D:/npm-global/node_modules/@minimax-ai/code/cli.js'
|
|
109
|
+
|
|
110
|
+
# 2. Region override (optional - MiniMax Code supports 'cn' or 'en')
|
|
111
|
+
regions:
|
|
112
|
+
mcodeRegion: 'cn'
|
|
113
|
+
|
|
114
|
+
# 3. Child process idle timeout in milliseconds (default: 0 = disabled)
|
|
115
|
+
# Applies to engines with persistent subprocesses (Kimi, Codex, Grok, MiniMax).
|
|
116
|
+
childIdleMs: 300000
|
|
117
|
+
|
|
118
|
+
# 4. Context window for hosted sessions (default: 262144 tokens)
|
|
119
|
+
# Used by dsh auto-compaction (triggers at 80% of this limit).
|
|
120
|
+
engineContextWindow: 262144
|
|
121
|
+
|
|
122
|
+
# 5. Summarizer model for session compaction (must be set together)
|
|
123
|
+
# Hosted sessions route compaction through this model.
|
|
124
|
+
summarizerProvider: 'deepseek-official'
|
|
125
|
+
summarizerModel: 'deepseek-flash'
|
|
126
|
+
```
|
|
116
127
|
|
|
117
|
-
|
|
128
|
+
---
|
|
118
129
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
- The catalog is **declared in the engine registry**, not probed at boot — this plugin starts no external process when the harness boots. A deployment whose subscription changed updates [`src/engine-registry.ts`](src/engine-registry.ts)'s `models` row; a stale id then fails loudly at the engine, which is the honest outcome.
|
|
146
|
-
- `in-process` sessions use dsh's models normally.
|
|
147
|
-
- **`bins`** (composition entry, optional) — per-engine executable overrides, keyed by each engine's registry `binConfigKey`. Pointing a **bundled** engine at an external CLI is how it is unbound: `claudeBin` reaches the SDK's own `pathToClaudeCodeExecutable`, while `codexBin` / `piBin` replace the entrypoint those drivers launch. Not setting one keeps the bundled copy and its argv byte for byte:
|
|
148
|
-
```yaml
|
|
149
|
-
- id: loop-engine
|
|
150
|
-
config:
|
|
151
|
-
bins:
|
|
152
|
-
claudeBin: 'D:/tools/claude.exe'
|
|
153
|
-
kimiBin: 'D:/tools/kimi.exe'
|
|
154
|
-
qoderclicnBin: 'D:/tools/qoderclicn.exe'
|
|
155
|
-
grokBin: 'C:/Users/me/.grok/bin/grok.exe'
|
|
156
|
-
minimaxcodeBin: 'D:/Programs/npm-global/node_modules/@minimax-ai/code/cli.js'
|
|
157
|
-
```
|
|
158
|
-
An npm-installed CLI needs no pin (the resolver finds the package entrypoint, and
|
|
159
|
-
a Windows `.cmd` shim is launched through `cmd.exe` — node refuses a `.cmd`
|
|
160
|
-
directly), but a pin is the way to choose among several installs.
|
|
161
|
-
- **`regions`** (composition entry, optional) — per-engine account **region**
|
|
162
|
-
overrides, keyed by each registry row's `region.configKey`. Today only MiniMax
|
|
163
|
-
Code declares one (`regions.mcodeRegion`, default `cn`), because its login
|
|
164
|
-
endpoint AND its stored credentials are region-scoped:
|
|
165
|
-
```yaml
|
|
166
|
-
- id: loop-engine
|
|
167
|
-
config:
|
|
168
|
-
regions:
|
|
169
|
-
mcodeRegion: 'en' # this engine's spelling of the non-China account
|
|
170
|
-
```
|
|
171
|
-
The value is spelled into the child's environment as the variable that engine's
|
|
172
|
-
CLI actually reads (`MAVIS_REGION` — measured, and NOT `MCODE_REGION`, which is
|
|
173
|
-
inert on the `mcode acp` path). An unknown value, or a `region` that contradicts
|
|
174
|
-
the same variable in `env`, fails the engine's construction loud rather than
|
|
175
|
-
pointing the child at an account nobody chose.
|
|
176
|
-
- **`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.
|
|
177
|
-
- **`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.
|
|
178
|
-
- **`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.
|
|
179
|
-
- **dsh's own commands** (`/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.
|
|
130
|
+
## Usage Guide
|
|
131
|
+
|
|
132
|
+
- **Creating Sessions**: Select an engine from the preset dropdown next to the workspace picker, or leave it as `standard` to use the native `in-process` loop. Subagents automatically inherit their parent's engine.
|
|
133
|
+
- **Default Engine**: Configure the default engine for new chats under **Settings → Loop engine**. Existing sessions remain unchanged.
|
|
134
|
+
- **Switching Engines Mid-Session**: Enable *Show the engine selector in the chat page* in settings to switch engines directly from the composer:
|
|
135
|
+
- **Hosted ↔ Hosted**: Handover occurs in place immediately.
|
|
136
|
+
- **Hosted ↔ In-Process**: Prompts for confirmation and reloads the browser tab (chat history is preserved; unsent drafts and scroll positions are reset).
|
|
137
|
+
- *Note*: Engine switching is permitted only when the current session is idle.
|
|
138
|
+
- **Header Badge**: Shows the engine actively powering the current session. Can be toggled via *Show the engine badge in the conversation header*.
|
|
139
|
+
- **Model Selection**:
|
|
140
|
+
- **A catalog is discovered, not shipped.** Kimi Code's is read from its own config file at boot; an ACP engine's arrives in its `session/new` response the first time a session opens; Codex's is static in its bundled CLI. Picking a discovered model passes its id to the engine. **A vendor shipping a model therefore needs no plugin release.**
|
|
141
|
+
- An engine whose catalog this build cannot read falls back to a **declared** list, and the settings page says which of the two you are looking at. **Pi** has none by design (it refreshes from each provider at runtime via `pi update --models`); **ZCode**'s could not be read because its GLM Coding Plan subscription has lapsed, and an expired account cannot enumerate what it may use.
|
|
142
|
+
- Other hosted engines share one `external` group holding a single `default`, which means "let the engine decide". A shared group is not a limitation on what you can run — it is the menu collapsing engines whose catalogs this build has not measured. Declaring a catalog (one `models` row in the registry) gives an engine its own group.
|
|
143
|
+
- Picking a **real dsh model** instead hands the engine that model's endpoint and credential as well; whether the engine can serve it is the engine's business, and a refusal is reported rather than swallowed.
|
|
144
|
+
- Native dsh commands (`/export`, `/feedback`, `/permission`) and context auto-compaction remain fully functional.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Architecture & Extending
|
|
149
|
+
|
|
150
|
+
Adding a new engine is straightforward thanks to the unified registry:
|
|
151
|
+
|
|
152
|
+
1. **Register Descriptor**: Add the engine ID to `HOSTED_ENGINE_IDS` and define its metadata and capabilities in `src/engine-registry.ts`.
|
|
153
|
+
2. **Implement Driver**: Create a driver implementing `runStep` (leveraging `src/driver-cli/` or `src/driver-acp/`).
|
|
154
|
+
3. **Bind Driver**: Register the driver class in `src/engine-drivers.ts`.
|
|
155
|
+
4. **UI Localization**: Add display strings in `src/client/locales.ts` and an optional SVG icon in `src/client/engine-marks.ts`.
|
|
180
156
|
|
|
181
|
-
|
|
157
|
+
Both tables enforce compile-time exhaustiveness checks — incomplete engine registrations fail at build time rather than runtime. Detailed instructions are in [docs/engine-registry.md](docs/engine-registry.md).
|
|
182
158
|
|
|
183
|
-
|
|
159
|
+
---
|
|
184
160
|
|
|
185
|
-
|
|
161
|
+
## Version Compatibility
|
|
186
162
|
|
|
187
|
-
|
|
163
|
+
A single release seamlessly supports multiple DeepSeek Harness generations via runtime detection:
|
|
164
|
+
|
|
165
|
+
| Plugin Release | Supported DeepSeek Harness Line |
|
|
188
166
|
|---|---|
|
|
189
|
-
| `0.2.0-
|
|
190
|
-
| `0.1.7-
|
|
191
|
-
| `0.1.5-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
- **
|
|
201
|
-
- **
|
|
202
|
-
- **
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
- [docs/
|
|
211
|
-
- [docs/
|
|
212
|
-
- [docs/compatibility.md](docs/compatibility.md) —
|
|
213
|
-
- [docs/
|
|
214
|
-
- [
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
- [docs/optimization-backlog.md](docs/optimization-backlog.md) — known issues and the optimization list.
|
|
218
|
-
- [docs/proposals/](docs/proposals/) — main-repo proposals.
|
|
167
|
+
| `0.2.0-rcX` | `0.2.0-rc.1`, `0.2.0-rc.2` |
|
|
168
|
+
| `0.1.7-rcX` | `0.1.7-rc.1`, `0.1.7-rc.2` |
|
|
169
|
+
| `0.1.5-rcX` | `0.1.5-rc.1`, `0.1.5-rc.2` |
|
|
170
|
+
|
|
171
|
+
See [docs/compatibility.md](docs/compatibility.md) for harness upgrade checklists and API surface diffs.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Technical Notes & Limitations
|
|
176
|
+
|
|
177
|
+
- **Agent Factory Replacement**: The plugin registers a unified facade over the harness agent factory. Any session that cannot be routed to a hosted engine gracefully falls back to the native `in-process` loop.
|
|
178
|
+
- **Engine State Persistence**: Active session engine bindings are stored in `$DSH_HOME/.loop-engine/engines.json`. If this file is cleared, sessions revert to their preset defaults.
|
|
179
|
+
- **Subprocess Concurrency**: Multi-session execution shares the respective CLI's local authentication and configuration directory.
|
|
180
|
+
- **Grok Build Shell Execution**: Grok tools rely on the harness client terminal bridge (`ctx.shell`).
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Documentation Links
|
|
185
|
+
|
|
186
|
+
- [docs/engine-registry.md](docs/engine-registry.md) — Engine registration guide & ACP engine recipe.
|
|
187
|
+
- [docs/per-session-engine.md](docs/per-session-engine.md) — Detailed user-facing behaviors and handover specs.
|
|
188
|
+
- [docs/architecture.md](docs/architecture.md) — Core routing, factory slots, and configuration patches.
|
|
189
|
+
- [docs/driver-core.md](docs/driver-core.md) — Shared driver runtime and lifecycle management.
|
|
190
|
+
- [docs/compatibility.md](docs/compatibility.md) — Multi-version harness compatibility guide.
|
|
191
|
+
- [docs/source-checkout.md](docs/source-checkout.md) — Running alongside a harness source checkout.
|
|
192
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md) — Development and probe verification workflows.
|
|
193
|
+
|
|
194
|
+
---
|
|
219
195
|
|
|
220
196
|
## License
|
|
221
197
|
|
|
222
|
-
MIT
|
|
223
|
-
notice is preserved there beside this fork's own; [NOTICE](NOTICE) records what the
|
|
224
|
-
fork adds and what it deliberately leaves untouched.
|
|
198
|
+
[MIT](LICENSE) © contributors of `dsh-loop-engine-allinone` and upstream `kuun993/dsh-loop-engine`. See [NOTICE](NOTICE) for license and attribution details.
|