@ljwei-stak/dsh-model-router 0.23.0 → 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.
@@ -3254,6 +3254,8 @@ var import_react2 = __toESM(require("react"), 1);
3254
3254
  // .dsh-plugin/client/insights-state.mjs
3255
3255
  var PACKAGE_STATUS = Object.freeze({
3256
3256
  pending: Object.freeze({ label: "\u5F85\u6267\u884C", tone: "pending" }),
3257
+ running: Object.freeze({ label: "\u6267\u884C\u4E2D", tone: "pending" }),
3258
+ interrupted: Object.freeze({ label: "\u6267\u884C\u4E2D\u65AD\uFF0C\u8D39\u7528\u5F85\u6838\u5BF9", tone: "warn" }),
3257
3259
  succeeded: Object.freeze({ label: "\u5B98\u65B9 CLI \u5B8C\u6210", tone: "ok" }),
3258
3260
  fallback: Object.freeze({ label: "\u5DF2\u56DE\u9000 API \u5B8C\u6210", tone: "warn" }),
3259
3261
  failed: Object.freeze({ label: "\u5931\u8D25", tone: "error" }),
@@ -3314,14 +3316,43 @@ function budgetMeter(spent, limit) {
3314
3316
  const share = Math.min(1, Math.max(0, spent / limit));
3315
3317
  return { limited: true, share, over: spent >= limit, text: `${money(spent)} / ${money(limit)}` };
3316
3318
  }
3319
+ var nonnegative2 = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
3320
+ function reservationSummary(ledger) {
3321
+ const value = ledger?.reserved ?? {};
3322
+ const reservations = (ledger?.reservations ?? []).filter((item) => ["active", "interrupted"].includes(item.status));
3323
+ return {
3324
+ today: nonnegative2(value.today),
3325
+ month: nonnegative2(value.month),
3326
+ unknownToday: nonnegative2(value.unknownToday),
3327
+ unknownMonth: nonnegative2(value.unknownMonth),
3328
+ activeCount: value.activeCount === void 0 ? reservations.filter((item) => item.status === "active").length : nonnegative2(value.activeCount),
3329
+ interruptedCount: value.interruptedCount === void 0 ? reservations.filter((item) => item.status === "interrupted").length : nonnegative2(value.interruptedCount)
3330
+ };
3331
+ }
3332
+ function budgetOccupancyMeter(spent, limit, reserved = 0) {
3333
+ const actual = nonnegative2(spent);
3334
+ const hold = nonnegative2(reserved);
3335
+ const meter = budgetMeter(actual + hold, limit);
3336
+ return { ...meter, text: `\u5DF2\u53D1\u751F ${money(actual)} \xB7 \u9884\u5360 ${money(hold)}${limit > 0 ? ` / \u4E0A\u9650 ${money(limit)}` : "\uFF08\u672A\u8BBE\u4E0A\u9650\uFF09"}` };
3337
+ }
3317
3338
  function planBudget(ledger, estimateUsd) {
3318
3339
  if (!ledger?.budget) return null;
3319
- return budgetCheck({
3340
+ const actual = ledger.spent ?? { today: 0, month: 0 };
3341
+ const reserved = reservationSummary(ledger);
3342
+ const result = budgetCheck({
3320
3343
  estimateUsd,
3321
- spent: ledger.spent ?? { today: 0, month: 0 },
3344
+ spent: { ...actual, today: nonnegative2(actual.today) + reserved.today, month: nonnegative2(actual.month) + reserved.month },
3322
3345
  dailyLimitUsd: ledger.budget.dailyLimitUsd,
3323
3346
  monthlyLimitUsd: ledger.budget.monthlyLimitUsd
3324
3347
  });
3348
+ if (result.exceeded) {
3349
+ const period = result.exceeded === "daily" ? "today" : "month";
3350
+ if (reserved[period] > 0) result.message = result.message.replace(
3351
+ `\u5DF2\u7528 ${money(nonnegative2(actual[period]) + reserved[period])}`,
3352
+ `\u5DF2\u53D1\u751F ${money(nonnegative2(actual[period]))}\uFF0C\u9884\u5360 ${money(reserved[period])}`
3353
+ );
3354
+ }
3355
+ return result;
3325
3356
  }
3326
3357
  function unwrapRemote(response, fallback) {
3327
3358
  if (!response?.ok) throw new Error(String(response?.error?.message ?? "") || fallback);
@@ -3338,6 +3369,8 @@ var RUN_STATUS_LABEL = Object.freeze({
3338
3369
  partial: "\u90E8\u5206\u5B8C\u6210",
3339
3370
  failed: "\u5931\u8D25",
3340
3371
  "cli-completed": "\u5B8C\u6210",
3372
+ running: "\u6267\u884C\u4E2D",
3373
+ interrupted: "\u6267\u884C\u4E2D\u65AD\uFF0C\u8D39\u7528\u5F85\u6838\u5BF9",
3341
3374
  incomplete: "\u672A\u5B8C\u6210",
3342
3375
  paused: "\u7B49\u5F85\u786E\u8BA4",
3343
3376
  "integration-pending": "\u5F85\u6574\u5408",
@@ -3382,7 +3415,18 @@ function runTotals(run) {
3382
3415
  }
3383
3416
  return { budgetUsd, referenceUsd, subscription };
3384
3417
  }
3385
- function rerunSupport(run) {
3418
+ function rerunSupport(run, ledger = null) {
3419
+ const reservation = (ledger?.reservations ?? []).find((item) => item.runId === run?.id && ["active", "interrupted"].includes(item.status));
3420
+ if (["running", "interrupted"].includes(run?.status) || reservation) {
3421
+ const interrupted = run?.status === "interrupted" || reservation?.status === "interrupted";
3422
+ return {
3423
+ supported: false,
3424
+ writes: run?.executionMode === "workspace-write",
3425
+ reassign: false,
3426
+ confirm: "",
3427
+ reason: interrupted ? "\u6267\u884C\u4E2D\u65AD\uFF0C\u8D39\u7528\u5F85\u6838\u5BF9\uFF0C\u4E0D\u80FD\u76F4\u63A5\u91CD\u8DD1\u3002\u8BF7\u5148\u6838\u5BF9\u65E7\u4EFB\u52A1\u4E0E\u5382\u5546\u8D26\u5355\uFF0C\u5E76\u4FDD\u7559\u539F\u59CB\u72B6\u6001\u53CA\u5DF2\u4FDD\u5B58\u7ED3\u679C\uFF1B\u4E0D\u4F1A\u81EA\u52A8\u4ED8\u8D39\u6062\u590D\u3002" : "\u4EFB\u52A1\u4ECD\u5728\u6267\u884C\u6216\u4FDD\u7559\u9884\u7B97\u9884\u5360\uFF0C\u4E0D\u80FD\u76F4\u63A5\u91CD\u8DD1\u3002\u8BF7\u5148\u7B49\u5F85\u539F\u4EFB\u52A1\u7ED3\u675F\uFF0C\u6216\u5728\u6267\u884C\u8FDB\u5EA6\u4E2D\u53D6\u6D88\u540E\u6838\u5BF9\u7ED3\u679C\u4E0E\u5382\u5546\u8D26\u5355\u3002"
3428
+ };
3429
+ }
3386
3430
  if (run?.kind === "tool") {
3387
3431
  const editable = run.executionMode === "workspace-write";
3388
3432
  return {
@@ -3512,7 +3556,8 @@ function launchRequest({ task, mode, directRoute, budgetUsd, preset, workspace,
3512
3556
  }
3513
3557
  function rerunConfirmations({ run, item, override = null, choice = null, ledger = null, health = null, toolFor = () => null, headlessIds = /* @__PURE__ */ new Set() } = {}) {
3514
3558
  const reasons = [];
3515
- const support = rerunSupport(run);
3559
+ const support = rerunSupport(run, ledger);
3560
+ if (!support.supported) return reasons;
3516
3561
  if (support.writes) reasons.push({ code: "workspace-write", text: support.confirm });
3517
3562
  if (run?.kind === "team" && run.executionEnvironment === "cli-native") reasons.push({
3518
3563
  code: "unsandboxed",
@@ -3525,12 +3570,7 @@ function rerunConfirmations({ run, item, override = null, choice = null, ledger
3525
3570
  reasons.push({ code: "unsandboxed", text: `\u4F1A\u76F4\u63A5\u542F\u52A8 ${tool.label} \u7684\u65E0\u754C\u9762 CLI\uFF0C\u4E0D\u7ECF\u8FC7 Harness \u8FDB\u7A0B\u6C99\u7BB1\uFF0C\u53EA\u8BFB\u4EC5\u7531 CLI \u53C2\u6570\u4FDD\u8BC1\u3002` });
3526
3571
  }
3527
3572
  const estimate = override ? null : item?.estimatedCost;
3528
- const check = ledger?.budget ? budgetCheck({
3529
- estimateUsd: typeof estimate === "number" ? estimate : null,
3530
- spent: ledger.spent ?? {},
3531
- dailyLimitUsd: ledger.budget.dailyLimitUsd,
3532
- monthlyLimitUsd: ledger.budget.monthlyLimitUsd
3533
- }) : null;
3573
+ const check = planBudget(ledger, typeof estimate === "number" ? estimate : null);
3534
3574
  if (check?.exceeded) reasons.push({ code: "over-budget", text: `\u8D85\u51FA\u9884\u7B97\uFF1A${check.message}` });
3535
3575
  return reasons;
3536
3576
  }
@@ -3598,18 +3638,18 @@ function feedbackRatingArguments(run, item, direction) {
3598
3638
  const active = direction === "up" ? item?.rating === 1 : item?.rating === -1;
3599
3639
  return [run?.id, item?.id, active ? "clear" : direction, item?.finishedAt];
3600
3640
  }
3601
- var nonnegative2 = (value) => Number.isFinite(value) && value >= 0 ? value : 0;
3641
+ var nonnegative3 = (value) => Number.isFinite(value) && value >= 0 ? value : 0;
3602
3642
  function learningView(learning, settings = {}) {
3603
3643
  return {
3604
3644
  available: Boolean(learning && typeof learning === "object" && !Array.isArray(learning)),
3605
3645
  // Current settings govern the next plan; a failed refresh must not make an
3606
3646
  // older profile claim that a newly disabled policy is still enabled.
3607
3647
  enabled: adaptiveSettingValue(settings, "feedbackLearningEnabled") !== false,
3608
- feedbackCount: nonnegative2(learning?.feedbackCount),
3609
- ignoredCount: nonnegative2(learning?.ignoredCount),
3610
- effectiveWeight: nonnegative2(learning?.effectiveWeight),
3648
+ feedbackCount: nonnegative3(learning?.feedbackCount),
3649
+ ignoredCount: nonnegative3(learning?.ignoredCount),
3650
+ effectiveWeight: nonnegative3(learning?.effectiveWeight),
3611
3651
  policyVersion: typeof learning?.policyVersion === "string" ? learning.policyVersion.slice(0, 100) : null,
3612
- resetAt: nonnegative2(adaptiveSettingValue(settings, "feedbackResetAt"))
3652
+ resetAt: nonnegative3(adaptiveSettingValue(settings, "feedbackResetAt"))
3613
3653
  };
3614
3654
  }
3615
3655
  function learningEvidenceRows(learning, limit = 12) {
@@ -3625,11 +3665,11 @@ function learningEvidenceRows(learning, limit = 12) {
3625
3665
  id: JSON.stringify([key, domain]),
3626
3666
  route: identity.map((part) => part.slice(0, 100)).join("/"),
3627
3667
  domain: domain.slice(0, 80),
3628
- feedbackCount: nonnegative2(cell.feedbackCount),
3629
- positiveCount: nonnegative2(cell.positiveCount),
3630
- negativeCount: nonnegative2(cell.negativeCount),
3631
- effectiveWeight: nonnegative2(cell.effectiveWeight),
3632
- effectiveSampleSize: nonnegative2(cell.effectiveSampleSize),
3668
+ feedbackCount: nonnegative3(cell.feedbackCount),
3669
+ positiveCount: nonnegative3(cell.positiveCount),
3670
+ negativeCount: nonnegative3(cell.negativeCount),
3671
+ effectiveWeight: nonnegative3(cell.effectiveWeight),
3672
+ effectiveSampleSize: nonnegative3(cell.effectiveSampleSize),
3633
3673
  shrinkage: Number.isFinite(cell.shrinkage) && cell.shrinkage >= 0 && cell.shrinkage <= 1 ? cell.shrinkage : 0,
3634
3674
  adjustment: cell.adjustment
3635
3675
  });
@@ -3652,7 +3692,7 @@ var EXCLUSION_LABELS = Object.freeze({
3652
3692
  });
3653
3693
  function learningExclusionRows(learning) {
3654
3694
  return Object.entries(EXCLUSION_LABELS).flatMap(([reason, label]) => {
3655
- const count = nonnegative2(learning?.exclusionReasons?.[reason]);
3695
+ const count = nonnegative3(learning?.exclusionReasons?.[reason]);
3656
3696
  return count > 0 ? [{ reason, label, count }] : [];
3657
3697
  });
3658
3698
  }
@@ -3669,7 +3709,7 @@ function dynamicSourceView(source, enabled = true) {
3669
3709
  source: publicSource,
3670
3710
  version: enabled !== false && typeof source?.version === "string" ? source.version.slice(0, 160) : null,
3671
3711
  verifiedAt: enabled !== false && Number.isFinite(source?.verifiedAt) && source.verifiedAt > 0 ? source.verifiedAt : null,
3672
- count: enabled === false ? 0 : nonnegative2(source?.modelCount ?? source?.rowCount),
3712
+ count: enabled === false ? 0 : nonnegative3(source?.modelCount ?? source?.rowCount),
3673
3713
  refreshing: enabled !== false && source?.refreshing === true,
3674
3714
  pending: enabled !== false && source?.pending === true,
3675
3715
  lastAttemptAt: enabled === false ? null : positiveTime(source?.lastAttemptAt),
@@ -3911,6 +3951,8 @@ function CostControlCard({ ledger, settingsScope, onChanged, error, refreshing =
3911
3951
  const daily = Number(value.dailyBudgetUsd ?? 0);
3912
3952
  const monthly = Number(value.monthlyBudgetUsd ?? 0);
3913
3953
  const spent = ledger?.spent ?? { today: 0, month: 0, unknownToday: 0, unknownMonth: 0 };
3954
+ const reserved = reservationSummary(ledger);
3955
+ const reservations = (ledger?.reservations ?? []).filter((item) => ["active", "interrupted"].includes(item.status));
3914
3956
  const set = async (key, next) => {
3915
3957
  if (await settings.write(key, next)) onChanged?.();
3916
3958
  };
@@ -3922,7 +3964,7 @@ function CostControlCard({ ledger, settingsScope, onChanged, error, refreshing =
3922
3964
  onChanged?.();
3923
3965
  }
3924
3966
  };
3925
- return /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card mr-cost", "aria-label": "\u6210\u672C\u63A7\u5236" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react2.default.createElement("div", null, /* @__PURE__ */ import_react2.default.createElement("h2", { className: "mr-card-title" }, "\u6210\u672C\u63A7\u5236\u4E0E\u8DEF\u7531\u65B9\u6848"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u9884\u7B97\u53EA\u8BA1\u7B97\u8D70 API Key \u6216\u6A21\u578B\u76EE\u5F55 API \u7684\u82B1\u8D39\uFF08CLI \u81EA\u62A5\u91D1\u989D\u6216 token \u7528\u91CF \xD7 \u4F60\u914D\u7F6E\u7684\u5355\u4EF7\uFF09\u3002\u5B98\u65B9 CLI \u7528\u8BA2\u9605\u8D26\u53F7\u767B\u5F55\u3001\u672A\u6CE8\u5165 API Key \u65F6\uFF0C\u53EA\u663E\u793A\u6309 API \u4EF7\u6298\u7B97\u7684\u201C\u8BA2\u9605\u53C2\u8003\u8D39\u7528\u201D\uFF0C\u4E0D\u8BA1\u5165\u9884\u7B97\u3002\u7F3A\u5C11\u5355\u4EF7\u7684\u8C03\u7528\u8BA1\u4E3A\u201C\u8D39\u7528\u672A\u77E5\u201D\u3002\u8FD9\u662F\u672C\u673A\u4F30\u7B97\uFF0C\u4E0D\u662F\u5382\u5546\u8D26\u5355\u3002"))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-body" }, error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, error), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-meters" }, /* @__PURE__ */ import_react2.default.createElement(Meter, { label: "\u4ECA\u65E5\u5DF2\u7528\uFF08\u8BA1\u5165\u9884\u7B97\uFF09", meter: budgetMeter(spent.today, daily) }), /* @__PURE__ */ import_react2.default.createElement(Meter, { label: "\u672C\u6708\u5DF2\u7528\uFF08\u8BA1\u5165\u9884\u7B97\uFF09", meter: budgetMeter(spent.month, monthly) })), (spent.subscriptionRunsMonth ?? 0) > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u8BA2\u9605\u53C2\u8003\u8D39\u7528\uFF08\u6309 API \u4EF7\u6298\u7B97\uFF0C\u4E0D\u8BA1\u5165\u9884\u7B97\uFF09\uFF1A\u4ECA\u65E5 ", money(spent.subscriptionToday ?? 0), " \xB7 \u672C\u6708 ", money(spent.subscriptionMonth ?? 0), "\uFF0C\u672C\u6708\u5171 ", spent.subscriptionRunsMonth, " \u6B21\u8BA2\u9605\u767B\u5F55\u8C03\u7528\u3002"), (spent.unknownToday > 0 || spent.unknownMonth > 0) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u672C\u6708\u6709 ", spent.unknownMonth, " \u6B21\u8C03\u7528\u7F3A\u5C11\u5355\u4EF7\u6216\u7528\u91CF\uFF0C\u672A\u8BA1\u5165\u91D1\u989D\u3002\u8BF7\u5728\u201C\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B\u201D\u4E2D\u8865\u9F50\u5355\u4EF7\u3002"), ledger?.budget?.exceeded && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, ledger.budget.message, " ", ledger.budget.action === "pause" ? "\u65B0\u7684\u6267\u884C\u4F1A\u5148\u6682\u505C\u5E76\u8BF7\u6C42\u786E\u8BA4\u3002" : "\u65B0\u7684\u6267\u884C\u4F1A\u5C1D\u8BD5\u81EA\u52A8\u964D\u7EA7\u4E3A\u201C\u7701\u94B1\u4F18\u5148\u201D\u3002"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, "\u8DEF\u7531\u65B9\u6848"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-segment", role: "group", "aria-label": "\u8DEF\u7531\u65B9\u6848" }, Object.values(ROUTING_PRESETS).map((item) => /* @__PURE__ */ import_react2.default.createElement("button", { key: item.id, type: "button", title: item.description, "aria-pressed": preset === item.id, disabled: !settings.writable, onClick: () => {
3967
+ return /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card mr-cost", "aria-label": "\u6210\u672C\u63A7\u5236" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react2.default.createElement("div", null, /* @__PURE__ */ import_react2.default.createElement("h2", { className: "mr-card-title" }, "\u6210\u672C\u63A7\u5236\u4E0E\u8DEF\u7531\u65B9\u6848"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u9884\u7B97\u53EA\u8BA1\u7B97\u8D70 API Key \u6216\u6A21\u578B\u76EE\u5F55 API \u7684\u82B1\u8D39\uFF08CLI \u81EA\u62A5\u91D1\u989D\u6216 token \u7528\u91CF \xD7 \u4F60\u914D\u7F6E\u7684\u5355\u4EF7\uFF09\u3002\u5B98\u65B9 CLI \u7528\u8BA2\u9605\u8D26\u53F7\u767B\u5F55\u3001\u672A\u6CE8\u5165 API Key \u65F6\uFF0C\u53EA\u663E\u793A\u6309 API \u4EF7\u6298\u7B97\u7684\u201C\u8BA2\u9605\u53C2\u8003\u8D39\u7528\u201D\uFF0C\u4E0D\u8BA1\u5165\u9884\u7B97\u3002\u7F3A\u5C11\u5355\u4EF7\u7684\u8C03\u7528\u8BA1\u4E3A\u201C\u8D39\u7528\u672A\u77E5\u201D\u3002\u8FD9\u662F\u672C\u673A\u4F30\u7B97\uFF0C\u4E0D\u662F\u5382\u5546\u8D26\u5355\u3002"))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-body" }, error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, error), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-meters" }, /* @__PURE__ */ import_react2.default.createElement(Meter, { label: "\u4ECA\u65E5\u9884\u7B97\u5360\u7528", meter: budgetOccupancyMeter(spent.today, daily, reserved.today) }), /* @__PURE__ */ import_react2.default.createElement(Meter, { label: "\u672C\u6708\u9884\u7B97\u5360\u7528", meter: budgetOccupancyMeter(spent.month, monthly, reserved.month) })), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u9884\u5360\u662F\u5C1A\u672A\u7ED3\u7B97\u7684\u8D39\u7528\u4F30\u7B97\uFF0C\u4E0D\u662F\u5B9E\u9645\u8D26\u5355\uFF1B\u5269\u4F59\u989D\u5EA6\u5DF2\u6263\u9664\u5DF2\u53D1\u751F\u8D39\u7528\u4E0E\u5DF2\u77E5\u9884\u5360\u3002\u6267\u884C\u4E2D ", reserved.activeCount, " \u9879 \xB7 \u5F85\u6838\u5BF9\u4E2D\u65AD ", reserved.interruptedCount, " \u9879\u3002"), (reserved.unknownToday > 0 || reserved.unknownMonth > 0) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption mr-warn-text" }, "\u9884\u5360\u91D1\u989D\u672A\u77E5\uFF1A\u4ECA\u65E5 ", reserved.unknownToday, " \u9879 \xB7 \u672C\u6708 ", reserved.unknownMonth, " \u9879\uFF0C\u672A\u8BA1\u5165\u4E0A\u65B9\u9884\u5360\u91D1\u989D\uFF0C\u4E0D\u80FD\u89C6\u4E3A\u96F6\u8D39\u7528\u3002\u8BF7\u6838\u5BF9\u5382\u5546\u8D26\u5355\u4E0E\u539F\u4EFB\u52A1\u8BB0\u5F55\u3002"), reserved.interruptedCount > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, "\u6709\u4E2D\u65AD\u4EFB\u52A1\u5C1A\u672A\u6838\u5BF9\uFF0C\u9884\u5360\u7EE7\u7EED\u4FDD\u7559\uFF0C\u4E0D\u80FD\u76F4\u63A5\u91CD\u8DD1\u3002\u8BF7\u5148\u6838\u5BF9\u65E7\u4EFB\u52A1\u4E0E\u5382\u5546\u8D26\u5355\uFF0C\u4FDD\u7559\u539F\u59CB\u72B6\u6001\u6587\u4EF6\u548C\u5DF2\u4FDD\u5B58\u7ED3\u679C\uFF1B\u82E5\u8BB0\u5F55\u635F\u574F\uFF0C\u4ECE\u53EF\u4FE1\u5907\u4EFD\u6062\u590D\u5B8C\u6574\u72B6\u6001\u3002\u5F53\u524D\u754C\u9762\u4E0D\u652F\u6301\u624B\u52A8\u7ED3\u7B97\u6216\u81EA\u52A8\u4ED8\u8D39\u6062\u590D\u3002"), reservations.length > 0 && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u67E5\u770B\u672A\u7ED3\u7B97\u9884\u5360\uFF08", reservations.length, " \u9879\uFF09"), /* @__PURE__ */ import_react2.default.createElement("ul", { className: "mr-checklist" }, reservations.map((item) => /* @__PURE__ */ import_react2.default.createElement("li", { key: item.id }, "\u8FD0\u884C ", /* @__PURE__ */ import_react2.default.createElement("code", null, item.runId || item.id), " \xB7 ", item.status === "interrupted" ? "\u6267\u884C\u4E2D\u65AD\uFF0C\u8D39\u7528\u5F85\u6838\u5BF9" : "\u6267\u884C\u4E2D", " \xB7 \u5269\u4F59\u9884\u5360 ", item.unknown || !Number.isFinite(item.remainingEstimateUsd) ? "\u91D1\u989D\u672A\u77E5" : money(item.remainingEstimateUsd), Number.isFinite(item.updatedAt) ? ` \xB7 \u6700\u8FD1\u4FDD\u5B58 ${new Date(item.updatedAt).toLocaleString()}` : "")))), (spent.subscriptionRunsMonth ?? 0) > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u8BA2\u9605\u53C2\u8003\u8D39\u7528\uFF08\u6309 API \u4EF7\u6298\u7B97\uFF0C\u4E0D\u8BA1\u5165\u9884\u7B97\uFF09\uFF1A\u4ECA\u65E5 ", money(spent.subscriptionToday ?? 0), " \xB7 \u672C\u6708 ", money(spent.subscriptionMonth ?? 0), "\uFF0C\u672C\u6708\u5171 ", spent.subscriptionRunsMonth, " \u6B21\u8BA2\u9605\u767B\u5F55\u8C03\u7528\u3002"), (spent.unknownToday > 0 || spent.unknownMonth > 0) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u672C\u6708\u6709 ", spent.unknownMonth, " \u6B21\u8C03\u7528\u7F3A\u5C11\u5355\u4EF7\u6216\u7528\u91CF\uFF0C\u672A\u8BA1\u5165\u91D1\u989D\u3002\u8BF7\u5728\u201C\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B\u201D\u4E2D\u8865\u9F50\u5355\u4EF7\u3002"), ledger?.budget?.exceeded && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, ledger.budget.message, " ", ledger.budget.action === "pause" ? "\u65B0\u7684\u6267\u884C\u4F1A\u5148\u6682\u505C\u5E76\u8BF7\u6C42\u786E\u8BA4\u3002" : "\u65B0\u7684\u6267\u884C\u4F1A\u5C1D\u8BD5\u81EA\u52A8\u964D\u7EA7\u4E3A\u201C\u7701\u94B1\u4F18\u5148\u201D\u3002"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, "\u8DEF\u7531\u65B9\u6848"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-segment", role: "group", "aria-label": "\u8DEF\u7531\u65B9\u6848" }, Object.values(ROUTING_PRESETS).map((item) => /* @__PURE__ */ import_react2.default.createElement("button", { key: item.id, type: "button", title: item.description, "aria-pressed": preset === item.id, disabled: !settings.writable, onClick: () => {
3926
3968
  void set("routingPreset", item.id);
3927
3969
  } }, item.label))), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, ROUTING_PRESETS[preset]?.description)), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-control-label", htmlFor: "mr-daily-budget" }, "\u6BCF\u65E5\u4E0A\u9650\uFF08USD\uFF0C0 \u4E3A\u4E0D\u9650\uFF09"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-inline" }, /* @__PURE__ */ import_react2.default.createElement("input", { className: "mr-input mr-budget", id: "mr-daily-budget", type: "number", min: "0", step: "0.5", placeholder: String(daily), value: dailyDraft, onChange: (event) => setDailyDraft(event.target.value) }), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !settings.writable || dailyDraft === "", onClick: () => {
3928
3970
  void saveLimit("dailyBudgetUsd", dailyDraft, setDailyDraft);
@@ -3952,22 +3994,22 @@ function DagView({ packages, renderNode, label = "\u5B50\u4EFB\u52A1\u4F9D\u8D56
3952
3994
  }))));
3953
3995
  }
3954
3996
  function ChannelText({ item }) {
3955
- if (!item.channel) return /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-pill" }, "\u5F85\u6267\u884C");
3997
+ if (!item.channel) return /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-pill" }, item.status === "running" ? "\u6267\u884C\u4E2D" : item.status === "interrupted" ? "\u6267\u884C\u4E2D\u65AD" : "\u5F85\u6267\u884C");
3956
3998
  return /* @__PURE__ */ import_react2.default.createElement("span", { className: item.channel === "official-cli" ? "mr-pill mr-pill-channel-ok" : "mr-pill" }, item.channel === "official-cli" ? `\u5B98\u65B9 CLI \xB7 ${item.toolId ?? ""}` : "\u6A21\u578B\u76EE\u5F55 API");
3957
3999
  }
3958
- function RunNode({ run, item, routes, allowReassign, busy, onRate, onRerun }) {
4000
+ function RunNode({ run, item, routes, allowReassign, busy, onRate, onRerun, ledger }) {
3959
4001
  const [target, setTarget] = import_react2.default.useState("");
3960
- if (item.status === "paused") return /* @__PURE__ */ import_react2.default.createElement(PausedNode, { run, item, busy, onRerun });
4002
+ const rerun = rerunSupport(run, ledger);
4003
+ if (item.status === "paused") return /* @__PURE__ */ import_react2.default.createElement(PausedNode, { run, item, busy, onRerun, rerun });
3961
4004
  const cost = packageCost(item);
3962
- const rerun = rerunSupport(run);
3963
4005
  const canRerun = rerun.supported && !item.ok && !busy;
3964
4006
  const others = routes.filter((route) => `${route.provider}/${route.model}` !== `${item.provider}/${item.model}`);
3965
- return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-route" }, item.provider, "/", item.model, item.reassigned ? "\uFF08\u5DF2\u6539\u6D3E\uFF09" : ""), item.manualAssignment && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u624B\u52A8\u5206\u914D \xB7 ", item.manualAssignment.kind === "tool" ? `\u5B98\u65B9\u5DE5\u5177 ${item.manualAssignment.toolId}\uFF08\u5382\u5546\u9ED8\u8BA4\u6A21\u578B\uFF09` : `\u6A21\u578B API ${item.manualAssignment.provider}/${item.manualAssignment.model}`, item.algorithmRecommendation?.provider ? ` \xB7 \u539F\u63A8\u8350 ${item.algorithmRecommendation.provider}/${item.algorithmRecommendation.model}` : ""), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react2.default.createElement(ChannelText, { item }), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u9884\u4F30 ", money(item.estimatedCost), " \xB7 \u5B9E\u9645 ", cost.budget, item.difficulty ? ` \xB7 \u96BE\u5EA6 ${BAND[item.difficulty] ?? item.difficulty}` : "")), cost.reference && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, cost.reference), item.actualModel && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "CLI \u56DE\u62A5\u6A21\u578B\uFF1A", item.actualModel), (item.billing || item.billingMode) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u8BA1\u8D39\uFF1A", BILLING_CHANNEL_LABEL[item.billing] ?? "\u2014", item.subscriptionRoute ? ` \xB7 \u5957\u9910\u8DEF\u7EBF ${item.subscriptionRoute.provider}/${item.subscriptionRoute.model}` : "", item.billingMode && item.billingMode !== "subscription-first" ? ` \xB7 ${BILLING_MODE_LABEL[item.billingMode] ?? item.billingMode}` : ""), billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-warn-text" }, "\u8BA1\u8D39\u5207\u6362\uFF1A", billingSwitchText(item)), item.fallback?.reason && item.fallback.reason !== billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u56DE\u9000\u539F\u56E0\uFF1A", item.fallback.reason), item.fallback?.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, "CLI \u539F\u59CB\u9519\u8BEF\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, item.fallback.error)), !item.ok && item.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, item.error), !item.ok && item.diagnostic && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "CLI \u8BCA\u65AD", Number.isInteger(item.exitCode) ? `\uFF08\u9000\u51FA\u7801 ${item.exitCode}\uFF09` : ""), /* @__PURE__ */ import_react2.default.createElement("pre", null, item.diagnostic)), item.review && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u5F3A\u6A21\u578B\u62BD\u67E5\uFF08", item.review.provider, "/", item.review.model, "\uFF09\uFF1A", item.review.score ? `${item.review.score}/5` : "\u672A\u8BC4\u5206", " ", item.review.summary), item.answer && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u67E5\u770B\u7ED3\u679C"), /* @__PURE__ */ import_react2.default.createElement("pre", null, item.answer, item.answerTruncated ? "\n\u2026\uFF08\u5DF2\u622A\u65AD\uFF09" : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-node-actions" }, item.ok && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", title: item.rating === 1 ? "\u518D\u6B21\u70B9\u51FB\u64A4\u56DE\u6709\u7528\u8BC4\u4EF7" : "\u8BC4\u4EF7\u6B64\u7ED3\u679C\u6709\u7528", "aria-pressed": item.rating === 1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "up")) }, "\u{1F44D} \u6709\u7528"), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", title: item.rating === -1 ? "\u518D\u6B21\u70B9\u51FB\u64A4\u56DE\u4E0D\u597D\u8BC4\u4EF7" : "\u8BC4\u4EF7\u6B64\u7ED3\u679C\u4E0D\u597D", "aria-pressed": item.rating === -1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "down")) }, "\u{1F44E} \u4E0D\u597D")), canRerun && /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-mini", type: "button", title: rerun.confirm || void 0, onClick: () => onRerun(run.id, item.id, null) }, run.kind === "tool" ? "\u91CD\u65B0\u6267\u884C\u6B64\u8C03\u7528" : rerun.writes ? "\u5728\u65B0\u5DE5\u4F5C\u533A\u7EED\u8DD1" : "\u91CD\u8DD1\u6B64\u6B65"), !rerun.supported && !item.ok && item.ran && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, rerun.reason), rerun.supported && rerun.reassign && !(rerun.writes && item.ok) && allowReassign && others.length > 0 && !busy && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-inline" }, /* @__PURE__ */ import_react2.default.createElement("select", { className: "mr-input mr-mini-select", "aria-label": "\u6539\u6D3E\u5230", value: target, onChange: (event) => setTarget(event.target.value) }, /* @__PURE__ */ import_react2.default.createElement("option", { value: "" }, "\u6539\u6D3E\u5230\u2026"), others.map((route) => /* @__PURE__ */ import_react2.default.createElement("option", { key: `${route.provider}/${route.model}`, value: `${route.provider}\0${route.model}` }, route.provider, "/", route.model))), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", disabled: !target, onClick: () => {
4007
+ return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-route" }, item.provider, "/", item.model, item.reassigned ? "\uFF08\u5DF2\u6539\u6D3E\uFF09" : ""), item.manualAssignment && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u624B\u52A8\u5206\u914D \xB7 ", item.manualAssignment.kind === "tool" ? `\u5B98\u65B9\u5DE5\u5177 ${item.manualAssignment.toolId}\uFF08\u5382\u5546\u9ED8\u8BA4\u6A21\u578B\uFF09` : `\u6A21\u578B API ${item.manualAssignment.provider}/${item.manualAssignment.model}`, item.algorithmRecommendation?.provider ? ` \xB7 \u539F\u63A8\u8350 ${item.algorithmRecommendation.provider}/${item.algorithmRecommendation.model}` : ""), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react2.default.createElement(ChannelText, { item }), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u9884\u4F30 ", money(item.estimatedCost), " \xB7 \u5B9E\u9645 ", cost.budget, item.difficulty ? ` \xB7 \u96BE\u5EA6 ${BAND[item.difficulty] ?? item.difficulty}` : "")), cost.reference && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, cost.reference), item.actualModel && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "CLI \u56DE\u62A5\u6A21\u578B\uFF1A", item.actualModel), (item.billing || item.billingMode) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u8BA1\u8D39\uFF1A", BILLING_CHANNEL_LABEL[item.billing] ?? "\u2014", item.subscriptionRoute ? ` \xB7 \u5957\u9910\u8DEF\u7EBF ${item.subscriptionRoute.provider}/${item.subscriptionRoute.model}` : "", item.billingMode && item.billingMode !== "subscription-first" ? ` \xB7 ${BILLING_MODE_LABEL[item.billingMode] ?? item.billingMode}` : ""), billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-warn-text" }, "\u8BA1\u8D39\u5207\u6362\uFF1A", billingSwitchText(item)), item.fallback?.reason && item.fallback.reason !== billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u56DE\u9000\u539F\u56E0\uFF1A", item.fallback.reason), item.fallback?.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, "CLI \u539F\u59CB\u9519\u8BEF\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, item.fallback.error)), !item.ok && item.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, item.error), !item.ok && item.diagnostic && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "CLI \u8BCA\u65AD", Number.isInteger(item.exitCode) ? `\uFF08\u9000\u51FA\u7801 ${item.exitCode}\uFF09` : ""), /* @__PURE__ */ import_react2.default.createElement("pre", null, item.diagnostic)), item.review && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u5F3A\u6A21\u578B\u62BD\u67E5\uFF08", item.review.provider, "/", item.review.model, "\uFF09\uFF1A", item.review.score ? `${item.review.score}/5` : "\u672A\u8BC4\u5206", " ", item.review.summary), item.answer && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u67E5\u770B\u7ED3\u679C"), /* @__PURE__ */ import_react2.default.createElement("pre", null, item.answer, item.answerTruncated ? "\n\u2026\uFF08\u5DF2\u622A\u65AD\uFF09" : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-node-actions" }, item.ok && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", title: item.rating === 1 ? "\u518D\u6B21\u70B9\u51FB\u64A4\u56DE\u6709\u7528\u8BC4\u4EF7" : "\u8BC4\u4EF7\u6B64\u7ED3\u679C\u6709\u7528", "aria-pressed": item.rating === 1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "up")) }, "\u{1F44D} \u6709\u7528"), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", title: item.rating === -1 ? "\u518D\u6B21\u70B9\u51FB\u64A4\u56DE\u4E0D\u597D\u8BC4\u4EF7" : "\u8BC4\u4EF7\u6B64\u7ED3\u679C\u4E0D\u597D", "aria-pressed": item.rating === -1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "down")) }, "\u{1F44E} \u4E0D\u597D")), canRerun && /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-mini", type: "button", title: rerun.confirm || void 0, onClick: () => onRerun(run.id, item.id, null) }, run.kind === "tool" ? "\u91CD\u65B0\u6267\u884C\u6B64\u8C03\u7528" : rerun.writes ? "\u5728\u65B0\u5DE5\u4F5C\u533A\u7EED\u8DD1" : "\u91CD\u8DD1\u6B64\u6B65"), !rerun.supported && !item.ok && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, rerun.reason), rerun.supported && rerun.reassign && !(rerun.writes && item.ok) && allowReassign && others.length > 0 && !busy && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-inline" }, /* @__PURE__ */ import_react2.default.createElement("select", { className: "mr-input mr-mini-select", "aria-label": "\u6539\u6D3E\u5230", value: target, onChange: (event) => setTarget(event.target.value) }, /* @__PURE__ */ import_react2.default.createElement("option", { value: "" }, "\u6539\u6D3E\u5230\u2026"), others.map((route) => /* @__PURE__ */ import_react2.default.createElement("option", { key: `${route.provider}/${route.model}`, value: `${route.provider}\0${route.model}` }, route.provider, "/", route.model))), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", disabled: !target, onClick: () => {
3966
4008
  const [provider, model] = target.split("\0");
3967
4009
  onRerun(run.id, item.id, { provider, model });
3968
4010
  } }, "\u6539\u6D3E\u5E76\u91CD\u8DD1"))));
3969
4011
  }
3970
- function PausedNode({ run, item, busy, onRerun }) {
4012
+ function PausedNode({ run, item, busy, onRerun, rerun }) {
3971
4013
  const pause = item.pause ?? {};
3972
4014
  return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-route" }, item.provider, "/", item.model), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-pill mr-pill-warn" }, "\u7B49\u5F85\u786E\u8BA4"), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u8BA2\u9605\u8C03\u7528\u5931\u8D25\uFF0C\u672A\u81EA\u52A8\u6539\u7528 API Key")), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-warn-text" }, pause.reason ?? item.error), pause.detail && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, "\u771F\u5B9E\u9519\u8BEF\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, pause.detail)), pause.loginRequired && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u770B\u8D77\u6765\u662F\u767B\u5F55\u95EE\u9898\uFF1A\u8BF7\u5148\u5728\u7EC8\u7AEF\u91CD\u65B0\u767B\u5F55\u8BE5 CLI\uFF0C\u518D\u70B9\u201C\u91CD\u8BD5\u8BA2\u9605\u201D\u3002"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-node-actions" }, SUBSCRIPTION_CHOICE_BUTTONS.map(([choice, label, secondary]) => /* @__PURE__ */ import_react2.default.createElement(
3973
4015
  "button",
@@ -3975,20 +4017,22 @@ function PausedNode({ run, item, busy, onRerun }) {
3975
4017
  key: choice,
3976
4018
  className: `mr-button mr-mini${secondary ? " mr-button-secondary" : ""}`,
3977
4019
  type: "button",
3978
- disabled: busy,
4020
+ disabled: busy || !rerun.supported,
3979
4021
  onClick: () => onRerun(run.id, item.id, null, choice)
3980
4022
  },
3981
4023
  label
3982
- ))));
4024
+ ))), !rerun.supported && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, rerun.reason));
3983
4025
  }
3984
4026
  function RunHistoryCard({ ledger, routes, onRefresh, onRate, onRerun, busy, error }) {
3985
4027
  const runs = ledger?.runs ?? [];
3986
4028
  const [openId, setOpenId] = import_react2.default.useState(null);
3987
4029
  const current = runs.find((run) => run.id === openId) ?? runs[0];
4030
+ const support = rerunSupport(current, ledger);
4031
+ const unresolved = ["running", "interrupted"].includes(current?.status) || (ledger?.reservations ?? []).some((item) => item.runId === current?.id && ["active", "interrupted"].includes(item.status));
3988
4032
  const totals = runTotals(current);
3989
4033
  const prior = priorAttemptTotals(current);
3990
4034
  const unknownCalls = prior.unknownCalls + [...current?.packages ?? [], ...current?.reviews ?? []].filter((item) => item.ran && item.billing !== "subscription" && !Number.isFinite(item.costUsd)).length;
3991
- return /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card mr-results", "aria-label": "\u6267\u884C\u8BB0\u5F55" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react2.default.createElement("div", null, /* @__PURE__ */ import_react2.default.createElement("h2", { className: "mr-card-title" }, "\u6267\u884C\u8BB0\u5F55\u4E0E\u5B50\u4EFB\u52A1"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u67E5\u770B\u6A21\u578B\u5206\u914D\u3001\u9010\u6B65\u7ED3\u679C\u4E0E\u8D39\u7528\u3002\u5931\u8D25\u6B65\u9AA4\u53EF\u91CD\u8DD1\u6216\u6539\u6D3E\uFF1B\u5DF2\u5B8C\u6210\u7684\u4E0A\u6E38\u4FDD\u6301\u539F\u7ED3\u679C\u3002")), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: busy, onClick: onRefresh }, "\u5237\u65B0")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-body" }, error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, error), !ledger && !error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u6267\u884C\u8BB0\u5F55\u2026"), ledger && runs.length === 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-empty" }, "\u8FD8\u6CA1\u6709\u6267\u884C\u8BB0\u5F55\u3002\u53EF\u5728\u4E0A\u65B9\u201C\u5728\u5DE5\u4F5C\u53F0\u6267\u884C\u201D\u4E2D\u9884\u89C8\u5E76\u6267\u884C\uFF0C\u6216\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u8C03\u7528 model_router_execute\u3001model_router_team_execute\u3001model_router_tool_run\uFF0C\u8FD9\u91CC\u4F1A\u663E\u793A\u51B3\u7B56\u548C\u7ED3\u679C\u3002"), runs.length > 0 && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-label", htmlFor: "mr-run-select" }, "\u9009\u62E9\u8BB0\u5F55"), /* @__PURE__ */ import_react2.default.createElement("select", { className: "mr-input", id: "mr-run-select", value: current?.id ?? "", onChange: (event) => setOpenId(event.target.value) }, runs.map((run) => /* @__PURE__ */ import_react2.default.createElement("option", { key: run.id, value: run.id }, new Date(run.createdAt).toLocaleString(), " \xB7 ", RUN_KIND_LABEL[run.kind ?? "assign"] ?? run.kind, " \xB7 ", RUN_STATUS_LABEL[run.status] ?? run.status, " \xB7 ", run.task.slice(0, 40)))), current && /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-run" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-result-grid" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u65B9\u6848"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, ROUTING_PRESETS[current.preset]?.label ?? current.preset, current.budget?.downgraded ? "\uFF08\u8D85\u9884\u7B97\u81EA\u52A8\u964D\u7EA7\uFF09" : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u96BE\u5EA6"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, BAND[current.decision?.complexity?.band] ?? "\u2014", current.decision?.complexity?.value !== null && current.decision?.complexity?.value !== void 0 ? ` \xB7 ${current.decision.complexity.value}` : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u9884\u4F30 / ", unknownCalls ? "\u5DF2\u77E5\u5B9E\u9645" : "\u5B9E\u9645", "\uFF08\u8BA1\u5165\u9884\u7B97\uFF09"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, money(current.decision?.estimatedCost), " / ", money(totals.budgetUsd))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u7C7B\u578B"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, RUN_KIND_LABEL[current.kind ?? "assign"] ?? current.kind, current.kind === "team" || current.kind === "tool" ? ` \xB7 ${current.executionMode === "workspace-write" ? "\u53EF\u7F16\u8F91" : "\u53EA\u8BFB"}` : ""))), totals.subscription && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u8BA2\u9605\u53C2\u8003\u8D39\u7528\uFF08\u6309 API \u4EF7\u6298\u7B97\uFF0C\u4E0D\u8BA1\u5165\u9884\u7B97\uFF09\uFF1A", money(totals.referenceUsd)), unknownCalls > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u53E6\u6709 ", unknownCalls, " \u6B21\u8C03\u7528\u8D39\u7528\u672A\u77E5\uFF0C\u672A\u8BA1\u5165\u4E0A\u65B9\u91D1\u989D\u3002"), (prior.budgetUsd > 0 || prior.subscriptionRuns > 0 || prior.unknownCalls > 0) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u7D2F\u8BA1\u5305\u542B\u6B64\u524D\u91CD\u8DD1\u5C1D\u8BD5\uFF1AAPI ", money(prior.budgetUsd), " \xB7 \u8BA2\u9605\u53C2\u8003 ", money(prior.referenceUsd), prior.unknownCalls > 0 ? ` \xB7 \u8D39\u7528\u672A\u77E5 ${prior.unknownCalls} \u6B21` : "", "\u3002\u4E0B\u65B9\u8282\u70B9\u663E\u793A\u6700\u8FD1\u4E00\u6B21\u7ED3\u679C\u3002"), current.kind === "team" && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u6267\u884C\u73AF\u5883\uFF1A", current.executionEnvironment === "cli-native" ? "\u5382\u5546 CLI \u6B63\u5E38\u73AF\u5883 \xB7 \u5F53\u524D\u7528\u6237\u6743\u9650 \xB7 \u65E0 Harness \u8FDB\u7A0B\u6C99\u7BB1" : current.executionEnvironment === "harness" ? "Harness \u53D7\u9650\u73AF\u5883" : "\u5386\u53F2\u8BB0\u5F55\u672A\u8BB0\u5F55\u6267\u884C\u73AF\u5883"), current.isolatedWorkspace && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u72EC\u7ACB\u5DE5\u4F5C\u533A\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, current.isolatedWorkspace)), current.rerunOf && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u91CD\u65B0\u6267\u884C\u81EA\u8FD0\u884C ", current.rerunOf.slice(0, 8), "\u3002"), current.decision?.reason && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u8DEF\u7531\u539F\u56E0\uFF1A", current.decision.reason), /* @__PURE__ */ import_react2.default.createElement(DagView, { packages: current.packages, renderNode: (item) => /* @__PURE__ */ import_react2.default.createElement(RunNode, { run: current, item, routes, allowReassign: ledger?.settings?.allowManualReassign !== false, busy, onRate, onRerun }) })))));
4035
+ return /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card mr-results", "aria-label": "\u6267\u884C\u8BB0\u5F55" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react2.default.createElement("div", null, /* @__PURE__ */ import_react2.default.createElement("h2", { className: "mr-card-title" }, "\u6267\u884C\u8BB0\u5F55\u4E0E\u5B50\u4EFB\u52A1"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u67E5\u770B\u6A21\u578B\u5206\u914D\u3001\u9010\u6B65\u7ED3\u679C\u4E0E\u8D39\u7528\u3002\u5DF2\u7ED3\u675F\u4EFB\u52A1\u7684\u5931\u8D25\u6B65\u9AA4\u53EF\u91CD\u8DD1\u6216\u6539\u6D3E\uFF1B\u5DF2\u5B8C\u6210\u7684\u4E0A\u6E38\u4FDD\u6301\u539F\u7ED3\u679C\u3002")), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: busy, onClick: onRefresh }, "\u5237\u65B0")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-body" }, error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, error), !ledger && !error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u6267\u884C\u8BB0\u5F55\u2026"), ledger && runs.length === 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-empty" }, "\u8FD8\u6CA1\u6709\u6267\u884C\u8BB0\u5F55\u3002\u53EF\u5728\u4E0A\u65B9\u201C\u5728\u5DE5\u4F5C\u53F0\u6267\u884C\u201D\u4E2D\u9884\u89C8\u5E76\u6267\u884C\uFF0C\u6216\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u8C03\u7528 model_router_execute\u3001model_router_team_execute\u3001model_router_tool_run\uFF0C\u8FD9\u91CC\u4F1A\u663E\u793A\u51B3\u7B56\u548C\u7ED3\u679C\u3002"), runs.length > 0 && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-label", htmlFor: "mr-run-select" }, "\u9009\u62E9\u8BB0\u5F55"), /* @__PURE__ */ import_react2.default.createElement("select", { className: "mr-input", id: "mr-run-select", value: current?.id ?? "", onChange: (event) => setOpenId(event.target.value) }, runs.map((run) => /* @__PURE__ */ import_react2.default.createElement("option", { key: run.id, value: run.id }, new Date(run.createdAt).toLocaleString(), " \xB7 ", RUN_KIND_LABEL[run.kind ?? "assign"] ?? run.kind, " \xB7 ", RUN_STATUS_LABEL[run.status] ?? run.status, " \xB7 ", run.task.slice(0, 40)))), current && /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-run" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-result-grid" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u65B9\u6848"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, ROUTING_PRESETS[current.preset]?.label ?? current.preset, current.budget?.downgraded ? "\uFF08\u8D85\u9884\u7B97\u81EA\u52A8\u964D\u7EA7\uFF09" : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u96BE\u5EA6"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, BAND[current.decision?.complexity?.band] ?? "\u2014", current.decision?.complexity?.value !== null && current.decision?.complexity?.value !== void 0 ? ` \xB7 ${current.decision.complexity.value}` : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u9884\u4F30 / ", unknownCalls ? "\u5DF2\u77E5\u5B9E\u9645" : "\u5B9E\u9645", "\uFF08\u8BA1\u5165\u9884\u7B97\uFF09"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, money(current.decision?.estimatedCost), " / ", money(totals.budgetUsd))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u7C7B\u578B"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, RUN_KIND_LABEL[current.kind ?? "assign"] ?? current.kind, current.kind === "team" || current.kind === "tool" ? ` \xB7 ${current.executionMode === "workspace-write" ? "\u53EF\u7F16\u8F91" : "\u53EA\u8BFB"}` : ""))), totals.subscription && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u8BA2\u9605\u53C2\u8003\u8D39\u7528\uFF08\u6309 API \u4EF7\u6298\u7B97\uFF0C\u4E0D\u8BA1\u5165\u9884\u7B97\uFF09\uFF1A", money(totals.referenceUsd)), unknownCalls > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u53E6\u6709 ", unknownCalls, " \u6B21\u8C03\u7528\u8D39\u7528\u672A\u77E5\uFF0C\u672A\u8BA1\u5165\u4E0A\u65B9\u91D1\u989D\u3002"), (prior.budgetUsd > 0 || prior.subscriptionRuns > 0 || prior.unknownCalls > 0) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u7D2F\u8BA1\u5305\u542B\u6B64\u524D\u91CD\u8DD1\u5C1D\u8BD5\uFF1AAPI ", money(prior.budgetUsd), " \xB7 \u8BA2\u9605\u53C2\u8003 ", money(prior.referenceUsd), prior.unknownCalls > 0 ? ` \xB7 \u8D39\u7528\u672A\u77E5 ${prior.unknownCalls} \u6B21` : "", "\u3002\u4E0B\u65B9\u8282\u70B9\u663E\u793A\u6700\u8FD1\u4E00\u6B21\u7ED3\u679C\u3002"), current.kind === "team" && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u6267\u884C\u73AF\u5883\uFF1A", current.executionEnvironment === "cli-native" ? "\u5382\u5546 CLI \u6B63\u5E38\u73AF\u5883 \xB7 \u5F53\u524D\u7528\u6237\u6743\u9650 \xB7 \u65E0 Harness \u8FDB\u7A0B\u6C99\u7BB1" : current.executionEnvironment === "harness" ? "Harness \u53D7\u9650\u73AF\u5883" : "\u5386\u53F2\u8BB0\u5F55\u672A\u8BB0\u5F55\u6267\u884C\u73AF\u5883"), current.isolatedWorkspace && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u72EC\u7ACB\u5DE5\u4F5C\u533A\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, current.isolatedWorkspace)), current.rerunOf && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u91CD\u65B0\u6267\u884C\u81EA\u8FD0\u884C ", current.rerunOf.slice(0, 8), "\u3002"), current.decision?.reason && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u8DEF\u7531\u539F\u56E0\uFF1A", current.decision.reason), !support.supported && unresolved && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption mr-warn-text" }, support.reason), /* @__PURE__ */ import_react2.default.createElement(DagView, { packages: current.packages, renderNode: (item) => /* @__PURE__ */ import_react2.default.createElement(RunNode, { run: current, item, routes, ledger, allowReassign: ledger?.settings?.allowManualReassign !== false, busy, onRate, onRerun }) })))));
3992
4036
  }
3993
4037
  function BillingCard({ billing, error, onRefresh, refreshing }) {
3994
4038
  const rows = billingRows(billing);
@@ -4030,6 +4074,26 @@ var STAGE_TEXT = Object.freeze({
4030
4074
  });
4031
4075
  var ACTIVE_JOB_KEY = "dsh-model-router:active-run-job";
4032
4076
  var isJobSnapshot = (value) => Boolean(text2(value?.jobId) && JOB_STATUSES.has(value.status));
4077
+ var REMOTE_WAIT_MS = 15e3;
4078
+ async function waitForRemote(operation, controllers) {
4079
+ const controller = new AbortController();
4080
+ controllers.add(controller);
4081
+ let timer;
4082
+ try {
4083
+ return await new Promise((resolve, reject) => {
4084
+ controller.signal.onabort = () => {
4085
+ clearTimeout(timer);
4086
+ reject(new Error("\u5DE5\u4F5C\u53F0\u8BF7\u6C42\u7B49\u5F85\u8D85\u65F6\uFF0C\u8BF7\u5728\u8FDE\u63A5\u6062\u590D\u540E\u91CD\u8BD5\u3002"));
4087
+ };
4088
+ timer = setTimeout(() => controller.abort(), REMOTE_WAIT_MS);
4089
+ Promise.resolve(operation(controller.signal)).then(resolve, reject);
4090
+ });
4091
+ } finally {
4092
+ clearTimeout(timer);
4093
+ controller.signal.onabort = null;
4094
+ controllers.delete(controller);
4095
+ }
4096
+ }
4033
4097
  function savedJob() {
4034
4098
  try {
4035
4099
  return typeof sessionStorage === "undefined" ? "" : text2(sessionStorage.getItem(ACTIVE_JOB_KEY));
@@ -4084,6 +4148,7 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
4084
4148
  const launchSequence = import_react3.default.useRef(0);
4085
4149
  const launching = import_react3.default.useRef(false);
4086
4150
  const awaitingLaunch = import_react3.default.useRef(null);
4151
+ const pendingRemotes = import_react3.default.useRef(/* @__PURE__ */ new Set());
4087
4152
  const onFinished = import_react3.default.useRef(onStarted);
4088
4153
  onFinished.current = onStarted;
4089
4154
  const inputSignature = JSON.stringify([task, mode, directRoute?.provider, directRoute?.model, budgetUsd, runPreset, workspace, lastWorkspace, planningRevision, disabledReason, runExecutor, runMode, runEnvironment, assignmentMode, packagePlanKey2, packageAssignments]);
@@ -4140,6 +4205,8 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
4140
4205
  }
4141
4206
  return () => {
4142
4207
  mounted.current = false;
4208
+ for (const controller of pendingRemotes.current) controller.abort();
4209
+ pendingRemotes.current.clear();
4143
4210
  launchListeners.delete(receiveLaunch);
4144
4211
  pendingRequest.current += 1;
4145
4212
  activeRun.current = null;
@@ -4217,7 +4284,7 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
4217
4284
  if (disposed || activeRun.current !== active || active.terminal) return;
4218
4285
  const sequence = ++active.requestSequence;
4219
4286
  try {
4220
- const value = unwrapRemote(await runStatus({ jobId: runningJobId }), "\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u6267\u884C\u8FDB\u5EA6\u3002");
4287
+ const value = unwrapRemote(await waitForRemote((signal) => runStatus({ jobId: runningJobId }, signal), pendingRemotes.current), "\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u6267\u884C\u8FDB\u5EA6\u3002");
4221
4288
  if (disposed) return;
4222
4289
  if (!isJobSnapshot(value) || value.jobId !== runningJobId) throw new Error("\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u6267\u884C\u8FDB\u5EA6\u3002");
4223
4290
  acceptSnapshot(value, active.token, sequence);
@@ -4281,7 +4348,7 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
4281
4348
  const signature2 = inputSignature;
4282
4349
  setPhase({ kind: "previewing" });
4283
4350
  try {
4284
- const value = unwrapRemote(await previewRun(snapshot), "\u6267\u884C\u9884\u89C8\u5931\u8D25\u3002");
4351
+ const value = unwrapRemote(await waitForRemote((signal) => previewRun(snapshot, signal), pendingRemotes.current), "\u6267\u884C\u9884\u89C8\u5931\u8D25\u3002");
4285
4352
  if (mounted.current && current === pendingRequest.current && signature2 === latestSignature.current) setPhase({ kind: "preview", value, request: snapshot, signature: signature2 });
4286
4353
  } catch (error) {
4287
4354
  if (mounted.current && current === pendingRequest.current && signature2 === latestSignature.current) setPhase({ kind: "error", message: text2(error?.message) || "\u6267\u884C\u9884\u89C8\u5931\u8D25\u3002" });
@@ -4342,7 +4409,7 @@ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger
4342
4409
  const sequence = ++active.requestSequence;
4343
4410
  setPhase((previous) => previous.kind === "running" ? { ...previous, cancelPending: true, cancelError: "" } : previous);
4344
4411
  try {
4345
- const value = unwrapRemote(await cancelRun({ jobId: active.jobId }), "\u53D6\u6D88\u8BF7\u6C42\u672A\u786E\u8BA4\u3002");
4412
+ const value = unwrapRemote(await waitForRemote((signal) => cancelRun({ jobId: active.jobId }, signal), pendingRemotes.current), "\u53D6\u6D88\u8BF7\u6C42\u672A\u786E\u8BA4\u3002");
4346
4413
  if (!isJobSnapshot(value) || value.jobId !== active.jobId) throw new Error("\u53D6\u6D88\u8BF7\u6C42\u672A\u786E\u8BA4\u3002");
4347
4414
  acceptSnapshot(value, active.token, sequence, true);
4348
4415
  } catch {
@@ -13863,7 +13930,7 @@ var xterm_default = `/**
13863
13930
  `;
13864
13931
 
13865
13932
  // .dsh-plugin/client/host-version.mjs
13866
- var ROUTER_CLIENT_VERSION = true ? "0.23.0" : "";
13933
+ var ROUTER_CLIENT_VERSION = true ? "0.24.0" : "";
13867
13934
  var STALE_HOST_MESSAGE = "\u63D2\u4EF6\u540E\u53F0\u7248\u672C\u8F83\u65E7\uFF0C\u8BF7\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u542F Harness\uFF08\u5305\u62EC\u6258\u76D8\u56FE\u6807\uFF09\u540E\u518D\u4F7F\u7528\u3002";
13868
13935
  function isMissingRemoteMethod(message) {
13869
13936
  const value = String(message ?? "");
@@ -15357,6 +15424,11 @@ function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResu
15357
15424
  if (mutationBusy.current) return;
15358
15425
  const run = ledger.value?.runs?.find((item2) => item2.id === runId);
15359
15426
  const item = run?.packages?.find((entry) => entry.id === packageId);
15427
+ const support = rerunSupport(run, ledger.value);
15428
+ if (!support.supported) {
15429
+ setLedger((previous) => ({ ...previous, error: support.reason }));
15430
+ return;
15431
+ }
15360
15432
  const reasons = rerunConfirmations({ run, item, override, choice, ledger: ledger.value, health: health.report, toolFor: toolForProvider, headlessIds: HEADLESS_TOOLS });
15361
15433
  if (reasons.length && !window.confirm(reasons.length === 1 ? `${reasons[0].text}
15362
15434
  \u7EE7\u7EED\u5417\uFF1F` : `\u91CD\u8DD1\u524D\u9700\u8981\u786E\u8BA4\u4EE5\u4E0B ${reasons.length} \u9879\uFF1A
@@ -15572,7 +15644,7 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
15572
15644
  }
15573
15645
  };
15574
15646
  const summary = healthSummary(workbench.health.report?.tools);
15575
- return /* @__PURE__ */ import_react5.default.createElement("main", { className: "mr-workspace" }, /* @__PURE__ */ import_react5.default.createElement("style", null, router_main_default), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-shell" }, /* @__PURE__ */ import_react5.default.createElement("header", { className: "mr-header" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-eyebrow" }, "Model Router \xB7 DeepSeek Harness"), /* @__PURE__ */ import_react5.default.createElement("h1", { className: "mr-title" }, "\u6A21\u578B\u8DEF\u7531\u5DE5\u4F5C\u53F0"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-subtitle" }, "\u628A\u4EFB\u52A1\u4EA4\u7ED9\u5408\u9002\u7684\u6A21\u578B\u3002\u4ECE\u672C\u5730\u89C4\u5212\uFF0C\u5230\u53EF\u786E\u8BA4\u7684\u6267\u884C\u3002")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-status" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: `mr-status-dot ${catalogState.status === "loading" ? "loading" : catalogState.status === "error" ? "error" : ""}` }), catalogState.status === "ready" ? `${providerCount} \u4E2A\u4F9B\u5E94\u5546 \xB7 ${routes.length} \u6761\u8DEF\u7EBF` : catalogState.status === "loading" ? "\u6B63\u5728\u8BFB\u53D6\u6A21\u578B\u76EE\u5F55" : "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-overview", "aria-label": "\u5DE5\u4F5C\u53F0\u6982\u89C8" }, /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "mr-overview-item", onClick: () => selectView("models") }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-label" }, "\u6A21\u578B\u8DEF\u7EBF"), /* @__PURE__ */ import_react5.default.createElement("strong", null, catalogState.status === "ready" ? routes.length : "\u2014"), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-detail" }, catalogState.status === "ready" ? `${providerCount} \u4E2A\u4F9B\u5E94\u5546 \xB7 \u914D\u7F6E\u4EF7\u683C\u4E0E\u80FD\u529B \u2192` : "\u7B49\u5F85\u76EE\u5F55\u52A0\u8F7D")), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "mr-overview-item", onClick: () => selectView("tools") }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-label" }, "\u5B98\u65B9\u5DE5\u5177"), /* @__PURE__ */ import_react5.default.createElement("strong", null, workbench.health.report ? summary.installed : "\u2014", /* @__PURE__ */ import_react5.default.createElement("small", null, " / ", OFFICIAL_TOOLS.length)), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-detail" }, workbench.health.report ? `${summary.ready} \u4E2A\u5DF2\u767B\u5F55 \xB7 \u67E5\u770B\u4F53\u68C0 \u2192` : "\u67E5\u770B\u5B89\u88C5\u4E0E\u767B\u5F55\u72B6\u6001 \u2192")), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "mr-overview-item", onClick: () => selectView("controls") }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-label" }, "\u4ECA\u65E5 API \u8D39\u7528"), /* @__PURE__ */ import_react5.default.createElement("strong", null, workbench.ledger.value ? money2(workbench.ledger.value.spent?.today ?? 0) : "\u2014"), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-detail" }, "\u672C\u673A\u8BB0\u5F55\u4F30\u7B97 \xB7 \u67E5\u770B\u9884\u7B97 \u2192"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-workspace-tabs", role: "tablist", "aria-label": "\u5DE5\u4F5C\u53F0\u529F\u80FD" }, WORKSPACE_VIEWS.map((item, index) => /* @__PURE__ */ import_react5.default.createElement("button", { key: item.id, ref: (element) => {
15647
+ return /* @__PURE__ */ import_react5.default.createElement("main", { className: "mr-workspace" }, /* @__PURE__ */ import_react5.default.createElement("style", null, router_main_default), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-shell" }, /* @__PURE__ */ import_react5.default.createElement("header", { className: "mr-header" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-eyebrow" }, "Model Router \xB7 DeepSeek Harness"), /* @__PURE__ */ import_react5.default.createElement("h1", { className: "mr-title" }, "\u6A21\u578B\u8DEF\u7531\u5DE5\u4F5C\u53F0"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-subtitle" }, "\u628A\u4EFB\u52A1\u4EA4\u7ED9\u5408\u9002\u7684\u6A21\u578B\u3002\u4ECE\u672C\u5730\u89C4\u5212\uFF0C\u5230\u53EF\u786E\u8BA4\u7684\u6267\u884C\u3002")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-status" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: `mr-status-dot ${catalogState.status === "loading" ? "loading" : catalogState.status === "error" ? "error" : ""}` }), catalogState.status === "ready" ? `${providerCount} \u4E2A\u4F9B\u5E94\u5546 \xB7 ${routes.length} \u6761\u8DEF\u7EBF` : catalogState.status === "loading" ? "\u6B63\u5728\u8BFB\u53D6\u6A21\u578B\u76EE\u5F55" : "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-overview", "aria-label": "\u5DE5\u4F5C\u53F0\u6982\u89C8" }, /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "mr-overview-item", onClick: () => selectView("models") }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-label" }, "\u6A21\u578B\u8DEF\u7EBF"), /* @__PURE__ */ import_react5.default.createElement("strong", null, catalogState.status === "ready" ? routes.length : "\u2014"), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-detail" }, catalogState.status === "ready" ? `${providerCount} \u4E2A\u4F9B\u5E94\u5546 \xB7 \u914D\u7F6E\u4EF7\u683C\u4E0E\u80FD\u529B \u2192` : "\u7B49\u5F85\u76EE\u5F55\u52A0\u8F7D")), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "mr-overview-item", onClick: () => selectView("tools") }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-label" }, "\u5B98\u65B9\u5DE5\u5177"), /* @__PURE__ */ import_react5.default.createElement("strong", null, workbench.health.report ? summary.installed : "\u2014", /* @__PURE__ */ import_react5.default.createElement("small", null, " / ", OFFICIAL_TOOLS.length)), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-detail" }, workbench.health.report ? `${summary.ready} \u4E2A\u5DF2\u767B\u5F55 \xB7 \u67E5\u770B\u4F53\u68C0 \u2192` : "\u67E5\u770B\u5B89\u88C5\u4E0E\u767B\u5F55\u72B6\u6001 \u2192")), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "mr-overview-item", onClick: () => selectView("controls") }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-label" }, "\u4ECA\u65E5\u5DF2\u53D1\u751F API \u8D39\u7528"), /* @__PURE__ */ import_react5.default.createElement("strong", null, workbench.ledger.value ? money2(workbench.ledger.value.spent?.today ?? 0) : "\u2014"), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-overview-detail" }, "\u9884\u5360 ", money2(reservationSummary(workbench.ledger.value).today), " \xB7 \u67E5\u770B\u9884\u7B97 \u2192"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-workspace-tabs", role: "tablist", "aria-label": "\u5DE5\u4F5C\u53F0\u529F\u80FD" }, WORKSPACE_VIEWS.map((item, index) => /* @__PURE__ */ import_react5.default.createElement("button", { key: item.id, ref: (element) => {
15576
15648
  tabRefs.current[item.id] = element;
15577
15649
  }, type: "button", role: "tab", id: `mr-tab-${item.id}`, "aria-selected": view === item.id, "aria-controls": `mr-panel-${item.id}`, tabIndex: view === item.id ? 0 : -1, onKeyDown: (event) => navigateTabs(event, index), onClick: () => setView(item.id) }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-tab-number", "aria-hidden": "true" }, item.number), item.label))), staleHostNotice({ hostVersion: toolProbes?.hostVersion, loaded: Boolean(toolProbes?.probes?.length) }) && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-error", role: "alert" }, staleHostNotice({ hostVersion: toolProbes?.hostVersion })), (workbench.health.report?.notices ?? []).map((notice) => /* @__PURE__ */ import_react5.default.createElement("div", { key: `${notice.kind}-${notice.at}`, className: "mr-error", role: "alert" }, notice.message)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view mr-stack", role: "tabpanel", id: "mr-panel-plan", "aria-labelledby": "mr-tab-plan", hidden: view !== "plan" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-grid mr-planning-grid" }, /* @__PURE__ */ import_react5.default.createElement("section", { className: "mr-card", "aria-label": "\u4EFB\u52A1\u89C4\u5212" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("h2", { className: "mr-card-title" }, "\u4EFB\u52A1\u89C4\u5212"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-card-copy" }, "\u5199\u6E05\u76EE\u6807\u4E0E\u9A8C\u6536\u6807\u51C6\uFF0C\u5148\u751F\u6210\u672C\u5730\u5EFA\u8BAE\uFF0C\u518D\u9884\u89C8\u6267\u884C\u3002")), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-pill" }, "\u672C\u5730\u89C4\u5212 \xB7 \u4E0D\u6D88\u8017 token")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react5.default.createElement("label", { className: "mr-label", htmlFor: "mr-task" }, "\u4EFB\u52A1\u63CF\u8FF0"), /* @__PURE__ */ import_react5.default.createElement("textarea", { className: "mr-textarea", id: "mr-task", value: task, onChange: (event) => {
15578
15650
  setTask(event.target.value);
@@ -15874,7 +15946,7 @@ var terminalWriteCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#TerminalW
15874
15946
  var terminalResizeCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#TerminalResize`, parseTerminalResize);
15875
15947
  var terminalStopCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#TerminalStop`, parseTerminalStop);
15876
15948
  var runRequestCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#RunRequest`, parseRunRequest);
15877
- function descriptor(method, parameters, result) {
15949
+ function descriptor(method, parameters, result, cancellable = false) {
15878
15950
  return Object.freeze({
15879
15951
  id: `${OFFICIAL_TOOLS_REMOTE_PACKAGE}#${OFFICIAL_TOOLS_REMOTE_NAMESPACE}/${method}`,
15880
15952
  service: OFFICIAL_TOOLS_REMOTE_NAMESPACE,
@@ -15882,7 +15954,8 @@ function descriptor(method, parameters, result) {
15882
15954
  method,
15883
15955
  invocation: { kind: "direct" },
15884
15956
  parameters,
15885
- result
15957
+ result,
15958
+ ...cancellable ? { cancellation: { parameter: "signal" } } : {}
15886
15959
  });
15887
15960
  }
15888
15961
  var toolIdParameter = Object.freeze({
@@ -15908,10 +15981,10 @@ var OFFICIAL_TOOLS_REMOTE_DESCRIPTORS = Object.freeze([
15908
15981
  descriptor("rerunStep", [jsonParameter("request", rerunRequestCodec)], anyObjectCodec("RerunResult")),
15909
15982
  descriptor("boundaries", [], anyObjectCodec("SecurityBoundaries")),
15910
15983
  // Workbench "start a run": plan preview with cost estimate and confirmation reasons, then execute.
15911
- descriptor("previewRun", [jsonParameter("request", runRequestCodec)], anyObjectCodec("RunPreview")),
15984
+ descriptor("previewRun", [jsonParameter("request", runRequestCodec)], anyObjectCodec("RunPreview"), true),
15912
15985
  descriptor("startRun", [jsonParameter("request", runRequestCodec)], anyObjectCodec("RunStarted")),
15913
- descriptor("runStatus", [jsonParameter("request", runJobRequestCodec)], anyObjectCodec("RunJobStatus")),
15914
- descriptor("cancelRun", [jsonParameter("request", runJobRequestCodec)], anyObjectCodec("RunJobStatus")),
15986
+ descriptor("runStatus", [jsonParameter("request", runJobRequestCodec)], anyObjectCodec("RunJobStatus"), true),
15987
+ descriptor("cancelRun", [jsonParameter("request", runJobRequestCodec)], anyObjectCodec("RunJobStatus"), true),
15915
15988
  // Workbench "官方工具终端": interactive shell / fixed official CLI sessions.
15916
15989
  // Output streams through long-poll reads; input and resize are unary calls.
15917
15990
  descriptor("terminalInfo", [], anyObjectCodec("TerminalInfo")),
@@ -16363,10 +16436,10 @@ function registerUi(ctx) {
16363
16436
  rateResult: (request) => officialToolsRemote.rateResult(request),
16364
16437
  rerunStep: (request) => officialToolsRemote.rerunStep(request),
16365
16438
  loadBoundaries: () => officialToolsRemote.boundaries(),
16366
- previewRun: (request) => officialToolsRemote.previewRun(request),
16439
+ previewRun: (request, signal) => officialToolsRemote.previewRun(request, signal),
16367
16440
  startRun: (request) => officialToolsRemote.startRun(request),
16368
- runStatus: (request) => officialToolsRemote.runStatus(request),
16369
- cancelRun: (request) => officialToolsRemote.cancelRun(request),
16441
+ runStatus: (request, signal) => officialToolsRemote.runStatus(request, signal),
16442
+ cancelRun: (request, signal) => officialToolsRemote.cancelRun(request, signal),
16370
16443
  terminalApi: Object.freeze({
16371
16444
  terminalInfo: () => officialToolsRemote.terminalInfo(),
16372
16445
  terminalStart: (request) => officialToolsRemote.terminalStart(request),