@kasenri/dsh-orbit 0.6.0 → 0.6.1

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/README.md CHANGED
@@ -44,7 +44,7 @@ Executor, Smart Watchdog, durable state and bounded recovery.
44
44
  |---|---|
45
45
  | `@deepseek-ai/dsh` | `0.1.5-rc.2` |
46
46
  | `@deepseek-ai/cordis` | `4.0.2` |
47
- | `@goodandready/dsh-moa`(可选 MoA 集成) | `0.2.19` |
47
+ | `@goodandready/dsh-moa`(可选 MoA 集成) | `>=0.2.19`(已验证 0.2.19、0.2.20) |
48
48
  | Node.js | `>= 22.19.0` |
49
49
 
50
50
  Requires the DSH base services: `agents`, `subagents`, `tools`, `sessions`
@@ -59,7 +59,7 @@ mirror remains available when a Git source is preferred:
59
59
  dsh plugin --profile web add @kasenri/dsh-orbit
60
60
 
61
61
  # 可选:为 Orbit 的关键步骤启用多候选 MoA 选优
62
- dsh plugin --profile web add @goodandready/dsh-moa@0.2.19
62
+ dsh plugin --profile web add @goodandready/dsh-moa@0.2.20
63
63
 
64
64
  # Git source alternative, tracks the mirror repository HEAD:
65
65
  # dsh plugin --profile web add github:KasenRi/dsh-orbit
@@ -166,12 +166,12 @@ SINGLE ─────────────→ Executor
166
166
  - `peerCritique` 默认关闭;开启时只允许一轮有界互评。
167
167
  - 新 Run 会冻结 Candidate/Judge 的 provider、model、reasoningEffort、MoA policy,以及原版 MoA settings 中用户显式配置的价格表(如果存在)。中途修改 UI 只影响下一次 Run。
168
168
  - Candidate/Judge 的 input/output/cache Token 来自 DSH 子 Session 的真实 `assistant/message.usage`;如果冻结的价格表能匹配对应 Route,同时记录美元成本;没有价格时只展示 Token,并明确标记无法计算成本,不猜价格。
169
- - Orbit 会把一个不含目标正文、候选正文、Judge 推理或代码的有界运行快照写进所属 DSH Session projection。Web UI 可显示当前 Step、MoA 阶段、各候选模型/成败、Token、Judge、winner 和总计,刷新/重连后仍可恢复。
169
+ - Orbit 会把一个不含目标正文、候选正文、Judge 推理或代码的有界运行快照写进所属 DSH Session projection。v0.6.1 的配置首页不再直接展开这些运行详情,而是保持紧凑;运行快照仍保留给会话恢复与后续运行态界面使用。
170
170
  - 冷恢复按 durable phase 继续:`JUDGE` 不重跑 Candidate,`SELECTED` 不重跑 Candidate/Judge,`PROMOTED` 不重跑 Candidate/Judge/Promotion。
171
171
  - Orbit ACTIVE 时会在下游 hook 之前阻止独立 `/moa`,避免原版 MoA 的自动 Promotion 与 Orbit 同时争夺 workspace。
172
172
  - `@goodandready/dsh-moa` 是可选依赖;未安装时普通 SINGLE 模式完全不受影响。
173
173
 
174
- 当前兼容层针对 `@goodandready/dsh-moa@0.2.19`。Orbit 只依赖它公开的项目上下文接口;候选调度、Judge、持久化与 Promotion 权限均由 `moa-adapter.ts` 封装。未来 MoA 提供正式 integration/manual-promotion API 时,只需替换该适配层。
174
+ 当前兼容层接受 `@goodandready/dsh-moa >=0.2.19`,并已在 0.2.19 与 0.2.20 上完成真实 DSH 烟雾验证。更高版本不再被 Orbit 主动版本上限拦截;若上游未来发生实际 API 不兼容,再按真实故障修正。Orbit 只依赖它公开的项目上下文接口;候选调度、Judge、持久化与 Promotion 权限均由 `moa-adapter.ts` 封装。
175
175
 
176
176
  ## State machine
177
177
 
package/lib/client.js CHANGED
@@ -84,7 +84,7 @@ window.__ModuleLoader__.load({
84
84
  }
85
85
  //#endregion
86
86
  //#region \0dsh-css:/root/.devspace/worktrees/dsh-pi-parity-b411f55f/packages/orbit/client/OrbitModelSelect.module.css.mjs
87
- const css = ".f77nca_panel{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-specific-menu);min-width:260px;max-width:420px;max-height:min(55vh,420px);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);border-radius:12px;flex-direction:column;padding:6px;font-size:13px;line-height:1.4;display:flex;position:fixed;overflow:auto}.f77nca_title{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;padding:6px 8px 2px;font-size:11px;overflow:hidden}.f77nca_group{color:var(--dsw-alias-label-tertiary);padding:8px 8px 2px;font-size:11px}.f77nca_row{width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:8px;align-items:center;gap:8px;padding:7px 8px;display:flex}.f77nca_row:hover{background:var(--dsw-alias-interactive-bg-hover)}.f77nca_switchRow{align-items:center;gap:8px;padding:4px 8px 6px;display:flex}.f77nca_switchControl{margin-left:auto}.f77nca_rowLabel{flex:none}.f77nca_rowValue{max-width:190px;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;margin-left:auto;overflow:hidden}.f77nca_rowValueActive{color:var(--dsw-alias-label-primary)}.f77nca_rowDetail{color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:11px}.f77nca_check{color:var(--dsw-alias-state-business-primary);flex:none;margin-left:6px}.f77nca_chevron{color:var(--dsw-alias-label-tertiary);flex:none;margin-left:6px}.f77nca_separator{background:var(--dsw-alias-border-l1);height:1px;margin:6px 4px}.f77nca_hint{color:var(--dsw-alias-label-tertiary);padding:6px 8px;font-size:11px}.f77nca_error{color:var(--dsw-alias-state-error-primary);align-items:center;gap:8px;padding:8px;font-size:12px;display:flex}.f77nca_back{width:100%;color:var(--dsw-alias-label-tertiary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:6px 8px 8px;font-size:12px;display:flex}";
87
+ const css = ".f77nca_panel{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-specific-menu);min-width:260px;max-width:420px;max-height:min(55vh,420px);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);border-radius:12px;flex-direction:column;padding:6px;font-size:13px;line-height:1.4;display:flex;position:fixed;overflow:auto}.f77nca_title{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;padding:6px 8px 2px;font-size:11px;overflow:hidden}.f77nca_group{color:var(--dsw-alias-label-tertiary);padding:8px 8px 2px;font-size:11px}.f77nca_row{width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:8px;align-items:center;gap:8px;padding:7px 8px;display:flex}.f77nca_row:hover{background:var(--dsw-alias-interactive-bg-hover)}.f77nca_switchRow{align-items:center;gap:8px;padding:4px 8px 6px;display:flex}.f77nca_switchNavRow{align-items:center;gap:6px;padding:2px 4px 2px 8px;display:flex}.f77nca_switchNavLabel{min-width:0;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;flex:1;padding:5px 0}.f77nca_chevronButton{width:26px;height:26px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:0;display:inline-flex}.f77nca_switchNavLabel:hover,.f77nca_chevronButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.f77nca_switchControl{margin-left:auto}.f77nca_rowLabel{flex:none}.f77nca_rowValue{max-width:190px;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;margin-left:auto;overflow:hidden}.f77nca_rowValueActive{color:var(--dsw-alias-label-primary)}.f77nca_rowDetail{color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:11px}.f77nca_check{color:var(--dsw-alias-state-business-primary);flex:none;margin-left:6px}.f77nca_chevron{color:var(--dsw-alias-label-tertiary);flex:none;margin-left:6px}.f77nca_separator{background:var(--dsw-alias-border-l1);height:1px;margin:6px 4px}.f77nca_hint{color:var(--dsw-alias-label-tertiary);padding:6px 8px;font-size:11px}.f77nca_error{color:var(--dsw-alias-state-error-primary);align-items:center;gap:8px;padding:8px;font-size:12px;display:flex}.f77nca_navHeader{grid-template-columns:auto 1fr auto;align-items:center;min-height:32px;display:grid}.f77nca_back{color:var(--dsw-alias-label-tertiary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:6px 8px 8px;font-size:12px;display:flex}.f77nca_navTitle{color:var(--dsw-alias-label-primary);text-align:center;text-overflow:ellipsis;white-space:nowrap;grid-column:2;font-size:12px;font-weight:600;overflow:hidden}.f77nca_choiceMark{width:16px;color:var(--dsw-alias-label-tertiary);text-align:center;flex:none}";
88
88
  const tagId = "@kasenri/dsh-orbit/OrbitModelSelect.module.css";
89
89
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
90
90
  const tag = document.createElement("style");
@@ -94,22 +94,28 @@ window.__ModuleLoader__.load({
94
94
  document.head.appendChild(tag);
95
95
  }
96
96
  var OrbitModelSelect_module_css_default = {
97
- "rowValueActive": "f77nca_rowValueActive",
98
97
  "error": "f77nca_error",
99
- "rowValue": "f77nca_rowValue",
100
98
  "switchRow": "f77nca_switchRow",
99
+ "rowDetail": "f77nca_rowDetail",
100
+ "rowLabel": "f77nca_rowLabel",
101
+ "switchControl": "f77nca_switchControl",
102
+ "rowValueActive": "f77nca_rowValueActive",
101
103
  "check": "f77nca_check",
102
- "group": "f77nca_group",
103
104
  "panel": "f77nca_panel",
104
105
  "row": "f77nca_row",
105
106
  "title": "f77nca_title",
106
- "switchControl": "f77nca_switchControl",
107
- "rowLabel": "f77nca_rowLabel",
108
- "rowDetail": "f77nca_rowDetail",
107
+ "switchNavRow": "f77nca_switchNavRow",
108
+ "rowValue": "f77nca_rowValue",
109
+ "group": "f77nca_group",
110
+ "switchNavLabel": "f77nca_switchNavLabel",
109
111
  "chevron": "f77nca_chevron",
110
- "separator": "f77nca_separator",
111
112
  "hint": "f77nca_hint",
112
- "back": "f77nca_back"
113
+ "back": "f77nca_back",
114
+ "navTitle": "f77nca_navTitle",
115
+ "choiceMark": "f77nca_choiceMark",
116
+ "chevronButton": "f77nca_chevronButton",
117
+ "separator": "f77nca_separator",
118
+ "navHeader": "f77nca_navHeader"
113
119
  };
114
120
  //#endregion
115
121
  //#region client/OrbitModelSelect.tsx
@@ -146,7 +152,6 @@ window.__ModuleLoader__.load({
146
152
  const dir = (0, react.useSyncExternalStore)((listener) => directory.subscribe(listener), () => directory.getSnapshot());
147
153
  const config = (0, react.useSyncExternalStore)((listener) => settings.subscribe(listener), () => settings.getSnapshot());
148
154
  const orbitSession = useProjection("orbitSession");
149
- const orbitRuntime = useProjection("orbitRuntime");
150
155
  const [orbitOverride, setOrbitOverride] = (0, react.useState)(null);
151
156
  const [orbitPending, setOrbitPending] = (0, react.useState)(false);
152
157
  const orbitEnabled = orbitOverride ?? orbitSession?.enabled === true;
@@ -199,11 +204,6 @@ window.__ModuleLoader__.load({
199
204
  const watchdogModel = modelOf(dir, watchdogRoute);
200
205
  const watchdogLabel = watchdogRoute === void 0 ? void 0 : routeLabelOf(dir, watchdogRoute) ?? watchdogRoute.model;
201
206
  const watchdogEffort = effortLabelOf(watchdogModel, watchdogRoute?.reasoningEffort);
202
- const usageText = (usage) => {
203
- if (!usage) return void 0;
204
- const tokens = `${usage.total_tokens.toLocaleString()} ${t("moaTokens")}`;
205
- return usage.cost_usd === void 0 ? tokens : `${tokens} · $${usage.cost_usd.toFixed(4)}`;
206
- };
207
207
  const moaRouteOf = (role) => {
208
208
  if (role === "moa-judge") return config.moa.judge;
209
209
  if (!role.startsWith("moa-candidate-")) return void 0;
@@ -222,11 +222,11 @@ window.__ModuleLoader__.load({
222
222
  }
223
223
  };
224
224
  const commitMoaPolicy = async (patch) => {
225
- if (submitting.current || config.status !== "ready") return;
225
+ if (submitting.current || config.status !== "ready") return false;
226
226
  submitting.current = true;
227
227
  setBusy(true);
228
228
  try {
229
- await writeMoaPolicy(patch);
229
+ return await writeMoaPolicy(patch);
230
230
  } finally {
231
231
  submitting.current = false;
232
232
  setBusy(false);
@@ -258,6 +258,23 @@ window.__ModuleLoader__.load({
258
258
  if (role === "moa-judge") return t("moaJudge");
259
259
  return `${t("moaCandidate")} ${role.slice(14)}`;
260
260
  };
261
+ const isMoaRole = (role) => role === "moa-judge" || role.startsWith("moa-candidate-");
262
+ const paneTitle = () => {
263
+ if (pane.kind === "moa") return t("moa");
264
+ if (pane.kind === "moa-candidate-count") return t("moaCandidateCount");
265
+ if (pane.kind === "moa-max-steps") return t("moaMaxSteps");
266
+ if (pane.kind === "role" || pane.kind === "models" || pane.kind === "efforts") return roleTitleOf(pane.role);
267
+ return "";
268
+ };
269
+ const parentPane = () => {
270
+ if (pane.kind === "moa" || pane.kind === "moa-candidate-count" || pane.kind === "moa-max-steps") return pane.kind === "moa" ? { kind: "root" } : { kind: "moa" };
271
+ if (pane.kind === "role") return isMoaRole(pane.role) ? { kind: "moa" } : { kind: "root" };
272
+ if (pane.kind === "models" || pane.kind === "efforts") return {
273
+ kind: "role",
274
+ role: pane.role
275
+ };
276
+ return { kind: "root" };
277
+ };
261
278
  const roleModelLabelOf = (role) => {
262
279
  if (role === "commander") return t("commanderModel");
263
280
  if (role === "executor") return t("executorModel");
@@ -347,19 +364,19 @@ window.__ModuleLoader__.load({
347
364
  },
348
365
  role: "menu",
349
366
  children: [
350
- pane.kind === "root" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
351
- className: OrbitModelSelect_module_css_default.title,
352
- children: t("title")
353
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
354
- type: "button",
355
- className: OrbitModelSelect_module_css_default.back,
356
- onClick: () => {
357
- setPane(pane.kind === "role" ? { kind: "root" } : {
358
- kind: "role",
359
- role: pane.role
360
- });
361
- },
362
- children: `${BACK} ${pane.kind === "role" ? t("back") : roleTitleOf(pane.role)}`
367
+ pane.kind === "root" ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
368
+ className: OrbitModelSelect_module_css_default.navHeader,
369
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
370
+ type: "button",
371
+ className: OrbitModelSelect_module_css_default.back,
372
+ onClick: () => {
373
+ setPane(parentPane());
374
+ },
375
+ children: `${BACK} ${t("back")}`
376
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
377
+ className: OrbitModelSelect_module_css_default.navTitle,
378
+ children: paneTitle()
379
+ })]
363
380
  }),
364
381
  settingsError === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
365
382
  className: OrbitModelSelect_module_css_default.error,
@@ -400,65 +417,6 @@ window.__ModuleLoader__.load({
400
417
  })]
401
418
  }),
402
419
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: OrbitModelSelect_module_css_default.separator }),
403
- orbitRuntime ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
404
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
405
- className: OrbitModelSelect_module_css_default.group,
406
- children: t("runtime")
407
- }),
408
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
409
- className: OrbitModelSelect_module_css_default.row,
410
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
411
- className: OrbitModelSelect_module_css_default.rowLabel,
412
- children: orbitRuntime.currentStep?.id ?? orbitRuntime.phase
413
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
414
- className: OrbitModelSelect_module_css_default.rowValue,
415
- children: [orbitRuntime.currentStep?.executionMode ?? orbitRuntime.phase, ` · ${orbitRuntime.loop.used}/${orbitRuntime.loop.max}`]
416
- })]
417
- }),
418
- orbitRuntime.moa ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
419
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
420
- className: OrbitModelSelect_module_css_default.row,
421
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
422
- className: OrbitModelSelect_module_css_default.rowLabel,
423
- children: t("moaRuntimePhase")
424
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
425
- className: OrbitModelSelect_module_css_default.rowValue,
426
- children: orbitRuntime.moa.phase
427
- })]
428
- }),
429
- orbitRuntime.moa.candidates.map((candidate) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
430
- className: OrbitModelSelect_module_css_default.row,
431
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
432
- className: OrbitModelSelect_module_css_default.rowLabel,
433
- children: `${t("moaCandidate")} ${candidate.index}`
434
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
435
- className: OrbitModelSelect_module_css_default.rowValue,
436
- children: [`${candidate.ok ? "✓" : "✗"} ${candidate.provider}/${candidate.model}`, usageText(candidate.usage) ? ` · ${usageText(candidate.usage)}` : ""]
437
- })]
438
- }, candidate.index)),
439
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
440
- className: OrbitModelSelect_module_css_default.row,
441
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
442
- className: OrbitModelSelect_module_css_default.rowLabel,
443
- children: t("moaJudge")
444
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
445
- className: OrbitModelSelect_module_css_default.rowValue,
446
- children: orbitRuntime.moa.winnerModel ?? orbitRuntime.moa.judgeModel ?? t("moaWaiting")
447
- })]
448
- }),
449
- orbitRuntime.moa.totalUsage ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
450
- className: OrbitModelSelect_module_css_default.row,
451
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
452
- className: OrbitModelSelect_module_css_default.rowLabel,
453
- children: t("moaTotalUsage")
454
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
455
- className: OrbitModelSelect_module_css_default.rowValue,
456
- children: [usageText(orbitRuntime.moa.totalUsage), orbitRuntime.moa.totalUsage.cost_usd === void 0 ? ` · ${t("moaCostUnavailable")}` : ""]
457
- })]
458
- }) : null
459
- ] }) : null,
460
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: OrbitModelSelect_module_css_default.separator })
461
- ] }) : null,
462
420
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
463
421
  type: "button",
464
422
  role: "menuitem",
@@ -542,11 +500,47 @@ window.__ModuleLoader__.load({
542
500
  ]
543
501
  }),
544
502
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: OrbitModelSelect_module_css_default.separator }),
503
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
504
+ className: OrbitModelSelect_module_css_default.switchNavRow,
505
+ children: [
506
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
507
+ type: "button",
508
+ role: "menuitem",
509
+ className: OrbitModelSelect_module_css_default.switchNavLabel,
510
+ disabled: busy,
511
+ onClick: () => {
512
+ setPane({ kind: "moa" });
513
+ },
514
+ children: t("moa")
515
+ }),
516
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
517
+ className: OrbitModelSelect_module_css_default.switchControl,
518
+ checked: config.moa.enabled,
519
+ disabled: busy,
520
+ label: t("moaEnable"),
521
+ onChange: (next) => {
522
+ commitMoaPolicy({ enabled: next });
523
+ }
524
+ }),
525
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
526
+ type: "button",
527
+ className: OrbitModelSelect_module_css_default.chevronButton,
528
+ "aria-label": t("moaOpenSettings"),
529
+ disabled: busy,
530
+ onClick: () => {
531
+ setPane({ kind: "moa" });
532
+ },
533
+ children: CHEVRON
534
+ })
535
+ ]
536
+ })
537
+ ] }) : null,
538
+ pane.kind === "moa" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
545
539
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
546
540
  className: OrbitModelSelect_module_css_default.switchRow,
547
541
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
548
542
  className: OrbitModelSelect_module_css_default.rowLabel,
549
- children: t("moa")
543
+ children: t("moaEnable")
550
544
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
551
545
  className: OrbitModelSelect_module_css_default.switchControl,
552
546
  checked: config.moa.enabled,
@@ -563,15 +557,22 @@ window.__ModuleLoader__.load({
563
557
  className: OrbitModelSelect_module_css_default.row,
564
558
  disabled: busy,
565
559
  onClick: () => {
566
- commitMoaPolicy({ candidateCount: config.moa.candidateCount >= 4 ? 2 : config.moa.candidateCount + 1 });
560
+ setPane({ kind: "moa-candidate-count" });
567
561
  },
568
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
569
- className: OrbitModelSelect_module_css_default.rowLabel,
570
- children: t("moaCandidateCount")
571
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
572
- className: OrbitModelSelect_module_css_default.rowValue,
573
- children: config.moa.candidateCount
574
- })]
562
+ children: [
563
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
564
+ className: OrbitModelSelect_module_css_default.rowLabel,
565
+ children: t("moaCandidateCount")
566
+ }),
567
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
568
+ className: OrbitModelSelect_module_css_default.rowValue,
569
+ children: config.moa.candidateCount
570
+ }),
571
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
572
+ className: OrbitModelSelect_module_css_default.chevron,
573
+ children: CHEVRON
574
+ })
575
+ ]
575
576
  }),
576
577
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
577
578
  className: OrbitModelSelect_module_css_default.switchRow,
@@ -594,16 +595,24 @@ window.__ModuleLoader__.load({
594
595
  className: OrbitModelSelect_module_css_default.row,
595
596
  disabled: busy,
596
597
  onClick: () => {
597
- commitMoaPolicy({ maxMoaSteps: config.moa.maxMoaSteps >= 5 ? 1 : config.moa.maxMoaSteps + 1 });
598
+ setPane({ kind: "moa-max-steps" });
598
599
  },
599
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
600
- className: OrbitModelSelect_module_css_default.rowLabel,
601
- children: t("moaMaxSteps")
602
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
603
- className: OrbitModelSelect_module_css_default.rowValue,
604
- children: config.moa.maxMoaSteps
605
- })]
600
+ children: [
601
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
602
+ className: OrbitModelSelect_module_css_default.rowLabel,
603
+ children: t("moaMaxSteps")
604
+ }),
605
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
606
+ className: OrbitModelSelect_module_css_default.rowValue,
607
+ children: config.moa.maxMoaSteps
608
+ }),
609
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
610
+ className: OrbitModelSelect_module_css_default.chevron,
611
+ children: CHEVRON
612
+ })
613
+ ]
606
614
  }),
615
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: OrbitModelSelect_module_css_default.separator }),
607
616
  Array.from({ length: config.moa.candidateCount }, (_, offset) => {
608
617
  const role = `moa-candidate-${offset + 1}`;
609
618
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
@@ -660,6 +669,54 @@ window.__ModuleLoader__.load({
660
669
  ]
661
670
  })
662
671
  ] }) : null,
672
+ pane.kind === "moa-candidate-count" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: [
673
+ 2,
674
+ 3,
675
+ 4
676
+ ].map((count) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
677
+ type: "button",
678
+ role: "menuitemradio",
679
+ "aria-checked": config.moa.candidateCount === count,
680
+ className: OrbitModelSelect_module_css_default.row,
681
+ disabled: busy,
682
+ onClick: () => {
683
+ commitMoaPolicy({ candidateCount: count }).then((ok) => {
684
+ if (ok) setPane({ kind: "moa" });
685
+ });
686
+ },
687
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
688
+ className: OrbitModelSelect_module_css_default.choiceMark,
689
+ children: config.moa.candidateCount === count ? "●" : "○"
690
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
691
+ className: OrbitModelSelect_module_css_default.rowLabel,
692
+ children: `${count} ${t("moaCandidatesUnit")}`
693
+ })]
694
+ }, count)) }) : null,
695
+ pane.kind === "moa-max-steps" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: [
696
+ 1,
697
+ 2,
698
+ 3,
699
+ 4,
700
+ 5
701
+ ].map((count) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
702
+ type: "button",
703
+ role: "menuitemradio",
704
+ "aria-checked": config.moa.maxMoaSteps === count,
705
+ className: OrbitModelSelect_module_css_default.row,
706
+ disabled: busy,
707
+ onClick: () => {
708
+ commitMoaPolicy({ maxMoaSteps: count }).then((ok) => {
709
+ if (ok) setPane({ kind: "moa" });
710
+ });
711
+ },
712
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
713
+ className: OrbitModelSelect_module_css_default.choiceMark,
714
+ children: config.moa.maxMoaSteps === count ? "●" : "○"
715
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
716
+ className: OrbitModelSelect_module_css_default.rowLabel,
717
+ children: count
718
+ })]
719
+ }, count)) }) : null,
663
720
  pane.kind === "role" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
664
721
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
665
722
  type: "button",
@@ -751,11 +808,10 @@ window.__ModuleLoader__.load({
751
808
  children: "✓"
752
809
  }) : null]
753
810
  }, choice.id))] }) : null,
754
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: OrbitModelSelect_module_css_default.separator }),
755
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
811
+ pane.kind === "root" || pane.kind === "moa" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: OrbitModelSelect_module_css_default.separator }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
756
812
  className: OrbitModelSelect_module_css_default.hint,
757
813
  children: t("applyOnNextSend")
758
- })
814
+ })] }) : null
759
815
  ]
760
816
  }), document.body) : null] });
761
817
  }
@@ -777,8 +833,10 @@ window.__ModuleLoader__.load({
777
833
  executorModel: "Executor model",
778
834
  watchdogModel: "Watchdog model",
779
835
  moa: "MoA",
780
- moaEnable: "Enable MoA for eligible steps",
836
+ moaEnable: "Enable MoA",
837
+ moaOpenSettings: "Open MoA settings",
781
838
  moaCandidate: "Candidate",
839
+ moaCandidatesUnit: "candidates",
782
840
  moaCandidateCount: "Candidate count",
783
841
  moaJudge: "Judge",
784
842
  moaPeerCritique: "Peer critique",
@@ -815,8 +873,10 @@ window.__ModuleLoader__.load({
815
873
  executorModel: "执行员模型",
816
874
  watchdogModel: "监控模型",
817
875
  moa: "MoA 多候选模式",
818
- moaEnable: "允许关键步骤使用 MoA",
876
+ moaEnable: "启用 MoA",
877
+ moaOpenSettings: "打开 MoA 设置",
819
878
  moaCandidate: "候选模型",
879
+ moaCandidatesUnit: "个候选",
820
880
  moaCandidateCount: "候选数量",
821
881
  moaJudge: "Judge 评审模型",
822
882
  moaPeerCritique: "候选互评",
@@ -12,7 +12,22 @@ import { dirname, join, relative, resolve } from 'node:path';
12
12
  import { pathToFileURL } from 'node:url';
13
13
  import { copyFile, lstat, mkdir, readFile, readdir, realpath, stat, writeFile } from 'node:fs/promises';
14
14
  import { redactText, truncateSafe } from "./sanitize.js";
15
- const SUPPORTED_MOA_VERSION = '0.2.19';
15
+ const MIN_SUPPORTED_MOA_VERSION = [0, 2, 19];
16
+ function isSupportedMoaVersion(version) {
17
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/u);
18
+ if (!match)
19
+ return false;
20
+ const current = [Number(match[1]), Number(match[2]), Number(match[3])];
21
+ for (let index = 0; index < MIN_SUPPORTED_MOA_VERSION.length; index += 1) {
22
+ const actual = current[index] ?? 0;
23
+ const minimum = MIN_SUPPORTED_MOA_VERSION[index] ?? 0;
24
+ if (actual > minimum)
25
+ return true;
26
+ if (actual < minimum)
27
+ return false;
28
+ }
29
+ return true;
30
+ }
16
31
  const MAX_CONTEXT_CHARS = 16_000;
17
32
  const MAX_CANDIDATE_TEXT = 12_000;
18
33
  const MAX_JUDGE_TEXT = 8_000;
@@ -222,8 +237,8 @@ export class OrbitMoaAdapter {
222
237
  }
223
238
  const pkg = JSON.parse(await readFile(packageJsonPath, 'utf8'));
224
239
  const version = String(pkg.version ?? '');
225
- if (version !== SUPPORTED_MOA_VERSION) {
226
- throw new Error('ORBIT_MOA_VERSION_UNSUPPORTED: 当前支持 ' + SUPPORTED_MOA_VERSION + ',检测到 ' + (version || 'unknown') + '。');
240
+ if (!isSupportedMoaVersion(version)) {
241
+ throw new Error('ORBIT_MOA_VERSION_UNSUPPORTED: 当前要求 @goodandready/dsh-moa >= 0.2.19,检测到 ' + (version || 'unknown') + '。');
227
242
  }
228
243
  const entry = require.resolve('@goodandready/dsh-moa');
229
244
  const api = await import(__rewriteRelativeImportExtension(pathToFileURL(entry).href));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kasenri/dsh-orbit",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "description": "让 AI 项目可以在无人监管下持续推进。Orbit 会自动规划任务、分工执行、逐步检查并继续完成后续工作;不同环节可以使用不同模型,让低成本模型承担执行任务、强模型负责规划和审核,从而降低整体 AI 使用成本。Watchdog 还会监控运行异常,在任务卡死或中断时协助恢复。",
6
6
  "license": "MIT",
@@ -62,7 +62,7 @@
62
62
  "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
63
63
  "@deepseek-ai/dsh-subagent": "^0.1.5-rc.2",
64
64
  "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
65
- "@goodandready/dsh-moa": "0.2.19"
65
+ "@goodandready/dsh-moa": ">=0.2.19"
66
66
  },
67
67
  "peerDependenciesMeta": {
68
68
  "@deepseek-ai/dsh-commands": {