@ljwei-stak/dsh-model-router 0.23.1 → 0.24.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/.dsh-plugin/client.js +83 -34
- package/.dsh-plugin/index.mjs +281 -51
- package/.dsh-plugin/shared/budget-reservations.mjs +254 -0
- package/.dsh-plugin/shared/execution-lifecycle.mjs +141 -0
- package/.dsh-plugin/shared/official-team-runtime.mjs +37 -13
- package/.dsh-plugin/shared/official-tools-runtime.mjs +3 -2
- package/.dsh-plugin/shared/router-state.mjs +23 -8
- package/.dsh-plugin/shared/run-ledger.mjs +6 -1
- package/.dsh-plugin/shared/task-executors.mjs +32 -3
- package/.dsh-plugin/shared/zcode-bundle.mjs +3 -3
- package/CHANGELOG.md +13 -0
- package/README.i18n.yaml +2 -2
- package/README.md +25 -17
- package/README.zh.md +24 -16
- package/docs/assets/workbench-budget-reservations.png +0 -0
- package/docs/releases/0.24.0-validation.md +41 -0
- package/package.json +7 -3
|
@@ -13,6 +13,7 @@ export const MAX_STORED_TASK = 20_000
|
|
|
13
13
|
export const MAX_QUALITY_BIAS = 0.04
|
|
14
14
|
|
|
15
15
|
const finite = value => typeof value === 'number' && Number.isFinite(value)
|
|
16
|
+
const receiptTimestamp = value => finite(value) && value >= 0 && Number.isFinite(new Date(value).getTime())
|
|
16
17
|
const nonEmptyText = value => (typeof value === 'string' && value.length > 0 ? value : null)
|
|
17
18
|
const routeKey = (provider, model) => `${String(provider ?? '')}\u0000${String(model ?? '')}`
|
|
18
19
|
|
|
@@ -382,7 +383,7 @@ function storedPackage(planned, result, pricing, finishedAt, billingFor = billin
|
|
|
382
383
|
// silently rewrite historical spend calculated from usage.
|
|
383
384
|
pricingSnapshot: pricing ? { ...pricing } : null,
|
|
384
385
|
...cost,
|
|
385
|
-
finishedAt,
|
|
386
|
+
finishedAt: receiptTimestamp(result?.finishedAt) ? result.finishedAt : finishedAt,
|
|
386
387
|
review: planned.review ?? null,
|
|
387
388
|
rating: planned.rating ?? null,
|
|
388
389
|
}
|
|
@@ -488,6 +489,7 @@ export function teamExecutionResults(plan, execution) {
|
|
|
488
489
|
...reasoningExecutionFields(result),
|
|
489
490
|
...(finite(result.durationMs) && result.durationMs >= 0 ? { durationMs: result.durationMs } : {}),
|
|
490
491
|
...(finite(result.inputChars) && result.inputChars >= 0 ? { inputChars: result.inputChars } : {}),
|
|
492
|
+
...(receiptTimestamp(result.finishedAt) ? { finishedAt: result.finishedAt } : {}),
|
|
491
493
|
requestedCliModel: result.requestedCliModel ?? null,
|
|
492
494
|
actualModel: result.actualModel ?? null,
|
|
493
495
|
...(result.reportedModel !== undefined ? { reportedModel: result.reportedModel } : {}),
|
|
@@ -541,6 +543,8 @@ export function buildToolRunRecord({ toolId, toolLabel, provider, model, cliMode
|
|
|
541
543
|
status: result?.status ?? 'pending',
|
|
542
544
|
packages: [{
|
|
543
545
|
id: packageId, ok: succeeded, cancelled: result?.status === 'cancelled',
|
|
546
|
+
...(result?.notStarted === true || result?.status === 'unsupported' ? { notStarted: true } : {}),
|
|
547
|
+
...(result?.blocked === true ? { blocked: true } : {}),
|
|
544
548
|
provider: plan.directRoute.provider, model: plan.directRoute.model,
|
|
545
549
|
channel: 'official-cli', toolId,
|
|
546
550
|
requestedCliModel: Object.hasOwn(result ?? {}, 'requestedModel') ? result.requestedModel : cliModel,
|
|
@@ -550,6 +554,7 @@ export function buildToolRunRecord({ toolId, toolLabel, provider, model, cliMode
|
|
|
550
554
|
...(typeof result?.source === 'string' ? { source: result.source } : {}),
|
|
551
555
|
...(typeof result?.sandboxEnforcement === 'string' ? { sandboxEnforcement: result.sandboxEnforcement } : {}),
|
|
552
556
|
...(result?.usageIncomplete === true ? { usageIncomplete: true } : {}),
|
|
557
|
+
...(receiptTimestamp(result?.finishedAt) ? { finishedAt: result.finishedAt } : {}),
|
|
553
558
|
answer: String(result?.finalText ?? ''),
|
|
554
559
|
error: succeeded ? null : String(result?.error ?? result?.reason ?? result?.status ?? '官方 CLI 未成功完成。'),
|
|
555
560
|
...(!succeeded && typeof result?.diagnostic === 'string' && result.diagnostic.trim()
|
|
@@ -1229,6 +1229,25 @@ export async function observeExecutionProgress(hook, value) {
|
|
|
1229
1229
|
try { await hook(value) } catch { /* Progress reporting does not control execution. */ }
|
|
1230
1230
|
}
|
|
1231
1231
|
|
|
1232
|
+
/** Required Host persistence is a dispatch boundary, unlike progress observers. */
|
|
1233
|
+
export async function awaitExecutionCheckpoint(hook, value, partial, stage) {
|
|
1234
|
+
if (typeof hook !== 'function') return
|
|
1235
|
+
try { await hook(value) } catch (cause) {
|
|
1236
|
+
const budgetChanged = cause?.code === 'ROUTER_BUDGET_CHANGED'
|
|
1237
|
+
const error = new Error(budgetChanged ? String(cause.message) : `执行检查点保存失败:${String(cause?.message ?? cause)}`, { cause })
|
|
1238
|
+
error.code = budgetChanged ? 'ROUTER_BUDGET_CHANGED' : 'ROUTER_CHECKPOINT_FAILED'
|
|
1239
|
+
if (budgetChanged) {
|
|
1240
|
+
error.budget = cause.budget
|
|
1241
|
+
error.runId = cause.runId
|
|
1242
|
+
error.reason = cause.reason
|
|
1243
|
+
}
|
|
1244
|
+
error.checkpointStage = stage
|
|
1245
|
+
// The caller can retain paid receipts even when the persistence sink failed.
|
|
1246
|
+
error.execution = typeof partial === 'function' ? partial() : partial
|
|
1247
|
+
throw error
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1232
1251
|
function checkedPackageSelections(packages, routes, overrides, runVerified, targets) {
|
|
1233
1252
|
const preceding = new Set()
|
|
1234
1253
|
const selected = {}
|
|
@@ -1305,11 +1324,12 @@ async function runManualTool(target, prompt, options) {
|
|
|
1305
1324
|
*/
|
|
1306
1325
|
async function runPackages({ packages, task, routingBypassed, routes, previous = [], targets = null, overrides = {}, choices = {}, options }) {
|
|
1307
1326
|
const routeList = Array.isArray(routes) ? routes : []
|
|
1308
|
-
const { credentialsFor, onPackageStart, onPackage, onStage, billing, ...runOptions } = options
|
|
1327
|
+
const { credentialsFor, onPackageStart, onPackage, onStage, onCheckpointStart, onCheckpointResult, billing, ...runOptions } = options
|
|
1309
1328
|
await observeExecutionProgress(onStage, 'preparing')
|
|
1310
1329
|
const effectivePackages = checkedPackageSelections(packages, routeList, overrides, runOptions.runVerified, targets)
|
|
1311
1330
|
const results = []
|
|
1312
1331
|
const ranIds = []
|
|
1332
|
+
const partial = () => ({ ...aggregateOf([...results]), status: runOptions.signal?.aborted ? 'cancelled' : 'failed', ranIds: [...ranIds] })
|
|
1313
1333
|
if (!runOptions.signal?.aborted) await observeExecutionProgress(onStage, 'executing')
|
|
1314
1334
|
for (const item of effectivePackages) {
|
|
1315
1335
|
const kept = previous.find(result => result.id === item.id)
|
|
@@ -1330,6 +1350,7 @@ async function runPackages({ packages, task, routingBypassed, routes, previous =
|
|
|
1330
1350
|
...identity, answer: '', fallback: null, cancelled: true, notStarted: true, error: '执行已取消,此步骤未开始。' }
|
|
1331
1351
|
results.push(cancelled)
|
|
1332
1352
|
ranIds.push(item.id)
|
|
1353
|
+
await awaitExecutionCheckpoint(onCheckpointResult, cancelled, partial, 'result')
|
|
1333
1354
|
await observeExecutionProgress(onPackage, cancelled)
|
|
1334
1355
|
}
|
|
1335
1356
|
if (runOptions.signal?.aborted) {
|
|
@@ -1349,6 +1370,7 @@ async function runPackages({ packages, task, routingBypassed, routes, previous =
|
|
|
1349
1370
|
}
|
|
1350
1371
|
results.push(blocked)
|
|
1351
1372
|
ranIds.push(item.id)
|
|
1373
|
+
await awaitExecutionCheckpoint(onCheckpointResult, blocked, partial, 'result')
|
|
1352
1374
|
await observeExecutionProgress(onPackage, blocked)
|
|
1353
1375
|
continue
|
|
1354
1376
|
}
|
|
@@ -1364,9 +1386,15 @@ async function runPackages({ packages, task, routingBypassed, routes, previous =
|
|
|
1364
1386
|
continue
|
|
1365
1387
|
}
|
|
1366
1388
|
const startedAt = Date.now()
|
|
1367
|
-
|
|
1389
|
+
const starting = { ...item, ...identity, provider, model, startedAt,
|
|
1368
1390
|
channel: target?.kind === 'tool' ? 'official-cli' : 'harness-llm',
|
|
1369
|
-
...(target?.kind === 'tool' ? { toolId: target.toolId } : {}) }
|
|
1391
|
+
...(target?.kind === 'tool' ? { toolId: target.toolId } : {}) }
|
|
1392
|
+
await observeExecutionProgress(onPackageStart, starting)
|
|
1393
|
+
if (runOptions.signal?.aborted) {
|
|
1394
|
+
await cancelledBeforeStart()
|
|
1395
|
+
continue
|
|
1396
|
+
}
|
|
1397
|
+
await awaitExecutionCheckpoint(onCheckpointStart, starting, partial, 'start')
|
|
1370
1398
|
if (runOptions.signal?.aborted) {
|
|
1371
1399
|
await cancelledBeforeStart()
|
|
1372
1400
|
continue
|
|
@@ -1404,6 +1432,7 @@ async function runPackages({ packages, task, routingBypassed, routes, previous =
|
|
|
1404
1432
|
}
|
|
1405
1433
|
results.push(entry)
|
|
1406
1434
|
ranIds.push(item.id)
|
|
1435
|
+
await awaitExecutionCheckpoint(onCheckpointResult, entry, partial, 'result')
|
|
1407
1436
|
await observeExecutionProgress(onPackage, entry)
|
|
1408
1437
|
}
|
|
1409
1438
|
return { ...aggregateOf(results), ranIds }
|
|
@@ -99,7 +99,7 @@ function rootFromCommand(value) {
|
|
|
99
99
|
const trimmed = value.trim()
|
|
100
100
|
const quoted = /^"([^"]+)"/.exec(trimmed)
|
|
101
101
|
const executable = quoted?.[1] ?? /^(.+?\.(?:exe|ico))(?=,|\s|$)/i.exec(trimmed)?.[1]
|
|
102
|
-
return executable && win32.isAbsolute(executable) ? dirname(executable) : null
|
|
102
|
+
return executable && win32.isAbsolute(executable) ? win32.dirname(executable) : null
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
/** Explicit selection is authoritative, even when the selected bundle is missing. */
|
|
@@ -125,8 +125,8 @@ export function zcodeDiscoveryCandidates({ installDir = '', env = process.env, r
|
|
|
125
125
|
}
|
|
126
126
|
for (const parent of [env.LOCALAPPDATA, env.ProgramFiles, env['ProgramFiles(x86)'], env.ProgramW6432]) {
|
|
127
127
|
if (typeof parent !== 'string' || !win32.isAbsolute(parent)) continue
|
|
128
|
-
add(join(parent, 'Programs', 'ZCode'), 'standard-directory')
|
|
129
|
-
add(join(parent, 'ZCode'), 'standard-directory')
|
|
128
|
+
add(win32.join(parent, 'Programs', 'ZCode'), 'standard-directory')
|
|
129
|
+
add(win32.join(parent, 'ZCode'), 'standard-directory')
|
|
130
130
|
}
|
|
131
131
|
return candidates
|
|
132
132
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.24.0 — 2026-10-24
|
|
4
|
+
|
|
5
|
+
- Reserve remaining execution estimates in shared persistent state before admission. Daily/monthly checks account for recorded API spending plus other active or interrupted reservations, preventing concurrent tasks from independently admitting the same estimated capacity. Unknown estimates or unresolved costs under a finite budget require explicit confirmation.
|
|
6
|
+
- Save mandatory package checkpoints before external calls and after receipts, with actual usage replacing the completed estimate before another paid step. Apply the lifecycle to routed runs, retries/reassignment, official teams, single-tool runs and consultations; optional review and quality-upgrade calls reserve extra capacity first. Checkpoint failures stop later calls and retain evidence.
|
|
7
|
+
- Recheck fresh actual spending and remaining reservations before each later paid call. Earlier costs above estimate or unresolved under a finite budget stop downstream calls; after worker cleanup, a budget stop retains completed receipts and releases unused holds. Subscription-to-API fallback re-estimates the actual route and rejects missing-price or over-budget calls. Save the first receipt and pending extra attempt before a quality upgrade starts.
|
|
8
|
+
- Preserve interrupted reservations and unknown usage when an execution owner is confirmed dead. Protect referenced run records from trimming, block rerun/reassignment while a hold exists, and distinguish actual spending from reserved estimates in the UI. No automatic replay, time-based hold expiry or manual reconciliation/release control is added.
|
|
9
|
+
- Upgrade state schema from v1 to v2 while preserving the ledger. Older plugin versions reject v2 state, so fully stop all Host processes before updating and back up state before a downgrade.
|
|
10
|
+
- Add Windows/Linux Node 24 CI for strict frozen dependency installation, the complete test suite, committed and rebuilt client consistency, offline preview compilation, and npm archive verification against raw Git blobs and the runtime import closure.
|
|
11
|
+
|
|
12
|
+
Validation evidence and pending release checks are tracked in the [0.24.0 acceptance report](docs/releases/0.24.0-validation.md). No new real provider or vendor CLI inference is claimed. Budget reservations are local estimates, not a provider billing cap; interrupted fees must be reconciled before their capacity can safely be reused.
|
|
13
|
+
- Preserve observed receipt timestamps across checkpoints; handle Windows lock contention and declared-platform PATH/ZCode paths, with canonical temporary-path and explicit adapter-capability CI fixtures.
|
|
14
|
+
|
|
15
|
+
|
|
3
16
|
## 0.23.1 — 2026-10-23
|
|
4
17
|
|
|
5
18
|
- Check retry budgets against the target and every unfinished downstream package that will execute. Reassignment uses the selected route estimate; successful downstream packages are excluded and unknown prices remain unknown.
|
package/README.i18n.yaml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
# README translation pairing for this repository.
|
|
2
2
|
# Reviewed together; Git blob hashes identify the exact synchronized texts.
|
|
3
|
-
README.md:
|
|
4
|
-
README.zh.md:
|
|
3
|
+
README.md: 3829f616ecffbfbc4d1793d4e3f2bc4eac6c9fc0
|
|
4
|
+
README.zh.md: 7505f5c1dad20079be2a9bb47a40fd70b5d2bdf4
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Want release notes only? Click **Watch → Custom → Releases** (you do not nee
|
|
|
10
10
|
|
|
11
11
|
A cost-aware model-routing workbench for **DeepSeek Harness Desktop**. Plan locally, compare configured routes, inspect execution permissions, and run dependent work packages through model APIs or supported official vendor CLIs.
|
|
12
12
|
|
|
13
|
-
Current version: **0.
|
|
13
|
+
Current version: **0.24.0** (`@ljwei-stak/dsh-model-router`). Concurrent executions now reserve remaining estimated budget in shared persistent state. Required checkpoints save each package before launch and after its receipt; interrupted executions retain their budget hold and unresolved cost evidence. The workbench separates recorded spending from reserved estimates. Windows/Linux Node 24 CI runs the full test, client build and package-integrity checks. Workbench execution shows live elapsed time and per-package progress, supports cancellation with completed results and reported costs retained, and reconnects to the active job when the panel is reopened. Choose algorithm recommendations or manually assign each decomposed package to an exact model API or official tool, preserving dependencies, refreshed cost previews and retry targets. Routing now supports task-specific quality evidence, joint model/effort selection, historical P90 resource estimates and dependency-aware search. Manual mixed execution is read-only; tools use their configured default model, while the existing editable official-team workflow remains available. Compatibility remains **DeepSeek Harness Desktop 0.2.0-rc.1 / 0.2.0-rc.2 / 0.2.1-rc.2**, including Hermes/Pi installation and terminal support; neither has a verified managed runner yet. Real vendor execution evidence remains tied to **0.20.0**, with no new model experiments in this release. The router and [GAL](https://github.com/Alice-Marx/deepseek-harness-galgame) have been independent plugins since 0.12.0.
|
|
14
14
|
|
|
15
15
|
Official CLI teamwork runs packages sequentially with dependency context and no automatic model-directory API fallback. Editable teams explicitly choose the Harness sandbox or the vendor CLI's normal environment. In the latter, Git worktrees collect edits but do not restrict OS access. CLIs retain their configured model unless explicitly mapped. See [real Windows validation and its limits](docs/releases/0.20.0-validation.md).
|
|
16
16
|
|
|
@@ -24,25 +24,25 @@ Both README versions describe the same interfaces, formulas, defaults and limits
|
|
|
24
24
|
|
|
25
25
|
**Category:** **Models & Reasoning** (模型与推理), the best fit in the [community directory's category list](https://www.alldsh.com/categories/); this is a community taxonomy, not an official DSH classification.
|
|
26
26
|
|
|
27
|
-
**Install (DSH Plugin Hub / web profile):** With the DSH CLI available, install the
|
|
27
|
+
**Install (DSH Plugin Hub / web profile):** With the DSH CLI available, install the versioned npm package with:
|
|
28
28
|
|
|
29
29
|
```sh
|
|
30
|
-
dsh plugin --profile web add @ljwei-stak/dsh-model-router@0.
|
|
30
|
+
dsh plugin --profile web add @ljwei-stak/dsh-model-router@0.24.0
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
**Install in Harness Desktop:** Launch Desktop once to initialize its `desktop` profile, quit Desktop fully, then run:
|
|
34
34
|
|
|
35
35
|
```sh
|
|
36
|
-
dsh plugin --profile desktop add @ljwei-stak/dsh-model-router@0.
|
|
36
|
+
dsh plugin --profile desktop add @ljwei-stak/dsh-model-router@0.24.0
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
You can also paste the package spec into **Harness Desktop → Plugins → Add plugin**. Restart Desktop after installation. A global `npm install -g` by itself does not register a Desktop plugin.
|
|
40
40
|
|
|
41
|
-
**Package and entry point:** [`@ljwei-stak/dsh-model-router@0.
|
|
41
|
+
**Package and entry point:** [`@ljwei-stak/dsh-model-router@0.24.0` on npm](https://www.npmjs.com/package/@ljwei-stak/dsh-model-router). The root [`package.json`](package.json) declares the package and bundle patch; [`.dsh-plugin/index.mjs`](.dsh-plugin/index.mjs) exports the required `apply(ctx)` entry point. License: [MIT](LICENSE).
|
|
42
42
|
|
|
43
43
|
**Configuration:** There is no supported import of a user-authored JSON/YAML configuration file. Configure providers, models, and credentials on Harness's **Models** page; configure routing profiles and preferences in the plugin settings. Persistent router state is stored in `$DSH_HOME/model-router/state.json` (default: `~/.dsh/model-router/state.json`). Provider CLIs retain their own login and configuration. The router does not copy API keys into model profiles or terminal logs.
|
|
44
44
|
|
|
45
|
-
**Screenshots and evidence:** The [workbench screenshot](docs/assets/workbench-task-preview.jpg) uses fixture models, prices, and health data; it is a simulated UI preview, not a live Harness or model run. See the [routing workflow diagram](docs/assets/routing-workflow.svg) for the execution flow. The [real Windows validation report](docs/releases/0.20.0-validation.md) documents specific 0.20.0 executions and their limits; 0.
|
|
45
|
+
**Screenshots and evidence:** The [workbench screenshot](docs/assets/workbench-task-preview.jpg) uses fixture models, prices, and health data; it is a simulated UI preview, not a live Harness or model run. See the [routing workflow diagram](docs/assets/routing-workflow.svg) for the execution flow. The [real Windows validation report](docs/releases/0.20.0-validation.md) documents specific 0.20.0 executions and their limits; 0.24.0 has no verified end-to-end vendor run. The [live progress screenshot](docs/assets/workbench-run-progress.png) is an offline simulation; see the [0.24.0 acceptance report](docs/releases/0.24.0-validation.md) for budget reservations, checkpoints and validation boundaries.
|
|
46
46
|
|
|
47
47
|
**Permissions and risks:** Planning is local and makes no model call. Execution sends the selected task/context to the chosen model API or vendor CLI and may incur charges. The default Harness-restricted environment separates read-only runs from approved `workspace-write` runs. An explicitly selected `cli-native` editable team runs with the current OS user's permissions, outside the Harness process sandbox; a Git worktree collects changes but does not restrict OS access. External providers and CLI services apply their own data handling and billing terms.
|
|
48
48
|
|
|
@@ -63,7 +63,7 @@ You can also paste the package spec into **Harness Desktop → Plugins → Add p
|
|
|
63
63
|
| Editable CLI execution | A sequential CLI team from the workbench, or one supported CLI from a session, using approved isolated Git worktrees and conditional patch integration. |
|
|
64
64
|
| Official tools | Detect, install/update, check launch readiness and inspect login status for twelve registry tools; installation jobs have logs and cancellation. |
|
|
65
65
|
| Interactive terminal | PowerShell/system shell and all twelve registry CLI targets (ZCode TUI on verified Windows desktop installs), including fixed login commands, live output and multiple sessions. |
|
|
66
|
-
| Costs and subscriptions | Daily/monthly budget
|
|
66
|
+
| Costs and subscriptions | Daily/monthly checks include persistent concurrent budget reservations; recorded spending and remaining estimates are separate. Subscription-first routing, quota cooldown and explicit handling of other subscription failures remain available. |
|
|
67
67
|
| History and quality | Per-package results, dependency views, failure details, rerun/reassignment, ratings and optional stronger-model review. |
|
|
68
68
|
| Execution boundaries | Shows what each route can read/write and whether its process uses the Harness sandbox. |
|
|
69
69
|
|
|
@@ -78,16 +78,16 @@ Generating a route recommendation is local: it does not start a vendor CLI or ma
|
|
|
78
78
|
Open **Plugins → Add plugin** and enter:
|
|
79
79
|
|
|
80
80
|
```text
|
|
81
|
-
@ljwei-stak/dsh-model-router@0.
|
|
81
|
+
@ljwei-stak/dsh-model-router@0.24.0
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
Use the official HTTPS npm source `https://registry.npmjs.org/` when a mirror lacks that exact version. Enable the plugin, then fully quit Harness (including its tray process) and restart it. Plugin details should show **0.
|
|
84
|
+
Use the official HTTPS npm source `https://registry.npmjs.org/` when a mirror lacks that exact version. Enable the plugin, then fully quit Harness (including its tray process) and restart it. Plugin details should show **0.24.0** and the sidebar should contain **模型路由** (Model Router). A global `npm install -g` alone does not register a Desktop plugin.
|
|
85
85
|
|
|
86
86
|
You can instead install a local `.tgz` archive or its extracted inner `package` directory through the plugin manager. Both must contain `package.json` and `.dsh-plugin`. See [releases](https://github.com/Alice-Marx/dsh-model-router/releases) for archived builds, or build your own checkout below.
|
|
87
87
|
|
|
88
88
|
### Upgrade from the old package name
|
|
89
89
|
|
|
90
|
-
The old name `@ljwei-stak/model-router-galgame` ended at 0.13.0. Remove that plugin entry while retaining your profile/application data, then add `@ljwei-stak/dsh-model-router@0.
|
|
90
|
+
The old name `@ljwei-stak/model-router-galgame` ended at 0.13.0. Remove that plugin entry while retaining your profile/application data, then add `@ljwei-stak/dsh-model-router@0.24.0`. Do not keep both entries installed: they share the internal plugin id `model-router-galgame` and tool names. The retained id lets existing router settings and history carry over.
|
|
91
91
|
|
|
92
92
|
For the combined 0.11.x package, back up the profile and export the GAL saves you want to preserve before upgrading. Story playback, artwork, music and saves now belong to the independent `@ljwei-stak/dsh-galgame` package. The detailed save limitations are in [MIGRATION.md](docs/archive/MIGRATION.md).
|
|
93
93
|
|
|
@@ -117,10 +117,12 @@ Switching tabs keeps the panels mounted, preserving in-progress installation and
|
|
|
117
117
|
5. In **在工作台执行**, choose **模型路由(只读)** for the existing routed executor, or first select **团队分工** and choose **官方工具协作**. For official teamwork, select **只读检查** (read-only) or **编辑文件** (edit files). Editable teams also choose **Harness 受限环境** (Harness sandbox, the default) or **厂商 CLI 正常环境** (normal vendor environment, outside the Harness sandbox). Enter an existing absolute workspace path, or reuse the last run's path. Click **预览执行计划**, review each package, its permissions and required confirmations, then explicitly confirm execution. The Host rechecks the plan before starting; changed conditions can require confirmation again.
|
|
118
118
|
6. Inspect **执行记录与子任务** for the actual channel, response, failures, cost and ratings. Official teamwork replans using only installed CLIs ready for the selected permission mode. Edits require approval and a clean Git repository; successful worktree changes are conditionally integrated. An unavailable or failed CLI never silently becomes an API call in this mode.
|
|
119
119
|
|
|
120
|
-
After execution starts, the workbench shows elapsed time, the current package and each package's state. **取消执行** requests cancellation of the active call and stops later packages from starting; **正在取消** remains visible until the executor finishes cleanup. Completed results and reported usage remain in history. Cancelling cannot undo charges already incurred or changes already integrated. Closing the panel does not cancel a run; reopening it in the same browser session can reconnect while the Host retains that job. Host restarts clear these in-memory jobs
|
|
120
|
+
After execution starts, the workbench shows elapsed time, the current package and each package's state. **取消执行** requests cancellation of the active call and stops later packages from starting; **正在取消** remains visible until the executor finishes cleanup. Completed results and reported usage remain in history. Cancelling cannot undo charges already incurred or changes already integrated. Closing the panel does not cancel a run; reopening it in the same browser session can reconnect while the Host retains that job. Host restarts clear these in-memory jobs; durably saved package receipts and budget reservations remain. A confirmed dead execution owner is marked `interrupted`, without automatically resuming calls or releasing its hold.
|
|
121
121
|
|
|
122
122
|
Preview, progress and cancellation requests stop waiting after 15 seconds. Progress reads retry against the same job; an unacknowledged cancellation can be retried explicitly. A transport timeout does not establish that the Host task stopped and never automatically resubmits `startRun`. Before retrying a recorded step, budget checks include that step and all unfinished downstream packages that will execute; reassignment uses the selected route estimate and unknown prices remain unknown. The [timeout recovery screenshot](docs/assets/workbench-run-timeout.png) is an offline simulation.
|
|
123
123
|
|
|
124
|
+
History shows active and interrupted budget reservations separately from actual spending. Runs with a reservation cannot be rerun or reassigned. If a Host crash or checkpoint failure leaves a reservation, first inspect the original task, retained worktree and provider bill; this release has no manual reconciliation/release control. Do not delete state to make the capacity appear free.
|
|
125
|
+
|
|
124
126
|
Changing task text, planning mode, profiles, directory or relevant settings invalidates the prior recommendation. Changing execution inputs also discards the pending or completed preview, so execution requires a new preview of the current request. Previewing execution uses current Host state and can differ from a previous local plan.
|
|
125
127
|
|
|
126
128
|
Example task:
|
|
@@ -339,9 +341,9 @@ A worktree separates collected changes; only the selected Harness environment su
|
|
|
339
341
|
|
|
340
342
|
### Failure and retry
|
|
341
343
|
|
|
342
|
-
History stores package status, exit code, bounded scrubbed diagnostics, entry/model evidence and available usage/cost. A later adapter exception does not discard earlier results. `cli-completed` means the runtime completed its process/patch workflow; deliverables still need acceptance checks. `blocked`, `cancelled`, `incomplete` and `integration-pending` distinguish preflight, interruption, package failure and integration problems.
|
|
344
|
+
Required checkpoints persist package launch state before an external call and its available result, usage and cost before the next paid step. A checkpoint failure stops later steps and preserves the reservation for reconciliation. History stores package status, exit code, bounded scrubbed diagnostics, entry/model evidence and available usage/cost. A later adapter exception does not discard earlier results. `cli-completed` means the runtime completed its process/patch workflow; deliverables still need acceptance checks. `blocked`, `cancelled`, `incomplete` and `integration-pending` distinguish preflight, interruption, package failure and integration problems.
|
|
343
345
|
|
|
344
|
-
A retry targets a failed package and unfinished downstream packages, preserving other successful results. Eligible editable `incomplete/cancelled` runs require the recorded source, retained worktree and baseline: the Host validates them, creates a fresh worktree, seeds prior unintegrated edits, and continues. Already integrated or `integration-pending` teams cannot use this step-resume path. Native retry again requires write and unsandboxed consent (`confirmWrite` and `confirmUnsandboxed` in the workbench rerun request); disabling the legacy `confirmUnsandboxedCli` setting cannot bypass it. Previous attempt charges remain in spending totals.
|
|
346
|
+
A retry targets a failed package and unfinished downstream packages, preserving other successful results. Eligible editable `incomplete/cancelled` runs require the recorded source, retained worktree and baseline: the Host validates them, creates a fresh worktree, seeds prior unintegrated edits, and continues. Already integrated or `integration-pending` teams cannot use this step-resume path. Native retry again requires write and unsandboxed consent (`confirmWrite` and `confirmUnsandboxed` in the workbench rerun request); disabling the legacy `confirmUnsandboxedCli` setting cannot bypass it. Previous attempt charges remain in spending totals. This retry path requires no active or interrupted reservation on the original run; a crash checkpoint is evidence to reconcile, not an automatic resume token.
|
|
345
347
|
|
|
346
348
|
Implementation: [official-team-runtime.mjs](.dsh-plugin/shared/official-team-runtime.mjs), [official-tool-executor.mjs](.dsh-plugin/shared/official-tool-executor.mjs), and [run-ledger.mjs](.dsh-plugin/shared/run-ledger.mjs).
|
|
347
349
|
|
|
@@ -349,9 +351,10 @@ Implementation: [official-team-runtime.mjs](.dsh-plugin/shared/official-team-run
|
|
|
349
351
|
|
|
350
352
|
## Costs, subscriptions and quality
|
|
351
353
|
|
|
352
|
-
- **Budgets:** per-run planning target plus daily/monthly checks. Over-budget routing can try the economy preset or pause for confirmation.
|
|
354
|
+
- **Budgets:** per-run planning target plus daily/monthly checks. Admission atomically checks recorded API spending plus other executions' remaining reservations in the same DSH_HOME, then reserves the new execution. Each saved receipt replaces its estimate with actual accounting; remaining holds are released only after the executor settles. Over-budget routing can try the economy preset or pause for confirmation. A finite daily/monthly limit with unknown prices, unresolved actual costs or unknown reservations requires explicit confirmation. Each later paid call rechecks fresh actual spending and remaining reservations. If an earlier charge exceeds its estimate or becomes unknown under a finite budget, later calls pause. A budget stop retains completed receipts and releases unused reservations after worker cleanup; crash or storage failures retain their holds. These local estimates do not establish a hard provider billing cap.
|
|
355
|
+
- **Checkpoints and interruption:** routed executions, retries/reassignment, official teams, single-tool runs and session consultations use the durable lifecycle. Optional reviews and quality upgrades reserve extra capacity before another call. Before a quality upgrade starts, the first receipt and the pending additional attempt are saved, so interruption cannot erase the first charge or imply the second attempt was free. The UI displays actual spending and reservations separately; a reservation is not an invoice. Confirmed dead owners retain interrupted holds and unknown usage evidence until reconciled; elapsed time alone does not free them, and no call is automatically replayed.
|
|
353
356
|
- **Subscription-first:** the default is to prefer a detected CLI account subscription or a configured coding-plan route. API-key environment variables are removed for CLI subscription attempts. `billing` can be `subscription-first`, `api-only` or `subscription-only`; `subscription` can be `cli-login`, `plan-key` or `none`.
|
|
354
|
-
- **Fallback:** detected quota exhaustion/rate limits mark a subscription in cooldown and can retry the routed step on its configured API route, subject to policy and availability. Other attempted subscription failures pause by default (`onSubscriptionFailure: "ask"`): choose API retry, subscription retry or cancel in history. Managed editable/single-tool/team runs do not automatically retry on the API.
|
|
357
|
+
- **Fallback:** detected quota exhaustion/rate limits mark a subscription in cooldown and can retry the routed step on its configured API route, subject to policy and availability. Other attempted subscription failures pause by default (`onSubscriptionFailure: "ask"`): choose API retry, subscription retry or cancel in history. A subscription-to-API route change must pass a fresh estimate and reservation check for that actual API route; a missing price or exceeded budget stops the call. Managed editable/single-tool/team runs do not automatically retry on the API.
|
|
355
358
|
- **Accounting:** API costs count toward budgets. Subscription runs display a reference cost separately. A valid CLI-reported amount, including zero, takes precedence. Token-based CLI cost requires complete usage and an actual reported model matching a configured model or its explicit CLI mapping; unknown or mismatched identity keeps cost unknown. The recommendation's price alone cannot establish actual CLI cost. Provider bills remain authoritative. Version 0.15.0 retains spending from evicted detailed runs and replaced retry results, so trimming history or retrying a step does not erase earlier charges. Costs already discarded by older versions cannot be reconstructed.
|
|
356
359
|
- **Quality and preference:** optional `off`/`sample`/`always` stronger-model review can add paid calls; it is not treated as human feedback. Explicit ratings adjust separate subjective utility for the exact route and task type, using time decay and low-sample shrinkage (default limit ±0.04, configurable up to ±0.1). They do not change objective quality scores or their hard floors; learning can be disabled, ratings withdrawn, or its starting point reset.
|
|
357
360
|
|
|
@@ -449,13 +452,13 @@ Implementation: [router.mjs](.dsh-plugin/shared/router.mjs), [assignment-solver.
|
|
|
449
452
|
|
|
450
453
|
## Data and privacy
|
|
451
454
|
|
|
452
|
-
Router profiles/preferences are held in the Harness plugin settings. Runtime state is stored in `<DSH_HOME>/model-router/state.json` (default `~/.dsh/model-router/state.json`): health/onboarding, subscription cooldown, ratings, up to 200 recent runs, 50 terminal metadata records and opt-in public data snapshots. Applied rates and data/feedback policy versions are frozen in run records. Preferences are local to that shared DSH_HOME, not authenticated per-user accounts; public data requests do not upload tasks or feedback.
|
|
455
|
+
Router profiles/preferences are held in the Harness plugin settings. Runtime state is stored in `<DSH_HOME>/model-router/state.json` (default `~/.dsh/model-router/state.json`): health/onboarding, subscription cooldown, ratings, up to 200 recent runs, up to 100 execution reservations, 50 terminal metadata records and opt-in public data snapshots. Runs referenced by a reservation are protected from history trimming. Applied rates and data/feedback policy versions are frozen in run records. Preferences are local to that shared DSH_HOME, not authenticated per-user accounts; public data requests do not upload tasks or feedback.
|
|
453
456
|
|
|
454
457
|
Version 0.15.0 also retains bounded spending aggregates for up to 90 populated calendar dates and 24 months. These contain amounts/counts, not task or response content.
|
|
455
458
|
|
|
456
459
|
Run history includes task text, output excerpts, route/workspace, failures and costs. Stored task text is capped at 20,000 characters and each answer at 4,000; reruns can therefore depend on truncated stored context. The plugin does not store API keys in model profiles or terminal transcripts. Task execution still sends the selected task/context to the chosen provider or CLI.
|
|
457
460
|
|
|
458
|
-
State writes use a lock and atomic replacement. Unparseable state is preserved as a `state.json.corrupt-<timestamp>` backup and surfaced as a notice. Back up state/profile data before migrations and avoid sharing unredacted histories or logs.
|
|
461
|
+
State writes use a lock and atomic replacement. State schema v2 preserves execution ownership, reservations and checkpoints, and upgrades readable v1 state without discarding its ledger. Older plugin versions reject v2 state; fully stop every Host process before upgrading and back up state before any downgrade. Unparseable state is preserved as a `state.json.corrupt-<timestamp>` backup and surfaced as a notice. Back up state/profile data before migrations and avoid sharing unredacted histories or logs.
|
|
459
462
|
|
|
460
463
|
<a id="development"></a>
|
|
461
464
|
|
|
@@ -493,6 +496,7 @@ Open [the local preview](http://127.0.0.1:4173). It uses mock models, tools and
|
|
|
493
496
|
| `shared/official-tool-executor.mjs`, `official-team-runtime.mjs` | Trusted entry, permissions/process capture, dependency execution and patch integration. |
|
|
494
497
|
| `shared/task-executors.mjs`, `subscription-billing.mjs` | Routed CLI/API execution, subscription policy and fallback. |
|
|
495
498
|
| `shared/run-ledger.mjs`, `router-state.mjs` | Identity/usage/cost records, retained spending and locked atomic persistence. |
|
|
499
|
+
| `shared/budget-reservations.mjs`, `execution-lifecycle.mjs` | Cross-process budget admission, remaining reservations, mandatory checkpoints and interrupted-owner evidence. |
|
|
496
500
|
| Other `.dsh-plugin/shared/` modules | Terminal contracts, tool health, public snapshots and bounded feedback. |
|
|
497
501
|
| `.dsh-plugin/client.js` | Generated Desktop client bundle; rebuild after client changes. |
|
|
498
502
|
| `scripts/` and `tests/` | Build/package/verification helpers and regression tests. |
|
|
@@ -503,6 +507,8 @@ Open [the local preview](http://127.0.0.1:4173). It uses mock models, tools and
|
|
|
503
507
|
|
|
504
508
|
`check:client` rebuilds in memory and compares the generated output with the committed bundle; `prepack` refuses a stale bundle. pnpm 10 has no `pnpm peers check` command: use the strict install above. Unavailable/incompatible host SDK packages may require the installed Harness runtime for local integration testing; [setup-harness-dev.mjs](scripts/setup-harness-dev.mjs) links missing SDK packages from an explicitly supplied Host `node_modules`, and [start-harness-preview.mjs](scripts/start-harness-preview.mjs) starts a separate local web Host profile. These helpers do not replace dependency verification or Desktop acceptance checks.
|
|
505
509
|
|
|
510
|
+
GitHub Actions runs a Node 24 matrix on Windows and Linux for the frozen strict dependency install, full test suite, committed-client consistency, actual client build and offline preview compilation. It packs the candidate and checks every file against raw Git blobs plus the runtime import closure. These checks use local fixtures and do not exercise real provider billing. After committing a local candidate, reproduce package verification with `node scripts/check-package.mjs` following `npm run pack:local`.
|
|
511
|
+
|
|
506
512
|
Legacy compatibility/research files and dated reports are preserved for reference; their presence does not make every older integration an active feature of the current packaged plugin. Releases and synchronization follow [AGENTS.md](AGENTS.md); use versioned packages or verified release tags to reproduce a release.
|
|
507
513
|
|
|
508
514
|
### Verification layers and known limits
|
|
@@ -531,6 +537,8 @@ When maintaining these docs, update both languages in the same change: matching
|
|
|
531
537
|
| Login/entitlement still fails | Check the vendor account, CLI login, network and actual model access; installation alone is insufficient. |
|
|
532
538
|
| Frontend says Host is older | Fully quit Harness, including the tray process, then restart. |
|
|
533
539
|
| Preview differs from old advice | Directory, login, quota or budget state changed; review the new preview. |
|
|
540
|
+
| Budget remains reserved after interruption | Check the original task, retained worktree and provider bill. The hold is not automatically cleared or replayed, and this release has no manual reconciliation/release control. |
|
|
541
|
+
| Older plugin cannot read state | Schema v2 contains protected reservations. Restore a compatible version; do not erase the ledger to bypass its checks. |
|
|
534
542
|
| Terminal TUI does not render | Check whether the card reports PTY or pipe fallback. |
|
|
535
543
|
| Logged in, but no executable team route | Check `readyModes`, platform, selected install and permission mode; terminal login alone does not establish managed capability. |
|
|
536
544
|
| Skills/MCP missing in Claude read-only | Restricted mode disables them; editable/native choices have different permissions and require the corresponding confirmation. |
|
package/README.zh.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
面向 **DeepSeek Harness Desktop** 的成本感知模型路由工作台。在本地规划任务、比较已配置路线、检查执行权限,并通过模型 API 或支持的厂商官方 CLI 执行有依赖关系的工作包。
|
|
12
12
|
|
|
13
|
-
当前版本:**0.
|
|
13
|
+
当前版本:**0.24.0**(`@ljwei-stak/dsh-model-router`)。并发执行现在会在共享持久状态中预占剩余估算预算;每个工作包调用前、收到结果后都必须保存检查点。中断任务保留预算预占和待核对费用证据,工作台分别显示已记录支出和预占估计。新增 Windows/Linux Node 24 CI,执行全量测试、客户端构建和包完整性检查。工作台支持实时耗时、逐工作包进度和取消,保留已完成结果与已报告费用;关闭重开面板可接管原任务。支持“按算法推荐分配 / 手动调整分配”:拆分后的工作包可逐个指定模型 API 或官方工具,保留依赖、重新预览费用,并保存重跑目标。同时接入任务相关质量证据、模型与推理档位联合选择、历史资源 P90 估计与依赖感知搜索。手动混合执行当前只读;官方工具使用自身默认模型,原有官方团队编辑流程保留。继续兼容 **DeepSeek Harness Desktop 0.2.0-rc.1 / 0.2.0-rc.2 / 0.2.1-rc.2**,沿用 Hermes/Pi 安装与终端支持;两者仍无经过验证的托管执行器。真实厂商执行证据仍见 **0.20.0** 报告,本版未新增模型实测。路由器与 [GAL](https://github.com/Alice-Marx/deepseek-harness-galgame) 自 0.12.0 起已拆分为独立插件。
|
|
14
14
|
|
|
15
15
|
官方 CLI 协作按依赖顺序逐包执行、传递依赖上下文,不会自动回退到模型目录 API。可编辑团队需明确选择 Harness 沙箱或厂商 CLI 正常环境。后者通过 Git worktree 收集修改,但不限制操作系统访问。未显式设置模型映射时,各 CLI 沿用自身配置的模型。参见[真实 Windows 验证及其局限](docs/releases/0.20.0-validation.md)。
|
|
16
16
|
|
|
@@ -27,22 +27,22 @@
|
|
|
27
27
|
**安装(DSH Plugin Hub / web profile):** 确保 DSH CLI 可用,然后安装已发布的 npm 包:
|
|
28
28
|
|
|
29
29
|
```sh
|
|
30
|
-
dsh plugin --profile web add @ljwei-stak/dsh-model-router@0.
|
|
30
|
+
dsh plugin --profile web add @ljwei-stak/dsh-model-router@0.24.0
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
**安装到 Harness Desktop:** 首次先启动一次 Desktop 初始化 `desktop` 配置,再彻底退出 Desktop,运行:
|
|
34
34
|
|
|
35
35
|
```sh
|
|
36
|
-
dsh plugin --profile desktop add @ljwei-stak/dsh-model-router@0.
|
|
36
|
+
dsh plugin --profile desktop add @ljwei-stak/dsh-model-router@0.24.0
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
也可以在 **Harness Desktop → 插件 → 添加插件** 中粘贴包名。安装后重启 Desktop。单独运行全局 `npm install -g` 不会注册 Desktop 插件。
|
|
40
40
|
|
|
41
|
-
**发布包与入口:** [npm 上的 `@ljwei-stak/dsh-model-router@0.
|
|
41
|
+
**发布包与入口:** [npm 上的 `@ljwei-stak/dsh-model-router@0.24.0`](https://www.npmjs.com/package/@ljwei-stak/dsh-model-router)。根目录[`package.json`](package.json)声明包名和 bundle patch;[`.dsh-plugin/index.mjs`](.dsh-plugin/index.mjs)导出所需的 `apply(ctx)` 入口。[许可证:MIT](LICENSE)。
|
|
42
42
|
|
|
43
43
|
**配置文件与配置入口:** 当前不支持导入用户编写的 JSON/YAML 配置文件。Provider、模型和凭据在 Harness **模型**页面配置;路由档案与偏好在插件设置中配置。路由器持久状态存于 `$DSH_HOME/model-router/state.json`(默认:`~/.dsh/model-router/state.json`)。Provider CLI 沿用各自的登录和配置;路由器不会把 API 密钥复制进模型档案或终端日志。
|
|
44
44
|
|
|
45
|
-
**截图与证据:** [工作台截图](docs/assets/workbench-task-preview.jpg)使用固定的模型、价格和健康状态数据,是模拟 UI 预览,不是实时 Harness 或模型运行。[路由流程图](docs/assets/routing-workflow.svg)展示执行路径。[真实 Windows 验证报告](docs/releases/0.20.0-validation.md)记录了 0.20.0 的具体执行及局限;0.
|
|
45
|
+
**截图与证据:** [工作台截图](docs/assets/workbench-task-preview.jpg)使用固定的模型、价格和健康状态数据,是模拟 UI 预览,不是实时 Harness 或模型运行。[路由流程图](docs/assets/routing-workflow.svg)展示执行路径。[真实 Windows 验证报告](docs/releases/0.20.0-validation.md)记录了 0.20.0 的具体执行及局限;0.24.0 尚无经过验证的端到端厂商运行。[实时进度截图](docs/assets/workbench-run-progress.png)是离线模拟;预算预占、检查点与验证边界见[0.24.0 验收报告](docs/releases/0.24.0-validation.md)。
|
|
46
46
|
|
|
47
47
|
**权限与风险:** 任务规划在本地完成,不调用模型。实际执行会把选定任务和上下文发送到所选模型 API 或厂商 CLI,并可能产生费用。默认使用 Harness 受限环境;只读运行不修改工作区,`workspace-write` 需要用户明确批准。明确选择 `cli-native` 的可编辑团队会在 Harness 进程沙箱之外,以当前操作系统用户权限运行;Git worktree 只收集修改,不限制操作系统访问。外部 Provider 和 CLI 服务各自适用其数据处理及计费规则。
|
|
48
48
|
|
|
@@ -63,7 +63,7 @@ dsh plugin --profile desktop add @ljwei-stak/dsh-model-router@0.23.1
|
|
|
63
63
|
| 可编辑 CLI 执行 | 从工作台执行顺序 CLI 团队,或在会话中调用单个受支持 CLI;使用获批的隔离 Git worktree,并有条件地合入补丁。 |
|
|
64
64
|
| 官方工具 | 对注册表中的十二种工具检测、安装/更新、检查启动就绪和登录状态;安装任务提供日志和取消功能。 |
|
|
65
65
|
| 交互终端 | PowerShell/系统 shell 与十二种注册表 CLI 目标(经过验证的 Windows 桌面安装支持 ZCode TUI);包含固定登录命令、实时输出和多会话。 |
|
|
66
|
-
| 费用与订阅 |
|
|
66
|
+
| 费用与订阅 | 日/月检查计入持久并发预占,已记录支出与剩余估计分别显示;保留订阅优先、额度冷却,以及其他订阅失败的显式处理。 |
|
|
67
67
|
| 历史与质量 | 逐包结果、依赖视图、失败详情、重跑/改派、评分与可选的更强模型复核。 |
|
|
68
68
|
| 执行边界 | 显示每条路线可读写的范围,以及进程是否使用 Harness 沙箱。 |
|
|
69
69
|
|
|
@@ -78,16 +78,16 @@ dsh plugin --profile desktop add @ljwei-stak/dsh-model-router@0.23.1
|
|
|
78
78
|
打开 **插件 → 添加插件**,输入:
|
|
79
79
|
|
|
80
80
|
```text
|
|
81
|
-
@ljwei-stak/dsh-model-router@0.
|
|
81
|
+
@ljwei-stak/dsh-model-router@0.24.0
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
镜像缺少该精确版本时,使用官方 HTTPS npm 源 `https://registry.npmjs.org/`。启用插件,然后完全退出 Harness(包括托盘进程)并重启。插件详情应显示 **0.
|
|
84
|
+
镜像缺少该精确版本时,使用官方 HTTPS npm 源 `https://registry.npmjs.org/`。启用插件,然后完全退出 Harness(包括托盘进程)并重启。插件详情应显示 **0.24.0**,侧栏应出现 **模型路由**。仅执行全局 `npm install -g` 不会把插件注册到 Desktop。
|
|
85
85
|
|
|
86
86
|
也可以通过插件管理器安装本地 `.tgz` 压缩包,或解压后的内部 `package` 目录。两者都必须包含 `package.json` 和 `.dsh-plugin`。历史构建见 [Releases](https://github.com/Alice-Marx/dsh-model-router/releases),也可按下文从源码构建。
|
|
87
87
|
|
|
88
88
|
### 从旧包名升级
|
|
89
89
|
|
|
90
|
-
旧名称 `@ljwei-stak/model-router-galgame` 停留在 0.13.0。保留配置档/应用数据,移除旧插件条目,再添加 `@ljwei-stak/dsh-model-router@0.
|
|
90
|
+
旧名称 `@ljwei-stak/model-router-galgame` 停留在 0.13.0。保留配置档/应用数据,移除旧插件条目,再添加 `@ljwei-stak/dsh-model-router@0.24.0`。不要同时保留两条插件:它们共用内部插件 id `model-router-galgame` 和工具名。保留该 id 能让现有路由设置与历史记录继续使用。
|
|
91
91
|
|
|
92
92
|
从合包 0.11.x 升级前,先备份配置档,并导出需要保留的 GAL 存档。剧情播放、立绘、音乐与存档现属于独立的 `@ljwei-stak/dsh-galgame`。详细存档限制见 [MIGRATION.md](docs/archive/MIGRATION.md)。
|
|
93
93
|
|
|
@@ -117,10 +117,12 @@ dsh plugin --profile desktop add @ljwei-stak/dsh-model-router@0.23.1
|
|
|
117
117
|
5. 在 **在工作台执行** 中,选择 **模型路由(只读)** 使用现有路由执行器;或先选择 **团队分工**,再选择 **官方工具协作**。官方协作可选择 **只读检查** 或 **编辑文件**。可编辑团队还需选择 **Harness 受限环境**(默认沙箱)或 **厂商 CLI 正常环境**(在 Harness 沙箱外运行)。填入已存在的工作区绝对路径,或沿用上次运行路径。点击 **预览执行计划**,查看各包、权限与所需确认,然后显式确认执行。Host 启动前会重新检查计划;条件变化可能要求重新确认。
|
|
118
118
|
6. 在 **执行记录与子任务** 查看实际通道、回答、失败、费用与评分。官方协作仅使用已安装、且在所选权限模式下就绪的 CLI 重新规划。编辑需要批准和干净的 Git 仓库;成功的 worktree 修改有条件地合入。该模式下,不可用或失败的 CLI 不会静默变成 API 调用。
|
|
119
119
|
|
|
120
|
-
执行开始后,工作台显示已耗时、当前工作包与每包状态。**取消执行**会请求停止当前调用,并阻止后续工作包启动;执行器完成收尾前持续显示**正在取消**。已完成结果和已报告用量仍保留在历史中。取消不能撤销已经产生的费用或已经整合的改动。关闭面板不会取消执行;同一浏览器会话重新打开后,可在 Host 仍保留该任务时重新连接。Host
|
|
120
|
+
执行开始后,工作台显示已耗时、当前工作包与每包状态。**取消执行**会请求停止当前调用,并阻止后续工作包启动;执行器完成收尾前持续显示**正在取消**。已完成结果和已报告用量仍保留在历史中。取消不能撤销已经产生的费用或已经整合的改动。关闭面板不会取消执行;同一浏览器会话重新打开后,可在 Host 仍保留该任务时重新连接。Host 重启会清除内存任务,已落盘的工作包结果与预算预占仍保留。确认执行进程已经退出后标记为 `interrupted`,不会自动续跑调用或释放预占。
|
|
121
121
|
|
|
122
122
|
预览、进度和取消请求最长等待 15 秒。进度读取超时后继续查询同一任务;取消未确认时可手动重试。网络等待超时不代表 Host 任务已停止,也不会自动重发 `startRun`。重跑历史步骤前,预算覆盖该步及实际会执行的全部未完成下游;改派使用所选路线估价,未知价格仍保持未知。[超时恢复截图](docs/assets/workbench-run-timeout.png)为离线模拟。
|
|
123
123
|
|
|
124
|
+
历史将活动/中断的预算预占与实际支出分别显示;有预占的运行不能重跑或改派。Host 崩溃或检查点保存失败后,请先核对原任务、保留的 worktree 和供应商账单;本版没有手工核对并释放预占的操作入口。不要通过删除状态把占用当成可用额度。
|
|
125
|
+
|
|
124
126
|
修改任务文本、规划模式、路线配置、目录或相关设置,会使旧建议失效。修改执行输入也会丢弃待确认或已完成的预览,必须对当前请求重新预览。执行预览使用 Host 当前状态,因此可能与先前本地计划不同。
|
|
125
127
|
|
|
126
128
|
任务示例:
|
|
@@ -339,9 +341,9 @@ worktree 用于分离和收集修改;只有所选 Harness 环境提供操作
|
|
|
339
341
|
|
|
340
342
|
### 失败与重试
|
|
341
343
|
|
|
342
|
-
|
|
344
|
+
必须保存的检查点在外部调用前记录启动状态,在下一次付费步骤前保存已有结果、用量和费用。检查点保存失败会停止后续步骤,保留预占以供核对。历史保存包状态、退出码、经过脱敏且有长度限制的诊断、入口/模型证据,以及可用的用量/费用。后续适配器异常不会丢弃先前结果。`cli-completed` 表示运行时完成了进程/补丁流程;交付物仍需通过验收。`blocked`、`cancelled`、`incomplete` 和 `integration-pending` 分别区分预检阻止、中断、包失败与合入问题。
|
|
343
345
|
|
|
344
|
-
重试针对失败包和未完成的后续依赖,保留其他成功结果。符合条件的可编辑 `incomplete/cancelled` 运行要求记录的源目录、保留的 worktree 与基线:Host 验证后创建新 worktree,播种先前尚未合入的修改,再继续执行。已经合入或 `integration-pending` 的团队不能使用这一步骤恢复路径。正常环境重试仍需写入和沙箱外执行的同意(工作台重跑请求中的 `confirmWrite` 与 `confirmUnsandboxed`);关闭旧设置 `confirmUnsandboxedCli`
|
|
346
|
+
重试针对失败包和未完成的后续依赖,保留其他成功结果。符合条件的可编辑 `incomplete/cancelled` 运行要求记录的源目录、保留的 worktree 与基线:Host 验证后创建新 worktree,播种先前尚未合入的修改,再继续执行。已经合入或 `integration-pending` 的团队不能使用这一步骤恢复路径。正常环境重试仍需写入和沙箱外执行的同意(工作台重跑请求中的 `confirmWrite` 与 `confirmUnsandboxed`);关闭旧设置 `confirmUnsandboxedCli` 也不能绕过。先前尝试的费用保留在支出总额中。原运行必须没有活动或中断预占,才能走这条重试路径;崩溃检查点是待核对证据,不是自动续跑令牌。
|
|
345
347
|
|
|
346
348
|
实现:[official-team-runtime.mjs](.dsh-plugin/shared/official-team-runtime.mjs)、[official-tool-executor.mjs](.dsh-plugin/shared/official-tool-executor.mjs) 与 [run-ledger.mjs](.dsh-plugin/shared/run-ledger.mjs)。
|
|
347
349
|
|
|
@@ -349,9 +351,10 @@ worktree 用于分离和收集修改;只有所选 Harness 环境提供操作
|
|
|
349
351
|
|
|
350
352
|
## 成本、订阅与质量
|
|
351
353
|
|
|
352
|
-
- **预算:**
|
|
354
|
+
- **预算:** 单次规划目标加日/月检查。在同一个 DSH_HOME 中,启动时原子检查已记录的 API 支出和其他任务的剩余预占,再为本次执行预占预算。保存每步结果后,以实际核算替换相应估计;执行器完成收尾后才释放剩余预占。超预算路由可以尝试省钱预设,或暂停等待确认。有限日/月预算遇到未知价格、待核对实际费用或未知预占时,需要显式确认。每次后续付费调用前,都会按最新实际支出和剩余预占重新检查;前一步实际费用超过估计,或在有限预算下变成未知时,会暂停后续调用。预算检查停止运行后,已完成收据保留,未用预占在执行器收尾后释放;崩溃或存储失败则继续保留预占。这些本地估计不能保证厂商硬性计费上限。
|
|
355
|
+
- **检查点与中断:** 路由执行、重跑/改派、官方团队、单工具运行和会话咨询共用持久执行生命周期。可选复核和质量升级在追加调用前预占额度。质量升级启动前,先保存首个收据与待核对的追加尝试,避免中断时抹掉首次费用或把第二次尝试视为免费。界面区分实际支出与预占,预占不是账单。确认进程退出后仍保留中断预占及未知用量证据以供核对;仅凭经过时间不会释放,也不会自动重放调用。
|
|
353
356
|
- **订阅优先:** 默认优先检测到的 CLI 账号订阅或已配置 coding-plan 路线。CLI 订阅尝试会移除 API-key 环境变量。`billing` 可为 `subscription-first`、`api-only` 或 `subscription-only`;`subscription` 可为 `cli-login`、`plan-key` 或 `none`。
|
|
354
|
-
- **回退:** 检测到额度耗尽/限流时,将订阅标记为冷却,并可按策略与可用性在已配置 API 路线上重试该路由步骤。其他已尝试的订阅失败默认暂停(`onSubscriptionFailure: "ask"`):可在历史中选择 API
|
|
357
|
+
- **回退:** 检测到额度耗尽/限流时,将订阅标记为冷却,并可按策略与可用性在已配置 API 路线上重试该路由步骤。其他已尝试的订阅失败默认暂停(`onSubscriptionFailure: "ask"`):可在历史中选择 API 重试、订阅重试或取消。订阅切换到 API 时,必须按实际 API 路线重新估算并检查预占;缺少价格或超预算时不会启动调用。托管可编辑/单工具/团队运行不会自动在 API 上重试。
|
|
355
358
|
- **核算:** API 费用计入预算。订阅运行单独显示参考费用。有效的 CLI 报告金额(包括零)优先采用。按 token 计算 CLI 费用,需要完整用量,以及报告的实际模型匹配某个已配置模型或其显式 CLI 映射;身份未知或不匹配时费用保持未知。仅有推荐路线价格不能确定实际 CLI 费用。厂商账单为准。0.15.0 起保留已淘汰详细运行和被重试替换结果的支出,因此裁剪历史或重试步骤不会抹掉先前费用。更早版本已丢弃的费用无法重建。
|
|
356
359
|
- **质量与偏好:** 可选 `off`/`sample`/`always` 更强模型复核可能增加付费调用,且不作为人工反馈。显式评分以时间衰减和小样本收缩,调整精确路线、任务类型对应的独立主观效用(默认上限 ±0.04,可配置至 ±0.1)。评分不改变客观质量分或其硬下限;可禁用学习、撤回评分或重置学习起点。
|
|
357
360
|
|
|
@@ -449,13 +452,13 @@ $`L`$ 为延迟效用:$`t`$ 是匹配历史的 P90 耗时,单位为毫秒;
|
|
|
449
452
|
|
|
450
453
|
## 数据与隐私
|
|
451
454
|
|
|
452
|
-
路由配置/偏好保存在 Harness 插件设置中。运行时状态写入 `<DSH_HOME>/model-router/state.json`(默认 `~/.dsh/model-router/state.json`):健康/入门状态、订阅冷却、评分、最多 200
|
|
455
|
+
路由配置/偏好保存在 Harness 插件设置中。运行时状态写入 `<DSH_HOME>/model-router/state.json`(默认 `~/.dsh/model-router/state.json`):健康/入门状态、订阅冷却、评分、最多 200 条近期运行、最多 100 条执行预占、50 条终端元数据,以及主动启用的公共数据快照。预占引用的运行不会被历史裁剪删除。运行记录会冻结采用的单价、数据/反馈策略版本。偏好属于共享的本地 DSH_HOME,不是经过认证的独立用户账号;公共数据请求不会上传任务或反馈。
|
|
453
456
|
|
|
454
457
|
0.15.0 起还保留有界支出汇总,最多覆盖 90 个有数据的日历日期与 24 个月。只包含金额/计数,不含任务或回答内容。
|
|
455
458
|
|
|
456
459
|
运行历史包含任务文本、输出节选、路线/工作区、失败与费用。保存的任务最多 20,000 字符,每条回答最多 4,000 字符,因此重跑可能依赖被截断的已存上下文。插件不把 API key 存进模型配置,也不保存终端转录。任务执行仍会把所选任务/上下文发送给相应供应商或 CLI。
|
|
457
460
|
|
|
458
|
-
|
|
461
|
+
状态写入使用锁和原子替换。状态结构 v2 保存执行所有权、预占和检查点,并升级可读的 v1 状态而不丢弃账本。旧插件会拒绝读取 v2 状态;升级前请完全停止所有 Host 进程,降级前先备份状态。无法解析的状态保留为 `state.json.corrupt-<timestamp>` 备份,并显示提示。迁移前请备份状态/配置档数据;不要分享未经脱敏的历史或日志。
|
|
459
462
|
|
|
460
463
|
<a id="development"></a>
|
|
461
464
|
|
|
@@ -493,6 +496,7 @@ npm run preview:ui
|
|
|
493
496
|
| `shared/official-tool-executor.mjs`、`official-team-runtime.mjs` | 可信入口、权限/进程捕获、依赖执行与补丁合入。 |
|
|
494
497
|
| `shared/task-executors.mjs`、`subscription-billing.mjs` | 路由 CLI/API 执行、订阅策略与回退。 |
|
|
495
498
|
| `shared/run-ledger.mjs`、`router-state.mjs` | 身份/用量/费用记录、支出保留与加锁原子持久化。 |
|
|
499
|
+
| `shared/budget-reservations.mjs`、`execution-lifecycle.mjs` | 跨进程预算准入、剩余预占、必须保存的检查点和中断进程证据。 |
|
|
496
500
|
| 其他 `.dsh-plugin/shared/` 模块 | 终端契约、工具健康、公共快照与有界反馈。 |
|
|
497
501
|
| `.dsh-plugin/client.js` | 生成的 Desktop 客户端 bundle;修改客户端后需重建。 |
|
|
498
502
|
| `scripts/` 与 `tests/` | 构建/打包/验证辅助脚本与回归测试。 |
|
|
@@ -503,6 +507,8 @@ npm run preview:ui
|
|
|
503
507
|
|
|
504
508
|
`check:client` 在内存中重建并比较已提交 bundle;`prepack` 会拒绝过期 bundle。pnpm 10 没有 `pnpm peers check` 命令:请使用上述严格安装。Host SDK 包不可用/不兼容时,本地集成测试可能需要已安装的 Harness 运行时;[setup-harness-dev.mjs](scripts/setup-harness-dev.mjs) 从显式提供的 Host `node_modules` 链接缺失 SDK 包,[start-harness-preview.mjs](scripts/start-harness-preview.mjs) 启动独立的本地 Web Host 配置档。这些辅助脚本不能代替依赖验证或 Desktop 验收。
|
|
505
509
|
|
|
510
|
+
GitHub Actions 通过 Windows/Linux Node 24 矩阵执行冻结锁文件严格依赖安装、全量测试、已提交客户端一致性、实际客户端构建和离线预览编译。打包后逐文件对比原始 Git blob,并检查运行时 import 依赖是否完整。这些检查使用本地预置数据,不验证真实供应商计费。提交本地候选后,可先运行 `npm run pack:local`,再运行 `node scripts/check-package.mjs` 复现包验证。
|
|
511
|
+
|
|
506
512
|
旧兼容/研究文件和带日期报告保留作参考;它们的存在不代表当前发行插件仍启用所有旧集成。发布与同步遵循 [AGENTS.md](AGENTS.md);重现某次发布请使用带版本号的包或已验证的发布 tag。
|
|
507
513
|
|
|
508
514
|
### 验证层次与已知局限
|
|
@@ -531,6 +537,8 @@ npm run preview:ui
|
|
|
531
537
|
| 登录/模型权限仍失败 | 检查厂商账号、CLI 登录、网络和实际模型访问;仅安装成功不够。 |
|
|
532
538
|
| 前端提示 Host 版本较旧 | 完全退出 Harness(包括托盘进程)后重启。 |
|
|
533
539
|
| 预览与旧建议不同 | 目录、登录、额度或预算状态已变化;请查看新预览。 |
|
|
540
|
+
| 中断后预算仍被预占 | 核对原任务、保留的 worktree 和供应商账单。预占不会自动释放或续跑,本版没有手工核对并释放的操作入口。 |
|
|
541
|
+
| 旧插件无法读取状态 | v2 状态包含受保护的预占;恢复兼容版本,不要删除账本绕过检查。 |
|
|
534
542
|
| 终端 TUI 不渲染 | 检查卡片报告的是 PTY 还是管道回退模式。 |
|
|
535
543
|
| 已登录但团队没有可执行路线 | 检查 `readyModes`、平台、所选安装和权限模式;仅终端已登录不能证明具备托管执行能力。 |
|
|
536
544
|
| Claude 只读中没有 skills/MCP | 受限模式会禁用它们;可编辑/正常环境选项权限不同,需要相应确认。 |
|
|
Binary file
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 0.24.0 release acceptance
|
|
2
|
+
|
|
3
|
+
Date: 2026-10-24. Package: `@ljwei-stak/dsh-model-router@0.24.0`.
|
|
4
|
+
|
|
5
|
+
Source acceptance: passed. Local tests and the actual Windows/Linux matrix below verify the implementation. The final tagged commit, archive digests and post-publication anonymous download checks are recorded separately in the dated release/archive evidence, so this document does not need to embed the checksum of its own containing archive.
|
|
6
|
+
|
|
7
|
+
## Problems and resulting behavior
|
|
8
|
+
|
|
9
|
+
- Concurrent executions could each pass a budget check against the same historical balance. Admission now checks recorded API spending plus other executions' remaining reservations under the shared state lock, then persists the new run and reservation atomically. Known estimated capacity is reserved before the call; missing prices and unresolved fees remain unknown and require explicit confirmation under a finite daily/monthly limit.
|
|
10
|
+
- A Host interruption could lose completed-step records because the run was saved only at the end. Required checkpoints now save launch state before an external call and available receipts before the next paid step. A receipt replaces its portion of the remaining estimate with actual accounting. Routed runs, retry/reassignment, official teams, single-tool executions and session consultations use the lifecycle. Optional stronger-model reviews and quality upgrades reserve extra capacity before their additional calls.
|
|
11
|
+
- Before every later paid call, admission rechecks fresh actual spending and remaining reservations. If earlier charges exceed estimates or unresolved fees prevent a finite budget from being verified, downstream calls stop. Subscription-to-API fallback must re-estimate its actual route; unknown pricing or exceeded budget prevents the call. Quality upgrades first save the initial receipt and pending additional attempt.
|
|
12
|
+
- A budget stop preserves completed receipts and releases unused reservations only after the worker settles. It differs from a crash or storage failure, which retains holds for reconciliation.
|
|
13
|
+
- Checkpoint persistence failure stops later calls. Confirmed dead owners become interrupted while retaining reservations and unresolved usage evidence. Live or uncertain owners are not expired by elapsed time. Protected run records remain in the bounded ledger, and active/interrupted reservations block rerun and reassignment.
|
|
14
|
+
- Receipt timestamps remain attached to observed package receipts across later checkpoints and final saves, including day/month rollovers. Windows lock-file sharing races use the existing bounded contention wait; PATH and ZCode discovery use the declared platform path syntax.
|
|
15
|
+
- Actual spending and reserved estimates are separate in the workbench. State schema v2 retains ownership, remaining reservations and checkpoints and accepts readable v1 state without dropping its ledger. Older plugin versions reject v2 state instead of silently rewriting away protected reservations.
|
|
16
|
+
- A Windows/Linux Node 24 workflow runs strict frozen dependency installation, the complete test suite, committed-client consistency, actual client build/check, offline preview compilation and archive verification. Package verification compares every file byte to the selected Git revision and checks the local runtime import closure.
|
|
17
|
+
|
|
18
|
+
## Validation record
|
|
19
|
+
|
|
20
|
+
| Check | Observed evidence |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| Focused reservation/state regressions | `npm test` includes reservation/state tests for cross-process admission, receipt settlement, protected retention, dead-owner recovery, unknown costs, ownership checks and v1 migration; the final local suite has 1,126 passes, 0 failures and 3 environment skips. |
|
|
23
|
+
| Host and executor integration | Full suite coverage includes required checkpoint failures, stopping downstream calls, retry accounting once, official team/tool/consultation/review/upgrade entry points, fallback repricing, fresh dispatch checks and receipt timestamps. Host path tests: 11/11; dispatch rechecks: 9/9; receipt-time regressions: 6/6. |
|
|
24
|
+
| UI inspection | The actual client was inspected in the offline browser fixture `budget-reservations`: recorded spend, remaining reservations, interrupted-state guidance and disabled reruns; 0 browser console errors. [Screenshot](../assets/workbench-budget-reservations.png). All amounts and executions are simulated. |
|
|
25
|
+
| Full local suite | `npm test`: 1,129 tests, 1,126 passed, 0 failed, 3 skipped. Full logs are retained in the release archive. |
|
|
26
|
+
| Dependency/client/docs checks | `pnpm install --frozen-lockfile --strict-peer-dependencies` passed; actual client build and `check:client` passed (988,427 bytes); README pairing/hashes and offline preview compilation passed. Formula content is unchanged. |
|
|
27
|
+
| Windows/Linux CI | [Implementation matrix run](https://github.com/Alice-Marx/dsh-model-router/actions/runs/40003924460) on `4795ade7adbd2a3075e3d9fde29f70372b542c03`: Node 24 / ubuntu-latest **success**; Node 24 / windows-latest **success**. Both ran the complete suite, strict installation, actual build/check, preview compilation and package verification. The final documentation commit runs the same matrix again before publication. |
|
|
28
|
+
| Package integrity | Local candidate archive: 75 files match raw Git blobs, including all 40 local runtime modules. Final `v0.24.0` commit and archive digests are recorded in the Release assets, which avoid embedding an archive checksum in a document inside that same archive. |
|
|
29
|
+
| Public release | After tag/upload, the publication audit anonymously downloads the npm archive, GitHub Release page and every attached asset and compares bytes and registry integrity. The dated public-npm/public-github verification JSON files are retained with the release archive. Neither version metadata nor a pushed tag alone establishes complete publication. |
|
|
30
|
+
|
|
31
|
+
## Boundaries and upgrade
|
|
32
|
+
|
|
33
|
+
Reservations represent remaining local estimates, not actual billed charges or a hard provider cap. Final charges can exceed estimates, and provider bills remain authoritative. Unknown or incomplete usage is not assigned zero. Subscription reference costs remain separate from recorded API spending. Calendar accounting retains its existing package-level settlement granularity; quality-cascade attempts are not split into separate daily/monthly invoices.
|
|
34
|
+
|
|
35
|
+
A normal completed, cancelled or budget-stopped executor releases its remaining reservation only after its cleanup settles; completed receipts remain chargeable. A Host crash or checkpoint failure does not prove the provider stopped or establish its final charge. The reservation and any unresolved fee evidence remain available for reconciliation. This release has no manual reconciliation/release control, no automatic call replay and no arbitrary timeout that makes an interrupted reservation free. Inspect the original task, retained worktree and provider bill before considering recovery; do not erase state to bypass accounting.
|
|
36
|
+
|
|
37
|
+
Live job/progress handles remain in Host memory and do not survive a restart. Persistent package checkpoints and reservations survive successful state writes; they do not restore an active worker or provide one-click continuation. Confirmed dead-owner detection is conservative; an owner whose liveness is uncertain remains reserved.
|
|
38
|
+
|
|
39
|
+
Required checkpoints are part of the managed execution paths. Arbitrary imports or external provider calls outside these paths are not brought under the router's budget accounting by this change. Deliverable correctness, real vendor access, account eligibility and settled charges are not established by offline fixtures or CI.
|
|
40
|
+
|
|
41
|
+
No new real paid-provider or vendor CLI inference or installed-DSH end-to-end acceptance is claimed for this release. Prior execution evidence remains dated in the [0.20.0 report](0.20.0-validation.md). Fully quit Harness, including tray/Host processes, update the plugin, then restart. Back up state/profile data before migration or downgrade; older plugin versions cannot read schema v2 state.
|