@ljwei-stak/dsh-model-router 0.14.0 → 0.16.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 +790 -228
- package/.dsh-plugin/index.mjs +124 -29
- package/.dsh-plugin/shared/adaptive-feedback.mjs +192 -0
- package/.dsh-plugin/shared/assignment-solver.mjs +86 -0
- package/.dsh-plugin/shared/dynamic-data-view.mjs +65 -0
- package/.dsh-plugin/shared/dynamic-data.mjs +294 -0
- package/.dsh-plugin/shared/harness-plan.mjs +5 -2
- package/.dsh-plugin/shared/livebench.mjs +57 -20
- package/.dsh-plugin/shared/model-profiles.mjs +7 -1
- package/.dsh-plugin/shared/official-tools-remote.mjs +3 -1
- package/.dsh-plugin/shared/router-state.mjs +18 -7
- package/.dsh-plugin/shared/router.mjs +115 -152
- package/.dsh-plugin/shared/run-ledger.mjs +93 -24
- package/CHANGELOG.md +29 -0
- package/INSTALLATION_GUIDE.zh.md +41 -27
- package/README.md +158 -363
- package/README.zh.md +157 -353
- package/docs/ROUTING_ADAPTIVE_LEARNING.zh.md +151 -0
- package/docs/ROUTING_DERIVATION_EXPERIMENTS.zh.md +684 -0
- package/docs/ROUTING_LIVEBENCH_DATA_SEARCH.zh.md +74 -0
- package/docs/ROUTING_LIVEBENCH_VALIDATION.zh.md +154 -0
- package/docs/ROUTING_RESEARCH.zh.md +59 -0
- package/docs/ROUTING_SELFTEST_STEPS.zh.md +192 -0
- package/docs/WORKBENCH_USER_GUIDE.zh.md +192 -0
- package/docs/assets/workbench-task-preview.jpg +0 -0
- package/package.json +21 -2
|
@@ -63,34 +63,94 @@ const pad = value => String(value).padStart(2, '0')
|
|
|
63
63
|
export const dayKey = at => { const date = new Date(at); return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}` }
|
|
64
64
|
export const monthKey = at => { const date = new Date(at); return `${date.getFullYear()}-${pad(date.getMonth() + 1)}` }
|
|
65
65
|
|
|
66
|
-
/**
|
|
67
|
-
export
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
/** Detailed history can be evicted without losing the current budget totals. */
|
|
67
|
+
export const MAX_SPENDING_DAYS = 90
|
|
68
|
+
export const MAX_SPENDING_MONTHS = 24
|
|
69
|
+
const emptyPeriodSpending = () => ({ costUsd: 0, unknown: 0, subscriptionUsd: 0, subscriptionRuns: 0 })
|
|
70
|
+
|
|
71
|
+
function periodSpending(value) {
|
|
72
|
+
const amount = field => finite(value?.[field]) && value[field] >= 0 ? value[field] : 0
|
|
73
|
+
return { costUsd: amount('costUsd'), unknown: Math.floor(amount('unknown')),
|
|
74
|
+
subscriptionUsd: amount('subscriptionUsd'), subscriptionRuns: Math.floor(amount('subscriptionRuns')) }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Bounded calendar aggregates contain amounts and counts, never tasks or answers. */
|
|
78
|
+
export function sanitizeArchivedSpending(value) {
|
|
79
|
+
const periods = (entries, pattern, limit) => Object.fromEntries(Object.entries(entries && typeof entries === 'object' && !Array.isArray(entries) ? entries : {})
|
|
80
|
+
.filter(([key, entry]) => pattern.test(key) && entry && typeof entry === 'object' && !Array.isArray(entry))
|
|
81
|
+
.sort(([left], [right]) => left.localeCompare(right)).slice(-limit)
|
|
82
|
+
.map(([key, entry]) => [key, periodSpending(entry)]))
|
|
83
|
+
return {
|
|
84
|
+
days: periods(value?.days, /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/, MAX_SPENDING_DAYS),
|
|
85
|
+
months: periods(value?.months, /^\d{4}-(?:0[1-9]|1[0-2])$/, MAX_SPENDING_MONTHS),
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function addArchivedSpending(target, source) {
|
|
90
|
+
const archive = sanitizeArchivedSpending(source)
|
|
91
|
+
for (const period of ['days', 'months']) {
|
|
92
|
+
for (const [key, amount] of Object.entries(archive[period])) {
|
|
93
|
+
const total = target[period][key] ??= emptyPeriodSpending()
|
|
94
|
+
for (const field of Object.keys(amount)) total[field] += amount[field]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function* spendingEntries(runs) {
|
|
71
100
|
for (const run of Array.isArray(runs) ? runs : []) {
|
|
72
|
-
for (const item of [...(run.packages
|
|
101
|
+
for (const item of [...(Array.isArray(run?.packages) ? run.packages : []), ...(Array.isArray(run?.reviews) ? run.reviews : [])]) {
|
|
102
|
+
if (!item || typeof item !== 'object') continue
|
|
73
103
|
const when = item.finishedAt ?? run.createdAt
|
|
74
|
-
if (!finite(when)) continue
|
|
75
|
-
const
|
|
76
|
-
if (!inMonth) continue
|
|
77
|
-
const inDay = dayKey(when) === today
|
|
104
|
+
if (!finite(when) || !finite(new Date(when).getTime())) continue
|
|
105
|
+
const amount = emptyPeriodSpending()
|
|
78
106
|
if (item.billing === 'subscription') {
|
|
79
|
-
//
|
|
107
|
+
// A subscription login is reference cost only, never budget spend.
|
|
80
108
|
if (item.ran !== true) continue
|
|
81
|
-
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
109
|
+
amount.subscriptionRuns = 1
|
|
110
|
+
if (finite(item.referenceCostUsd) && item.referenceCostUsd >= 0) amount.subscriptionUsd = item.referenceCostUsd
|
|
111
|
+
} else if (finite(item.costUsd) && item.costUsd >= 0) amount.costUsd = item.costUsd
|
|
112
|
+
else if (item.ran === true) amount.unknown = 1
|
|
113
|
+
else continue
|
|
114
|
+
yield { when, amount }
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Fold only evicted records into the archive; retained records are counted live. */
|
|
120
|
+
export function archiveSpending(runs, archivedSpending) {
|
|
121
|
+
const archive = sanitizeArchivedSpending(archivedSpending)
|
|
122
|
+
for (const run of Array.isArray(runs) ? runs : []) addArchivedSpending(archive, run?.priorAttemptSpending)
|
|
123
|
+
for (const { when, amount } of spendingEntries(runs)) {
|
|
124
|
+
for (const [periods, key] of [[archive.days, dayKey(when)], [archive.months, monthKey(when)]]) {
|
|
125
|
+
const total = periods[key] ??= emptyPeriodSpending()
|
|
126
|
+
for (const field of Object.keys(amount)) total[field] += amount[field]
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return sanitizeArchivedSpending(archive)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Recorded spending, including evicted history, for the local day and month. */
|
|
133
|
+
export function spending(runs, at = Date.now(), archivedSpending = null) {
|
|
134
|
+
const today = dayKey(at)
|
|
135
|
+
const month = monthKey(at)
|
|
136
|
+
const archive = sanitizeArchivedSpending(archivedSpending)
|
|
137
|
+
for (const run of Array.isArray(runs) ? runs : []) addArchivedSpending(archive, run?.priorAttemptSpending)
|
|
138
|
+
const daily = periodSpending(archive.days[today])
|
|
139
|
+
const monthly = periodSpending(archive.months[month])
|
|
140
|
+
const total = { today: daily.costUsd, month: monthly.costUsd, unknownToday: daily.unknown, unknownMonth: monthly.unknown,
|
|
141
|
+
subscriptionToday: daily.subscriptionUsd, subscriptionMonth: monthly.subscriptionUsd,
|
|
142
|
+
subscriptionRunsToday: daily.subscriptionRuns, subscriptionRunsMonth: monthly.subscriptionRuns }
|
|
143
|
+
for (const { when, amount } of spendingEntries(runs)) {
|
|
144
|
+
if (monthKey(when) !== month) continue
|
|
145
|
+
total.month += amount.costUsd
|
|
146
|
+
total.unknownMonth += amount.unknown
|
|
147
|
+
total.subscriptionMonth += amount.subscriptionUsd
|
|
148
|
+
total.subscriptionRunsMonth += amount.subscriptionRuns
|
|
149
|
+
if (dayKey(when) === today) {
|
|
150
|
+
total.today += amount.costUsd
|
|
151
|
+
total.unknownToday += amount.unknown
|
|
152
|
+
total.subscriptionToday += amount.subscriptionUsd
|
|
153
|
+
total.subscriptionRunsToday += amount.subscriptionRuns
|
|
94
154
|
}
|
|
95
155
|
}
|
|
96
156
|
return total
|
|
@@ -196,6 +256,9 @@ function storedPackage(planned, result, pricing, finishedAt, billingFor = billin
|
|
|
196
256
|
answer: String(result?.answer ?? '').slice(0, MAX_STORED_ANSWER),
|
|
197
257
|
answerTruncated: String(result?.answer ?? '').length > MAX_STORED_ANSWER,
|
|
198
258
|
usage: result?.usage ?? null,
|
|
259
|
+
// Freeze the rates used for this result. Future price updates must not
|
|
260
|
+
// silently rewrite historical spend calculated from usage.
|
|
261
|
+
pricingSnapshot: pricing ? { ...pricing } : null,
|
|
199
262
|
...cost,
|
|
200
263
|
finishedAt,
|
|
201
264
|
review: planned.review ?? null,
|
|
@@ -231,6 +294,8 @@ export function buildRunRecord({ id, createdAt, task, plan, execution, preset =
|
|
|
231
294
|
mode: plan?.mode ?? 'single',
|
|
232
295
|
preset,
|
|
233
296
|
decision: {
|
|
297
|
+
dataVersions: plan?.optimization?.dataVersions ?? null,
|
|
298
|
+
personalization: plan?.optimization?.personalization ?? null,
|
|
234
299
|
selected: plan?.selected ? { provider: plan.selected.provider, model: plan.selected.model } : null,
|
|
235
300
|
reason: String(plan?.reason ?? ''),
|
|
236
301
|
complexity: plan?.complexity ? { band: plan.complexity.band, value: finite(plan.complexity.value) ? Number(plan.complexity.value.toFixed(3)) : null } : null,
|
|
@@ -248,6 +313,10 @@ export function buildRunRecord({ id, createdAt, task, plan, execution, preset =
|
|
|
248
313
|
export function mergeRerun(run, execution, { rerunIds = [], pricingFor = () => null, billingFor = billingOf, finishedAt = Date.now() } = {}) {
|
|
249
314
|
const results = Array.isArray(execution?.packages) ? execution.packages : []
|
|
250
315
|
const retried = new Set(rerunIds)
|
|
316
|
+
// Retrying replaces the visible result, but earlier attempts still incurred
|
|
317
|
+
// charges (or unknown usage). Keep their calendar totals before replacement.
|
|
318
|
+
const replaced = run.packages.filter(stored => retried.has(stored.id) && results.some(item => item.id === stored.id))
|
|
319
|
+
run.priorAttemptSpending = archiveSpending([{ createdAt: run.createdAt, packages: replaced }], run.priorAttemptSpending)
|
|
251
320
|
run.packages = run.packages.map(stored => {
|
|
252
321
|
const result = results.find(item => item.id === stored.id)
|
|
253
322
|
if (!result || !retried.has(stored.id)) return stored
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.16.0 — 2026-10-05
|
|
4
|
+
|
|
5
|
+
Stable release under the npm `latest` tag. Fully quit Harness, including the tray process, and restart after upgrading so both the Host and client load the new version. Public data refresh is opt-in; enabling it does not authorize paid model exploration.
|
|
6
|
+
|
|
7
|
+
- Add opt-in versioned public LiveBench/curated pricing snapshots with TTL, failure backoff, last-good fallback and atomic cross-process promotion; explicit manual prices win. Freeze each run's applied rates and data/policy versions, and disable cleared sources immediately without deleting recoverable snapshots.
|
|
8
|
+
- Replace production review/rating quality bias with task-specific, time-decayed, shrinkage-regularized subjective utility. Preserve objective proxy quality floors; expose learning controls/reset and the local DSH_HOME / last-200-runs scope. Agent rating tools require approval; Desktop ratings bind to the displayed result timestamp.
|
|
9
|
+
- Require explicit score scale for dynamic benchmark mirrors and exact benchmark model identity; expose optional benchmarkModel mapping without claiming verified execution effort. Add controlled synthetic adaptation and Host/Client integration tests; no paid exploration, real-user result collection, universal official pricing scraper or actual quality-cost benefit claim.
|
|
10
|
+
|
|
11
|
+
- Use estimated per-package token cost against a fixed reference pricing scale, not the most expensive configured route; an irrelevant expensive model no longer rescales existing preferences. Remove the model-name-specific synthesis bonus.
|
|
12
|
+
- Protect least-cost known-price candidates before truncating pools. Disable local Pareto pruning for dependency-coupled tasks, where route identity changes later handoff penalties.
|
|
13
|
+
- Solve retained candidate spaces of at most 4,096 combinations exactly; larger spaces use bounded beam search with a protected affordable prefix. Expose exact/approximate search, candidate truncation and the surrogate-objective scope instead of claiming global answer-quality optimality.
|
|
14
|
+
- Correct repeated quality-bias application for unknown models. Explain that benchmark/manual scores and quality floors are not calibrated correctness probabilities.
|
|
15
|
+
- Preserve explicit/derived benchmark provenance, exclude image-ineligible savings baselines, and use unrounded totals for budget gates. Report quality filtering, Pareto pruning, and candidate truncation separately.
|
|
16
|
+
- Add independent exhaustive-oracle tests and a label-matrix offline evaluation tool with validation-selected single-model baselines, random routing, hindsight Oracle, actual recorded costs and rare-expert recall. No paid model calls or real quality-improvement claim.
|
|
17
|
+
- Audit the official LiveBench 2026-06-25 aggregate score/cost release with pinned source hashes, complete-coverage checks and descriptive static Pareto profiles. Add continuous-score, domain-stratified whole-group paired bootstrap tooling and document the missing latest per-question cost/quality matrix. Aggregates are not replayed as question outcomes; no real routing-benefit claim or production routing change.
|
|
18
|
+
|
|
19
|
+
Validation: 558 tests, with 555 passed, 3 existing platform-condition skips and no failures. Strict frozen-lockfile installation, generated-client check and actual-component mock-preview compilation passed. Nine controlled synthetic adaptation checks passed; these are mechanism tests, not real model quality-cost gains. Real paid model calls, user-result collection, execution-effort validation and Harness Desktop end-to-end acceptance were not part of this verification. Research artifacts are in the complete GitHub source checkout, not the npm runtime package; historical experiments retain their original development-version identifiers.
|
|
20
|
+
|
|
21
|
+
## 0.15.0 — 2026-10-03
|
|
22
|
+
|
|
23
|
+
- Reorganize the workbench into task/execution, model configuration, official tools, and budget/security pages. Keep panels mounted so drafts, installation polling, and terminal sessions survive navigation; add keyboard tab navigation and panel-width responsive layouts.
|
|
24
|
+
- Show local routing results immediately after task planning, with expandable work-package details and human-readable dependency names.
|
|
25
|
+
- Discard pending execution previews when their inputs change, and confirm only the request that was actually previewed. Invalidate local plans when model profiles or routing settings change externally.
|
|
26
|
+
- Preserve API spending, unknown-call counts, and subscription reference costs when detailed history is pruned or a step is retried. Retain 200 detailed runs plus bounded calendar aggregates; previously discarded costs cannot be recovered.
|
|
27
|
+
- Add `npm run preview:ui`: a localhost-only preview of the actual client with in-memory fixtures, five normal/error/empty/onboarding/delayed scenarios, and no real model calls or terminal processes.
|
|
28
|
+
- Rewrite the English/Chinese README, installation instructions, and workbench guide around the current capabilities, source setup, execution boundaries, and local-data behavior. Include the guide and a clearly labeled simulated UI screenshot in the package.
|
|
29
|
+
|
|
30
|
+
Validation: 220 tests passed, with 3 existing Windows-specific skips; the generated client and packaged file bytes were checked. Browser preview checks cover navigation, narrow panels, validation, draft persistence, and stale-preview rejection. Real vendor accounts, paid CLI calls, and Harness Desktop end-to-end execution were not exercised in this release's validation.
|
|
31
|
+
|
|
3
32
|
## 0.14.0 — 2026-10-03
|
|
4
33
|
|
|
5
34
|
Stable release under the npm `latest` tag. It folds in the 0.14.0-beta.1 – beta.4 prereleases (published under `next` only). **After updating, quit Harness completely (including the tray icon) and start it again**: Harness serves the new workbench UI at once, but the running Host keeps the plugin code it already imported, so the new Host methods are missing until a full restart. The workbench now warns when the Host and client versions differ.
|
package/INSTALLATION_GUIDE.zh.md
CHANGED
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
模型路由从 **0.12.0** 起独立发布;GAL 是新的 **0.1.0** 插件。两者均声明支持官方 **DeepSeek Harness Desktop 0.2.0-rc.1 / 0.2.0-rc.2**,可分别安装和更新。
|
|
4
4
|
|
|
5
|
+
当前路由正式版为 **0.16.0**。在既有四页工作台与费用累计保留的基础上,本版加入可选动态公开数据和分任务类型的持续反馈学习。公开数据默认关闭;主观偏好调整不改变公共能力评分或质量门槛。源码开发可使用独立模拟 UI 预览;安装时选择下方精确版本。
|
|
6
|
+
|
|
5
7
|
[路由 README](README.zh.md) · [迁移说明](MIGRATION.md) · [独立 GAL README](https://github.com/Alice-Marx/deepseek-harness-galgame#readme)
|
|
6
8
|
|
|
7
9
|
## 1. 选择需要的插件
|
|
8
10
|
|
|
9
11
|
| 需求 | 添加插件输入框 | 安装后的入口 |
|
|
10
12
|
| --- | --- | --- |
|
|
11
|
-
| 分析复杂度、按质量和费用选模型、调用官方工具 | `@ljwei-stak/dsh-model-router@0.
|
|
13
|
+
| 分析复杂度、按质量和费用选模型、调用官方工具 | `@ljwei-stak/dsh-model-router@0.16.0` | 模型路由 |
|
|
12
14
|
| 剧情、立绘、音乐、存档、自由对话 | `@ljwei-stak/dsh-galgame@0.1.0` | Gal 模块 |
|
|
13
15
|
| 两者都要 | 分别安装上面两个包 | 模型路由 + Gal 模块 |
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
旧 npm 包名 `@ljwei-stak/model-router-galgame` 最后版本为 0.13.0,之后不再更新;新安装使用 `@ljwei-stak/dsh-model-router`。自 0.12.0 起路由不含 GAL 入口或剧情美术。GAL 不依赖路由,路由也不依赖 GAL。
|
|
16
18
|
|
|
17
19
|
路由正式版发布在 npm **`latest`** 标签,预发布版在 `next`。推荐填写精确版本。不要省略版本号:`latest` 或镜像状态可能选择与当前宿主不兼容的旧包。
|
|
18
20
|
|
|
@@ -22,7 +24,7 @@
|
|
|
22
24
|
2. 在“包名、GitHub 仓库地址或本地目录路径”输入框填一个完整包名,例如:
|
|
23
25
|
|
|
24
26
|
```text
|
|
25
|
-
@ljwei-stak/dsh-model-router@0.
|
|
27
|
+
@ljwei-stak/dsh-model-router@0.16.0
|
|
26
28
|
```
|
|
27
29
|
|
|
28
30
|
只想安装 GAL 时填写:
|
|
@@ -37,8 +39,8 @@
|
|
|
37
39
|
https://registry.npmjs.org/
|
|
38
40
|
```
|
|
39
41
|
|
|
40
|
-
4.
|
|
41
|
-
5. 检查插件详情与侧边栏:路由应为 **0.
|
|
42
|
+
4. 核对预览的包名、版本和宿主兼容信息,安装并启用。完全退出 Harness(包括托盘进程)再启动,确保 Host 加载新代码。
|
|
43
|
+
5. 检查插件详情与侧边栏:路由应为 **0.16.0 / 模型路由**;GAL 应为 **0.1.0 / Gal 模块**。仅装路由时没有 GAL 入口是预期行为。
|
|
42
44
|
|
|
43
45
|
普通用户无需 `npm install -g`,该命令不会把插件注册到当前 Harness profile。
|
|
44
46
|
|
|
@@ -46,13 +48,13 @@
|
|
|
46
48
|
|
|
47
49
|
进入对应 Release 下载 `.tgz`:
|
|
48
50
|
|
|
49
|
-
- [模型路由 Releases](https://github.com/Alice-Marx/dsh-model-router/releases)(也可运行 `npm pack @ljwei-stak/dsh-model-router@0.
|
|
51
|
+
- [模型路由 Releases](https://github.com/Alice-Marx/dsh-model-router/releases)(也可运行 `npm pack @ljwei-stak/dsh-model-router@0.16.0` 获取同一安装包)
|
|
50
52
|
- [独立 GAL v0.1.0](https://github.com/Alice-Marx/deepseek-harness-galgame/releases/tag/v0.1.0)
|
|
51
53
|
|
|
52
54
|
在“添加插件”填写下载文件的**绝对路径**,例如:
|
|
53
55
|
|
|
54
56
|
```text
|
|
55
|
-
D:\Plugins\ljwei-stak-dsh-model-router-0.
|
|
57
|
+
D:\Plugins\ljwei-stak-dsh-model-router-0.16.0.tgz
|
|
56
58
|
```
|
|
57
59
|
|
|
58
60
|
```text
|
|
@@ -62,7 +64,7 @@ D:\Plugins\ljwei-stak-dsh-galgame-0.1.0.tgz
|
|
|
62
64
|
如附有 `.sha256` 文件,用 PowerShell 计算并比较摘要:
|
|
63
65
|
|
|
64
66
|
```powershell
|
|
65
|
-
Get-FileHash -Algorithm SHA256 -LiteralPath 'D:\Plugins\ljwei-stak-dsh-model-router-0.
|
|
67
|
+
Get-FileHash -Algorithm SHA256 -LiteralPath 'D:\Plugins\ljwei-stak-dsh-model-router-0.16.0.tgz'
|
|
66
68
|
Get-FileHash -Algorithm SHA256 -LiteralPath 'D:\Plugins\ljwei-stak-dsh-galgame-0.1.0.tgz'
|
|
67
69
|
```
|
|
68
70
|
|
|
@@ -72,7 +74,7 @@ Get-FileHash -Algorithm SHA256 -LiteralPath 'D:\Plugins\ljwei-stak-dsh-galgame-0
|
|
|
72
74
|
|
|
73
75
|
1. 在旧合并插件的 GAL 播放器导出需要保留的剧情进度,并备份整个 Harness profile。每份 JSON 仅保存**当前剧情状态**,不含所有手动槽、设置、已读记录或本地音乐;重要槽位可依次读档再导出。
|
|
74
76
|
2. 在**同一个 profile**安装独立 `@ljwei-stak/dsh-galgame@0.1.0`。
|
|
75
|
-
3. 0.13.0 起包名改为 `@ljwei-stak/dsh-model-router`(旧包名最后版本为 0.13.0,内容相同,之后不再更新):在插件管理器卸载原 `@ljwei-stak/model-router-galgame`(保留 profile 与应用数据),再添加 `@ljwei-stak/dsh-model-router@0.
|
|
77
|
+
3. 0.13.0 起包名改为 `@ljwei-stak/dsh-model-router`(旧包名最后版本为 0.13.0,内容相同,之后不再更新):在插件管理器卸载原 `@ljwei-stak/model-router-galgame`(保留 profile 与应用数据),再添加 `@ljwei-stak/dsh-model-router@0.16.0`。不要两个同时安装(条目 id 与工具名相同);条目 id 未变,路由设置与执行记录会保留。完成两项更新后再玩剧情,避免同时操作旧合并入口和新入口。
|
|
76
78
|
4. 现在路由与 GAL 各有一个入口。独立 GAL 沿用旧存档 localStorage 键,核对当前进度和三槽;更换 profile 或进度未恢复时,先切换到匹配剧目,再导入 JSON 备份。
|
|
77
79
|
5. 后续分别更新需要的插件;只用路由可以不启用或不安装 GAL。保留 profile 与应用数据,卸载插件时不要清理故事数据。
|
|
78
80
|
|
|
@@ -80,18 +82,26 @@ GAL 核心只包含**《回声之城·正篇》**与**《旧城迁移篇:未
|
|
|
80
82
|
|
|
81
83
|
## 5. 模型路由第一次使用
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
工作台自 0.15.0 起分成**任务与执行、模型配置、官方工具、预算与安全**四页;0.16.0 沿用该布局。切换页面保留安装任务、终端会话和未完成的输入。
|
|
86
|
+
|
|
87
|
+
1. 在 Harness 官方**模型**页配置供应商、模型与凭据。插件读取准确的 `provider/model` 目录,模型档案不保存 API Key。
|
|
88
|
+
2. 在**模型配置**刷新目录,逐条填写自报质量评分、核对过的输入/输出单价(USD / 百万 token)和擅长方向;缺价留空。可选 `cliModel` 必须是该厂商 CLI 已验证接受的名字。可选 LiveBench 名称须准确对应版本与推理档位;它是用户确认的映射,不自动证明实际执行档位。
|
|
89
|
+
3. 在**任务与执行 → 任务规划**输入目标、步骤和验收标准。单任务推荐一条路线,团队模式为足够复杂的任务拆依赖工作包,指定模型跳过其他路线比较。预算是本地估价目标,`0` 表示不设本次估价约束,不限制厂商账单。
|
|
90
|
+
4. 点**生成路由建议**。建议直接显示在规划之后;规划计算在本机完成,不启动模型或 CLI。若已明确启用动态公开数据,读取账本/规划时可按检查间隔请求公开源,但不会把任务或反馈发送给这些源。
|
|
91
|
+
5. 需要真实只读执行时,使用**在工作台执行**,填写存在的工作区绝对路径(留空沿用上次运行)。先**预览执行计划**、核对路线/费用和全部确认原因,再明确确认执行。宿主启动前会重查;确认后才发生真实调用,结果写入执行记录。
|
|
92
|
+
6. 在**官方工具**检测、安装/更新工具并核对入口与登录。ZCode 打开原厂安装窗口后仍需用户选择目录并完成安装,再体检。可信入口就绪不等于账号和模型有权限。
|
|
93
|
+
7. 在**预算与安全**查看每日/月度预算、订阅失败策略及可读/写边界;**持续反馈与本地偏好**可设置学习启停、半衰期、收缩强度和调整上限,**动态公共数据**需自行启用。官方工具终端不经过 Harness 沙箱,继承用户登录环境,需单独确认启动。
|
|
94
|
+
8. 需要 CLI 修改文件时进入官方会话、选择工作区,明确请求 `model_router_tool_run` 或 `model_router_team_execute` 的 `workspace-write` 模式。可编辑托管执行要求干净 Git 仓库、宿主审批和进程沙箱。`model_router_execute` 用于只读路由执行,`model_router_consult` 用于模型 API 意见。
|
|
95
|
+
|
|
96
|
+
完整教程见[工作台使用指南](docs/WORKBENCH_USER_GUIDE.zh.md);路线算法、订阅与数据保存说明见[README](README.zh.md)。
|
|
89
97
|
|
|
90
|
-
|
|
98
|
+
在成功结果上点 👍 / 👎,再次点已选评价可撤回。评价按准确路线和任务类型形成时间衰减、向零收缩的**主观偏好效用**,默认最大幅度 ±0.04,可配置到不超过 ±0.1;不抬高客观能力分或公共质量门槛。模型复核不视作人工评价,模型侧评分工具需要用户审批;本版不发起付费探索。
|
|
91
99
|
|
|
92
|
-
|
|
100
|
+
学习范围是同一个本地 **DSH_HOME** 共享的最近 **200 次运行**,不是多账号隔离或无限长期记忆。“从现在重新学习”只让旧结果不再参与学习,不删除执行记录和费用累计。动态价格只读取用户指定的公开、严格结构化、按官方文档策展的 USD/百万 token 固定费率快照;不是自动抓取所有厂商价目表,复杂阶梯/时段计费不能强行折成该格式。人工单价优先;公开数据默认关闭,详情见[动态数据与持续反馈说明](docs/ROUTING_ADAPTIVE_LEARNING.zh.md)。
|
|
93
101
|
|
|
94
|
-
|
|
102
|
+
注册表包含 Kimi、Claude、Codex、MiniMax、MiMo、Grok、Gemini 和 ZCode。Claude、Codex、MiMo、Grok 支持单工具/团队只读或可编辑执行;Kimi、MiniMax、ZCode 仅支持获批的可编辑托管执行。Gemini 有路由无界面适配器,不进入单工具/团队托管执行器。详见[官方工具与托管模式](README.zh.md#官方工具与托管模式)。CLI 模型名可能不同于 Harness 目录;多数 CLI 不提供可核验的实际模型 ID,要看厂商记录与账单。
|
|
103
|
+
|
|
104
|
+
安装使用固定官方 npm 包的 `@latest` 或 ZCode 签名安装器。希望 npm 工具安装在非 C 盘时,先按自己的空间规划配置全局前缀;Grok 数据目录与登录应使用一致的 `GROK_HOME`。MiniMax Windows 原生依赖失败时,从固定官方 HTTPS 来源下载最新版安装脚本,仅检查大小和基本内容结构后原样执行,**没有锁定该安装脚本的哈希**。安装后的 MiniMax CLI 代码另按已安装版本的官方 npm tarball 摘要核验。MiMo/Grok 同样使用官方 npm 内容证明;适用的 Claude/Codex/ZCode Windows 入口验证发布者签名,ZCode 内置脚本还有每个签名构建的首次信任摘要检查。具体规则见[执行器](.dsh-plugin/shared/official-tool-executor.mjs)和[npm 内容核验](.dsh-plugin/shared/npm-attestation.mjs)。
|
|
95
105
|
|
|
96
106
|
## 6. GAL 第一次使用
|
|
97
107
|
|
|
@@ -104,31 +114,35 @@ Claude、Codex、MiMo、Grok 支持只读或可编辑;Kimi、MiniMax、ZCode
|
|
|
104
114
|
| 检查 | 预期 |
|
|
105
115
|
| --- | --- |
|
|
106
116
|
| 宿主版本 | 0.2.0-rc.1 或 0.2.0-rc.2;包括 `rc` 后缀。 |
|
|
107
|
-
| 路由独立安装 | 0.
|
|
117
|
+
| 路由独立安装 | 0.16.0 详情、模型路由入口、目录和模型档案可用;不出现旧合并 GAL 入口。 |
|
|
108
118
|
| GAL 独立安装 | 0.1.0 详情、Gal 模块入口、标题与两部核心剧情可用;不要求安装路由。 |
|
|
109
119
|
| 共同安装 | 两个入口各一份,路由工具和 GAL 播放器均能使用。 |
|
|
110
120
|
| 存档迁移 | 同 profile 可读旧键;跨 profile 用匹配剧目 JSON 导入;旧篇目的数据不覆盖。 |
|
|
111
121
|
| 本地规划 | 简单与复杂工作包分配可解释;价格未知保持未知;生成计划不调用模型。 |
|
|
112
122
|
| 官方工具 | 探测、固定来源安装、修复、取消和日志可检查;登录另验。 |
|
|
113
|
-
|
|
|
123
|
+
| 工作台只读执行 | 预览不启动模型,明确确认后执行;核对记录中的渠道、错误与费用。 |
|
|
124
|
+
| 持续反馈 | 点赞/不好/撤回后重新规划;调整只影响本地主观效用,停用与重置不抹除费用。 |
|
|
125
|
+
| 动态公开数据 | 默认关闭;自行启用后核对快照版本、校验时间及失败/过期状态;人工单价仍优先。 |
|
|
126
|
+
| 可编辑执行 | 在干净测试仓库核对审批、隔离工作区、补丁整合、厂商实际模型与计费。 |
|
|
114
127
|
|
|
115
|
-
|
|
128
|
+
历史 0.15.0 的自动测试验证为 220 项通过、3 项 Windows 平台跳过;组件 UI 预览检查使用模拟数据。**0.16.0 的发布验证见[更新记录](CHANGELOG.md)**,不把模拟公开源/模型流和组件预览当作真实付费调用或 Harness Desktop 端到端验收;上表中的实际安装、账号和工作区检查仍需在使用环境中完成。
|
|
116
129
|
|
|
117
130
|
## 8. 开发者从完整源码构建
|
|
118
131
|
|
|
119
|
-
|
|
132
|
+
路由需要 Node.js **22.19+** 与 **pnpm 10.34.6**。从完整源码仓库根目录构建;复现正式版 0.16.0 时检出对应发布标签。旧版(如 0.15.0)标签保留其当时内容。运行:
|
|
120
133
|
|
|
121
134
|
```powershell
|
|
122
|
-
pnpm install --frozen-lockfile
|
|
135
|
+
pnpm install --frozen-lockfile --strict-peer-dependencies
|
|
123
136
|
npm run build:client
|
|
124
137
|
npm test
|
|
125
138
|
npm run check:client
|
|
126
|
-
|
|
127
|
-
npm pack --pack-destination dist
|
|
139
|
+
npm run pack:local
|
|
128
140
|
```
|
|
129
141
|
|
|
130
|
-
|
|
142
|
+
pnpm 10 没有 `pnpm peers check`;使用严格依赖安装。客户端修改后必须重建,通过 `check:client` 再打包。将 `dist` 中本地包的绝对路径填入插件管理器,在测试 profile 验证;本地开发改动需独立验证,不能仅凭版本号判断包内容相同。
|
|
143
|
+
|
|
144
|
+
仅查看 UI 可运行 `npm run preview:ui` 并打开[本地预览](http://127.0.0.1:4173)。这是模拟目录、工具和执行记录,不启动 Harness Host、真实 CLI 或付费模型;不能代替桌面集成验收。GAL 独立仓库的开发与验证步骤以其自身 README 为准。
|
|
131
145
|
|
|
132
146
|
## 历史兼容提醒
|
|
133
147
|
|
|
134
|
-
合并版 **0.11.1 / 0.11.0** 声明 rc.1 与 rc.2;**0.10.2** 是未发布的本地兼容修复。已发布 **0.10.1** 仅声明 rc.1,rc.2 拒绝安装是 peer 依赖问题,换镜像不能修复;**0.8.0** 使用 0.1.7-rc.2 依赖,不用于当前宿主。历史 Git 标签和安装包保留,详见
|
|
148
|
+
合并版 **0.11.1 / 0.11.0** 声明 rc.1 与 rc.2;**0.10.2** 是未发布的本地兼容修复。已发布 **0.10.1** 仅声明 rc.1,rc.2 拒绝安装是 peer 依赖问题,换镜像不能修复;**0.8.0** 使用 0.1.7-rc.2 依赖,不用于当前宿主。历史 Git 标签和安装包保留,详见[更新记录](CHANGELOG.md)和[迁移说明](MIGRATION.md)。
|