dsh-opendesign-corouter 0.1.6 → 0.1.8

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/lib/client.js CHANGED
@@ -20054,9 +20054,9 @@ function amount(value, label, negative = false) {
20054
20054
  if (typeof value !== "number" || !Number.isFinite(value) || !negative && value < 0) throw new Error(`${label} \u5FC5\u987B\u662F${negative ? "" : "\u975E\u8D1F"}\u6709\u9650\u6570\u5B57`);
20055
20055
  return value;
20056
20056
  }
20057
- function positiveInteger(value, label, max) {
20057
+ function positiveInteger(value, label, max, min = 1) {
20058
20058
  const result = count(value, label);
20059
- if (result === 0 || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
20059
+ if (result < min || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
20060
20060
  return result;
20061
20061
  }
20062
20062
  function parseEfforts(value) {
@@ -20159,9 +20159,9 @@ function parseStatusConfig(value) {
20159
20159
  apiKeyEnv,
20160
20160
  ...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
20161
20161
  ...value.modelSettings === void 0 ? {} : { modelSettings: parseModelSettingsMap(value.modelSettings) },
20162
- ...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5) },
20163
- ...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5) },
20164
- ...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600) }
20162
+ ...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5, 1e3) },
20163
+ ...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5, 1e3) },
20164
+ ...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600, 5) }
20165
20165
  };
20166
20166
  }
20167
20167
  function parseStatus(value) {
@@ -20174,9 +20174,13 @@ function parseStatus(value) {
20174
20174
  if (ids.has(model.id)) throw new Error(`\u6A21\u578B\u5217\u8868\u91CD\u590D\u4E86 id "${model.id}"`);
20175
20175
  ids.add(model.id);
20176
20176
  }
20177
+ const apiKeyConfigured = flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA");
20178
+ const apiKeySource = value.apiKeySource === void 0 ? void 0 : member(value.apiKeySource, ["reference", "stored", "device"], "\u63A8\u7406\u51ED\u636E\u6765\u6E90");
20179
+ if (!apiKeyConfigured && apiKeySource !== void 0) throw new Error("\u672A\u914D\u7F6E\u51ED\u636E\u65F6\u4E0D\u80FD\u6307\u5B9A\u63A8\u7406\u51ED\u636E\u6765\u6E90");
20177
20180
  return {
20178
20181
  revision: text(value.revision, "\u914D\u7F6E\u7248\u672C", MAX_REVISION),
20179
- apiKeyConfigured: flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
20182
+ apiKeyConfigured,
20183
+ ...apiKeySource === void 0 ? {} : { apiKeySource },
20180
20184
  ...value.sessionSource === void 0 ? {} : { sessionSource: member(value.sessionSource, SESSION_SOURCES, "\u767B\u5F55\u6001\u6765\u6E90") },
20181
20185
  quota: parseQuotaSnapshot(value.quota),
20182
20186
  login: parseLoginState(value.login),
@@ -20230,6 +20234,19 @@ var TYPERT_REMOTE = createTypertRemoteInfo({ package: "dsh-opendesign-corouter",
20230
20234
  } }, external_exports);
20231
20235
  var typert_remote_client_default = TYPERT_REMOTE;
20232
20236
 
20237
+ // src/reasoning.ts
20238
+ var PROTOCOL_EFFORTS = {
20239
+ "chat-completions": ["none", "minimal", "low", "medium", "high", "xhigh", "ultra", "max"],
20240
+ responses: ["none", "minimal", "low", "medium", "high", "xhigh", "max"],
20241
+ messages: ["none", "low", "medium", "high", "xhigh", "max"]
20242
+ };
20243
+ function protocolAcceptsEffort(protocol, effort) {
20244
+ return PROTOCOL_EFFORTS[protocol].includes(effort);
20245
+ }
20246
+ function modelReasoningEfforts(model, protocol) {
20247
+ return model.reasoningEfforts?.filter((effort) => protocolAcceptsEffort(protocol, effort));
20248
+ }
20249
+
20233
20250
  // src/client.ts
20234
20251
  var h = React.createElement;
20235
20252
  var SETTINGS_NS = "llm-opendesign-corouter";
@@ -20264,7 +20281,7 @@ var LOGIN_LABELS = {
20264
20281
  };
20265
20282
  var QUOTA_LABELS = {
20266
20283
  ok: "\u989D\u5EA6\u4FE1\u606F\u5DF2\u66F4\u65B0",
20267
- partial: "\u90E8\u5206\u989D\u5EA6\u6682\u4E0D\u53EF\u7528\uFF0C\u5176\u4F59\u6570\u636E\u4ECD\u53EF\u53C2\u8003",
20284
+ partial: "\u989D\u5EA6\u6570\u636E\u6682\u672A\u5B8C\u6574",
20268
20285
  "need-login": "\u9700\u8981\u767B\u5F55\u540E\u8BFB\u53D6\u989D\u5EA6",
20269
20286
  error: "\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u989D\u5EA6"
20270
20287
  };
@@ -20278,7 +20295,9 @@ function installStyles() {
20278
20295
  .odc-tab{flex:none;border:1px solid transparent;border-radius:8px;padding:7px 13px;background:transparent;color:var(--dsw-alias-label-secondary,inherit);font:inherit;cursor:pointer}.odc-tab:hover{background:var(--dsw-alias-bg-layer-1,transparent)}.odc-tab[aria-selected=true]{color:var(--dsw-alias-label-primary,inherit);border-color:var(--dsw-alias-border-l3,transparent);background:var(--dsw-alias-bg-layer-1,transparent)}
20279
20296
  .odc-panel{display:grid;gap:14px}.odc-card{min-width:0;padding:15px;border:1px solid var(--dsw-alias-border-l4,transparent);border-radius:12px;background:var(--dsw-alias-bg-layer-1,transparent)}.odc-card>p{margin-top:6px}.odc-card-head,.odc-row{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.odc-card-head{margin-bottom:12px}
20280
20297
  .odc-quota-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}.odc-metric{display:grid;align-content:start;gap:5px;min-height:96px}.odc-metric-value{font-size:20px;font-weight:650;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.odc-metric-value.odc-metric-text{font-size:13px;font-weight:600;line-height:1.55}.odc-quota-grid+.odc-quota-grid{margin-top:10px}
20281
- .odc-label,.odc-hint,.odc-meta{color:var(--dsw-alias-label-secondary,inherit);font-size:11px;line-height:1.6}.odc-meta{margin-top:10px!important}.odc-window{display:grid;gap:7px;margin-top:10px}.odc-window progress{width:100%;height:7px;accent-color:var(--dsw-alias-brand-primary,Highlight)}
20298
+ .odc-label,.odc-hint,.odc-meta{color:var(--dsw-alias-label-secondary,inherit);font-size:11px;line-height:1.6}.odc-meta{margin-top:10px!important}
20299
+ .odc-window{display:grid;gap:10px;margin-top:12px;padding:14px;border-radius:10px;background:var(--dsw-alias-bg-layer-2,transparent);min-width:0}.odc-window-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.odc-window h4{margin:0;font-size:13px;font-weight:600}.odc-window-remaining{display:flex;align-items:baseline;gap:6px;font-variant-numeric:tabular-nums;white-space:nowrap}.odc-window-remaining strong{font-size:22px;line-height:1.2}.odc-window progress{display:block;width:100%;height:8px;accent-color:var(--dsw-alias-brand-primary,Highlight)}
20300
+ .odc-window-usage{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin:0}.odc-window-usage>div{display:grid;gap:3px;min-width:0}.odc-window dt,.odc-quota-footer dt{color:var(--dsw-alias-label-secondary,inherit);font-size:11px}.odc-window dd,.odc-quota-footer dd{margin:0;min-width:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.odc-window-reset{display:grid;gap:3px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l4,transparent)}.odc-window-reset time{font-size:12px}.odc-window-details>summary{cursor:pointer;font-size:11px;color:var(--dsw-alias-label-secondary,inherit);min-height:32px;padding:6px 0}.odc-window-details dl{display:grid;gap:8px;margin:6px 0 0}.odc-window-details dl>div{display:grid;gap:3px}.odc-quota-footer{display:grid;gap:8px;margin:0;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l4,transparent)}.odc-quota-footer>div{display:grid;grid-template-columns:72px minmax(0,1fr);gap:10px}.odc-quota-footer dd{font-size:11px;color:var(--dsw-alias-label-secondary,inherit)}
20282
20301
  .odc-button{display:inline-flex;align-items:center;justify-content:center;min-height:32px;padding:6px 12px;border:1px solid var(--dsw-alias-border-l3,transparent);border-radius:8px;background:var(--dsw-alias-bg-layer-2,transparent);color:var(--dsw-alias-label-primary,inherit);font:inherit;font-size:12px;cursor:pointer}.odc-button:hover:not(:disabled){border-color:var(--dsw-alias-brand-primary,Highlight)}.odc-button-primary{background:var(--dsw-alias-button-primary-fill,var(--dsw-alias-brand-primary,Highlight));color:var(--dsw-alias-label-primary-foreground,HighlightText);border-color:transparent}.odc-button-primary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover,var(--dsw-alias-brand-primary,Highlight))}.odc-button:disabled{opacity:.55;cursor:not-allowed}.odc-button-small{min-height:26px;padding:3px 9px;font-size:11px}.odc-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
20283
20302
  .odc-notice{padding:9px 11px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,transparent);font-size:12px;line-height:1.6}.odc-notice[data-kind=error]{color:var(--dsw-alias-state-error-primary,inherit);color:color-mix(in srgb,var(--dsw-alias-state-error-primary,CanvasText) 85%,var(--dsw-alias-label-primary,CanvasText))}
20284
20303
  .odc-model-groups{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-top:12px}.odc-model-list{display:grid;gap:6px;margin:10px 0 0;padding:0;list-style:none}.odc-model-item{padding:9px 10px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,transparent);min-width:0}.odc-model-head{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;flex-wrap:wrap}.odc-model-switch{min-width:0;flex:1 1 190px}.odc-model-item strong,.odc-model-item code{display:block;overflow-wrap:anywhere}.odc-model-item strong{font-size:12px;font-weight:600}.odc-model-item code{margin-top:2px;color:var(--dsw-alias-label-secondary,inherit);font-size:11px}.odc-model-meta{margin-top:6px!important;color:var(--dsw-alias-label-secondary,inherit);font-size:11px;overflow-wrap:anywhere}.odc-model-count{color:var(--dsw-alias-label-secondary,inherit);font-size:11px;font-weight:400}.odc-chip{display:inline-flex;align-items:center;padding:1px 7px;border:1px solid var(--dsw-alias-border-l3,transparent);border-radius:999px;color:var(--dsw-alias-label-secondary,inherit);font-size:10px;line-height:1.6}
@@ -20471,19 +20490,49 @@ function QuotaView({ quota, nextAutoRefreshAt, refreshIntervalSeconds }) {
20471
20490
  React.Fragment,
20472
20491
  null,
20473
20492
  h("p", { className: "odc-metric-value" }, "\u2014"),
20474
- h("p", { className: "odc-hint" }, "\u989D\u5EA6\u7A97\u53E3\u6682\u4E0D\u53EF\u786E\u8BA4\uFF1B\u4E0D\u6309 0 \u586B\u5145\u3002")
20475
- ) : quota.windows.map((window, index) => h(
20476
- "div",
20477
- { className: "odc-window", key: `${window.durationSeconds}-${index}` },
20478
- h(
20479
- "div",
20480
- { className: "odc-row" },
20481
- h("span", null, windowLabel(window.durationSeconds)),
20482
- h("span", { className: "odc-label" }, `\u5DF2\u7528 ${window.percent.toFixed(1)}% \xB7 \u5269\u4F59 ${window.remaining ?? "\u2014"}`)
20483
- ),
20484
- h("progress", { max: 100, value: window.percent, "aria-label": `${windowLabel(window.durationSeconds)}\u5DF2\u7528\u989D\u5EA6` }),
20485
- h("span", { className: "odc-meta" }, `\u5DF2\u7528 ${window.used} / \u4E0A\u9650 ${window.limit} \xB7 \u6062\u590D ${formatTime(window.resetsAt)}${window.windowStart === void 0 ? "" : ` \xB7 \u7A97\u53E3\u5F00\u59CB ${formatTime(window.windowStart)}`}${window.resetMode === void 0 ? "" : ` \xB7 \u91CD\u7F6E\u65B9\u5F0F ${RESET_MODE_LABELS[window.resetMode] ?? window.resetMode}`}`)
20486
- ))
20493
+ h("p", { className: "odc-hint" }, "\u6682\u65F6\u65E0\u6CD5\u83B7\u53D6\u989D\u5EA6\u7A97\u53E3\u3002")
20494
+ ) : quota.windows.map((window, index) => {
20495
+ const label = windowLabel(window.durationSeconds);
20496
+ const remainingPercent = Math.max(0, Math.min(100, 100 - window.percent));
20497
+ return h(
20498
+ "section",
20499
+ { className: "odc-window", key: `${window.durationSeconds}-${index}`, "aria-label": label },
20500
+ h(
20501
+ "div",
20502
+ { className: "odc-window-head" },
20503
+ h("h4", null, label),
20504
+ h(
20505
+ "div",
20506
+ { className: "odc-window-remaining" },
20507
+ h("strong", null, `${remainingPercent.toFixed(1)}%`),
20508
+ h("span", { className: "odc-label" }, "\u5269\u4F59")
20509
+ )
20510
+ ),
20511
+ h("progress", { max: 100, value: remainingPercent, "aria-label": `${label}\u5269\u4F59\u989D\u5EA6` }),
20512
+ h(
20513
+ "dl",
20514
+ { className: "odc-window-usage", "aria-label": "\u7A97\u53E3\u7528\u91CF\u660E\u7EC6" },
20515
+ [{ label: "\u5DF2\u7528", value: window.used }, { label: "\u4E0A\u9650", value: window.limit }, { label: "\u5269\u4F59", value: window.remaining ?? "\u2014" }].map((item) => h("div", { key: item.label }, h("dt", null, item.label), h("dd", null, item.value)))
20516
+ ),
20517
+ h(
20518
+ "div",
20519
+ { className: "odc-window-reset" },
20520
+ h("span", { className: "odc-label" }, "\u4E0B\u6B21\u6062\u590D"),
20521
+ window.resetsAt === void 0 ? h("span", null, "\u2014") : h("time", { dateTime: window.resetsAt }, formatTime(window.resetsAt))
20522
+ ),
20523
+ window.windowStart === void 0 && window.resetMode === void 0 ? null : h(
20524
+ "details",
20525
+ { className: "odc-window-details" },
20526
+ h("summary", null, "\u7A97\u53E3\u8BE6\u60C5"),
20527
+ h(
20528
+ "dl",
20529
+ null,
20530
+ window.windowStart === void 0 ? null : h("div", null, h("dt", null, "\u7A97\u53E3\u5F00\u59CB"), h("dd", null, h("time", { dateTime: window.windowStart }, formatTime(window.windowStart)))),
20531
+ window.resetMode === void 0 ? null : h("div", null, h("dt", null, "\u91CD\u7F6E\u65B9\u5F0F"), h("dd", null, RESET_MODE_LABELS[window.resetMode] ?? window.resetMode))
20532
+ )
20533
+ )
20534
+ );
20535
+ })
20487
20536
  ),
20488
20537
  h("div", { className: "odc-quota-grid" }, metrics.map((metric) => h(
20489
20538
  "div",
@@ -20499,12 +20548,17 @@ function QuotaView({ quota, nextAutoRefreshAt, refreshIntervalSeconds }) {
20499
20548
  h("strong", { className: "odc-metric-value odc-metric-text" }, metric.value),
20500
20549
  h("span", { className: "odc-hint" }, metric.hint)
20501
20550
  ))),
20502
- h("p", { className: "odc-meta" }, `\u66F4\u65B0\u4E8E ${formatTime(quota.updatedAt)}${quota.source !== void 0 ? ` \xB7 \u6765\u6E90\uFF1A${SOURCE_LABELS[quota.source]}\uFF08\u53EA\u8BFB\u5C55\u793A\uFF09` : ""}`),
20551
+ h(
20552
+ "dl",
20553
+ { className: "odc-quota-footer", "aria-label": "\u989D\u5EA6\u6570\u636E\u6765\u6E90\u4E0E\u66F4\u65B0\u65F6\u95F4" },
20554
+ h("div", null, h("dt", null, "\u6700\u8FD1\u66F4\u65B0"), h("dd", null, h("time", { dateTime: quota.updatedAt }, formatTime(quota.updatedAt)))),
20555
+ quota.source === void 0 ? null : h("div", null, h("dt", null, "\u6570\u636E\u6765\u6E90"), h("dd", null, SOURCE_LABELS[quota.source]))
20556
+ ),
20503
20557
  h(
20504
20558
  "details",
20505
20559
  { className: "odc-model-details" },
20506
20560
  h("summary", null, "\u5982\u4F55\u7406\u89E3\u8FD9\u4E9B\u989D\u5EA6\uFF1F"),
20507
- h("p", { className: "odc-hint" }, "\u8D60\u9001\u7A97\u53E3\u4E0E\u94B1\u5305\u4F59\u989D\u5206\u522B\u8BA1\u91CF\u3002\u5957\u9910\u4F59\u989D\u6765\u81EA\u8BA2\u9605\uFF0C\u5145\u503C / \u8D60\u9001\u91D1\u989D\u6765\u81EA\u94B1\u5305\uFF1B\u603B\u989D\u5EA6\u662F\u94B1\u5305\u5F53\u524D\u53EF\u7528\u603B\u989D\u3002\u5B9E\u9645\u6263\u6B3E\u7531\u670D\u52A1\u7AEF\u51B3\u5B9A\u3002\u989D\u5EA6\u6570\u636E\u53EA\u8BFB\u5C55\u793A\uFF0C\u672A\u77E5\u91D1\u989D\u663E\u793A \u2014\u3002")
20561
+ h("p", { className: "odc-hint" }, "\u8D60\u9001\u7A97\u53E3\u663E\u793A\u5468\u671F\u5185\u7684\u4F7F\u7528\u91CF\u3002\u5957\u9910\u4F59\u989D\u548C\u5145\u503C / \u8D60\u9001\u91D1\u989D\u662F\u94B1\u5305\u7684\u4E0D\u540C\u5206\u6C60\uFF0C\u603B\u989D\u5EA6\u662F\u94B1\u5305\u5408\u8BA1\u3002\u2014 \u8868\u793A\u6682\u65E0\u6570\u636E\u3002")
20508
20562
  ),
20509
20563
  quota.note !== void 0 ? h("p", { className: "odc-notice", "data-kind": quota.state === "error" ? "error" : "status", role: quota.state === "error" ? "alert" : "status" }, quota.note) : null
20510
20564
  );
@@ -20585,7 +20639,7 @@ function Overview({ status, busy, onRefresh, nextAutoRefreshAt, refreshIntervalS
20585
20639
  h(
20586
20640
  "div",
20587
20641
  { className: "odc-card-head" },
20588
- h("div", null, h("h3", null, "\u989D\u5EA6\u6982\u89C8"), h("p", { className: "odc-hint" }, "\u5957\u9910\u7A97\u53E3\u4E0E\u94B1\u5305\u4F59\u989D\u5206\u5F00\u8BA1\u91CF\uFF1B\u672A\u77E5\u6570\u636E\u4E0D\u505A\u63A8\u7B97\u3002")),
20642
+ h("div", null, h("h3", null, "\u989D\u5EA6\u6982\u89C8"), h("p", { className: "odc-hint" }, "\u67E5\u770B\u5957\u9910\u7528\u91CF\u3001\u8BA2\u9605\u4F59\u989D\u548C\u5145\u503C\u4F59\u989D\u3002")),
20589
20643
  h("button", { className: "odc-button", type: "button", disabled: busy, onClick: onRefresh }, busy ? "\u5237\u65B0\u4E2D\u2026" : "\u5237\u65B0\u989D\u5EA6")
20590
20644
  ),
20591
20645
  h(QuotaView, { quota: status?.quota, nextAutoRefreshAt, refreshIntervalSeconds })
@@ -20664,8 +20718,9 @@ function EffortField({ id, model, value, disabled, onChange }) {
20664
20718
  const mounted = useMounted();
20665
20719
  const [error62, setError] = React.useState(void 0);
20666
20720
  const listed = model.reasoningEfforts ?? [];
20667
- const options = value === void 0 || listed.includes(value) ? listed : [...listed, value];
20668
- const unknown2 = options.length === 0;
20721
+ const invalidDefault = value !== void 0 && !listed.includes(value);
20722
+ const options = invalidDefault ? [...listed, value] : listed;
20723
+ const unavailable = listed.length === 0;
20669
20724
  return h(
20670
20725
  "div",
20671
20726
  { className: "odc-field odc-field-compact" },
@@ -20674,8 +20729,9 @@ function EffortField({ id, model, value, disabled, onChange }) {
20674
20729
  id,
20675
20730
  className: "odc-input",
20676
20731
  value: value ?? "",
20677
- disabled: disabled || unknown2,
20732
+ disabled: disabled || unavailable && !invalidDefault,
20678
20733
  "aria-describedby": `${id}-hint`,
20734
+ "aria-invalid": invalidDefault || error62 !== void 0,
20679
20735
  onChange: (event) => {
20680
20736
  const next = event.target.value;
20681
20737
  void (async () => {
@@ -20685,13 +20741,13 @@ function EffortField({ id, model, value, disabled, onChange }) {
20685
20741
  }
20686
20742
  }, [
20687
20743
  h("option", { key: "", value: "" }, "\u7EE7\u627F\u9ED8\u8BA4"),
20688
- ...options.map((effort) => h("option", { key: effort, value: effort }, effort))
20744
+ ...options.map((effort) => h("option", { key: effort, value: effort, disabled: invalidDefault && effort === value }, invalidDefault && effort === value ? `${effort}\uFF08\u5F53\u524D\u4E0D\u53EF\u7528\uFF09` : effort))
20689
20745
  ]),
20690
20746
  h("small", {
20691
20747
  className: error62 === void 0 ? "odc-hint" : "odc-hint odc-field-error",
20692
20748
  id: `${id}-hint`,
20693
20749
  ...error62 === void 0 ? {} : { role: "alert" }
20694
- }, error62 ?? (unknown2 ? "\u8BE5\u6A21\u578B\u76EE\u5F55\u672A\u63D0\u4F9B\u601D\u8003\u6863\u4F4D\uFF0C\u65E0\u6CD5\u8986\u76D6\u3002" : "\u53EA\u5217\u51FA\u8BE5\u6A21\u578B\u5DF2\u77E5\u6863\u4F4D\uFF1B\u7559\u7A7A\u7EE7\u627F\u9ED8\u8BA4\u3002"))
20750
+ }, error62 ?? (invalidDefault ? "\u5DF2\u4FDD\u5B58\u7684\u6863\u4F4D\u4E0D\u9002\u7528\u4E8E\u5F53\u524D\u6A21\u578B\u6216\u534F\u8BAE\uFF0C\u8BF7\u9009\u62E9\u5176\u4ED6\u6863\u4F4D\u6216\u7EE7\u627F\u9ED8\u8BA4\u3002" : unavailable ? "\u5F53\u524D\u6A21\u578B\u6216\u534F\u8BAE\u672A\u63D0\u4F9B\u53EF\u8C03\u6574\u7684\u601D\u8003\u6863\u4F4D\u3002" : "\u7559\u7A7A\u4F7F\u7528\u670D\u52A1\u7AEF\u9ED8\u8BA4\u6863\u4F4D\u3002"))
20695
20751
  );
20696
20752
  }
20697
20753
  function ModelRow({ model, settings, authoritative, writable, pending, onCommit }) {
@@ -20859,9 +20915,13 @@ function Models({ status, formSnapshot, setFormField, pendingField, onRefreshMod
20859
20915
  saving.current = false;
20860
20916
  }
20861
20917
  };
20862
- const source = status?.modelsSource === "openai" ? "OpenAI /models \u53D1\u73B0" : status?.modelsSource === "builtin" ? "\u5185\u7F6E\u76EE\u5F55" : "\u5C1A\u672A\u786E\u8BA4";
20918
+ const source = status?.modelsSource === "openai" ? "\u5F53\u524D\u7F51\u5173" : status?.modelsSource === "builtin" ? "\u5185\u7F6E\u76EE\u5F55" : "\u5C1A\u672A\u786E\u8BA4";
20863
20919
  const updated = status?.modelsUpdatedAt === void 0 ? "" : ` \xB7 \u66F4\u65B0\u4E8E ${formatTime(status.modelsUpdatedAt)}`;
20864
- const models = status?.models ?? [];
20920
+ const protocol = formSnapshot.value?.apiProtocol ?? status?.config.apiProtocol ?? "chat-completions";
20921
+ const models = (status?.models ?? []).map((model) => {
20922
+ const reasoningEfforts = modelReasoningEfforts(model, protocol);
20923
+ return { ...model, ...reasoningEfforts === void 0 ? {} : { reasoningEfforts } };
20924
+ });
20865
20925
  return h(
20866
20926
  React.Fragment,
20867
20927
  null,
@@ -20872,7 +20932,7 @@ function Models({ status, formSnapshot, setFormField, pendingField, onRefreshMod
20872
20932
  "div",
20873
20933
  null,
20874
20934
  h("h3", null, "\u53EF\u7528\u6A21\u578B"),
20875
- h("p", { className: "odc-hint" }, "\u4E24\u4E2A Provider \u72EC\u7ACB\u7B5B\u9009\u3002\u9010\u6A21\u578B\u7684\u542F\u7528\u4E0E\u53C2\u6570\u4F1A\u4FDD\u5B58\u5230\u63D2\u4EF6\u8BBE\u7F6E\uFF0C\u53EA\u5F71\u54CD\u672C\u63D2\u4EF6\u7684\u6A21\u578B\u9009\u62E9\u4E0E\u8BF7\u6C42\u3002")
20935
+ h("p", { className: "odc-hint" }, "\u6309\u5206\u7EC4\u641C\u7D22\u6A21\u578B\uFF0C\u8BBE\u7F6E\u542F\u7528\u72B6\u6001\u4E0E\u9ED8\u8BA4\u53C2\u6570\u3002")
20876
20936
  ),
20877
20937
  h(
20878
20938
  "div",
@@ -20882,8 +20942,9 @@ function Models({ status, formSnapshot, setFormField, pendingField, onRefreshMod
20882
20942
  className: "odc-button",
20883
20943
  type: "button",
20884
20944
  disabled: refreshingModels || status === void 0 || status.apiKeyConfigured === false,
20885
- onClick: onRefreshModels
20886
- }, refreshingModels ? "\u6B63\u5728\u5237\u65B0\u6A21\u578B\u2026" : "\u4ECE OpenAI \u5237\u65B0\u6A21\u578B")
20945
+ onClick: onRefreshModels,
20946
+ title: "\u4ECE\u5F53\u524D\u914D\u7F6E\u7684\u7F51\u5173\u8BFB\u53D6\u53EF\u7528\u6A21\u578B\u76EE\u5F55"
20947
+ }, refreshingModels ? "\u6B63\u5728\u5237\u65B0\u6A21\u578B\u2026" : "\u5237\u65B0\u6A21\u578B\u76EE\u5F55")
20887
20948
  )
20888
20949
  ),
20889
20950
  status?.apiKeyConfigured === false ? h("p", { className: "odc-hint" }, "\u5237\u65B0\u6A21\u578B\u9700\u8981\u53EF\u7528\u7684 API Key\uFF1B\u4FDD\u5B58 Key \u540E\u91CD\u8BD5\u3002") : null,
@@ -20892,8 +20953,8 @@ function Models({ status, formSnapshot, setFormField, pendingField, onRefreshMod
20892
20953
  models.length === 0 ? h("p", { className: "odc-hint", role: "status" }, "\u6682\u65E0\u53EF\u7528\u6A21\u578B\uFF1B\u53EF\u5237\u65B0\u6A21\u578B\u5217\u8868\u540E\u91CD\u8BD5\u3002") : h(
20893
20954
  "div",
20894
20955
  { className: "odc-model-groups" },
20895
- h(ModelGroup, { title: "\u5957\u9910\u8D60\u9001 Provider", group: "plan", models, settingsMap, authoritative, writable, pending, onCommit: commit }),
20896
- h(ModelGroup, { title: "\u4ED8\u8D39 Provider", group: "paid", models, settingsMap, authoritative, writable, pending, onCommit: commit })
20956
+ h(ModelGroup, { title: "\u5957\u9910\u8D60\u9001\u6A21\u578B", group: "plan", models, settingsMap, authoritative, writable, pending, onCommit: commit }),
20957
+ h(ModelGroup, { title: "\u4ED8\u8D39\u6A21\u578B", group: "paid", models, settingsMap, authoritative, writable, pending, onCommit: commit })
20897
20958
  )
20898
20959
  );
20899
20960
  }
@@ -20985,12 +21046,12 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
20985
21046
  "section",
20986
21047
  { className: "odc-card" },
20987
21048
  h("h3", null, "\u7A7A\u8F6E\u76D1\u63A7"),
20988
- h("p", { className: "odc-hint" }, "\u72EC\u7ACB\u76D1\u63A7\u5957\u9910\u8D60\u9001\u6A21\u578B\u7684\u7A7A\u8F6E\u6216\u534F\u8BAE\u6B8B\u6E23\uFF1B\u4E0D\u5F71\u54CD\u4ED8\u8D39 Provider \u7684\u5F00\u5173\u3002"),
21049
+ h("p", { className: "odc-hint" }, "\u68C0\u6D4B DeepSeek V4.1 Flash \u5DE5\u5177\u5BF9\u8BDD\u4E2D\u7684\u7A7A\u56DE\u7B54\u6216\u534F\u8BAE\u6807\u8BB0\u6B8B\u7559\u3002"),
20989
21050
  h("div", { style: { marginTop: 14 } }, h(Switch, {
20990
21051
  checked: formSnapshot.value?.emptyTurnGuard ?? status?.config.emptyTurnGuard ?? true,
20991
21052
  disabled: !writable || pendingField.includes("emptyTurnGuard"),
20992
21053
  label: "\u542F\u7528\u7A7A\u8F6E\u76D1\u63A7",
20993
- hint: `\u672C\u6B21\u8FD0\u884C\u5DF2\u62E6\u622A ${status?.guardedTurns ?? "\u2014"} \u8F6E\u3002\u68C0\u6D4B\u540E\u7531\u5BBF\u4E3B\u91CD\u8BD5\u7B56\u7565\u5904\u7406\uFF0C\u5BBF\u4E3B\u91CD\u8BD5\u4F1A\u989D\u5916\u6D88\u8017\u989D\u5EA6\u3002`,
21054
+ hint: `\u5DF2\u68C0\u6D4B\u5230 ${status?.guardedTurns ?? "\u2014"} \u6B21\u7A7A\u56DE\u7B54\u3002\u81EA\u52A8\u91CD\u8BD5\u7531 DSH \u7684\u91CD\u8BD5\u8BBE\u7F6E\u63A7\u5236\uFF0C\u91CD\u8BD5\u53EF\u80FD\u989D\u5916\u6D88\u8017\u989D\u5EA6\u3002`,
20994
21055
  onChange: (checked) => {
20995
21056
  void setFormField("emptyTurnGuard", checked);
20996
21057
  }
@@ -21000,7 +21061,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
21000
21061
  "section",
21001
21062
  { className: "odc-card" },
21002
21063
  h("h3", null, "\u63A8\u7406\u534F\u8BAE"),
21003
- h("p", { className: "odc-hint" }, "\u63D2\u4EF6\u6309\u6240\u9009\u534F\u8BAE\u7EC4\u88C5\u8BF7\u6C42\uFF1B\u6A21\u578B\u53D1\u73B0\u59CB\u7EC8\u8BFB\u53D6 OpenAI /models\uFF0C\u4E0E\u8FD9\u91CC\u7684\u9009\u62E9\u65E0\u5173\u3002"),
21064
+ h("p", { className: "odc-hint" }, "\u9009\u62E9\u5F53\u524D\u7F51\u5173\u652F\u6301\u7684\u63A8\u7406\u534F\u8BAE\u3002\u6A21\u578B\u76EE\u5F55\u59CB\u7EC8\u4ECE\u8BE5\u7F51\u5173\u8BFB\u53D6\u3002"),
21004
21065
  h(
21005
21066
  "div",
21006
21067
  { className: "odc-field" },
@@ -21048,7 +21109,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
21048
21109
  className: "odc-input",
21049
21110
  type: "text",
21050
21111
  value: apiKeyEnv,
21051
- disabled: !writable,
21112
+ disabled: !writable || pendingField.includes("apiKeyEnv"),
21052
21113
  autoCapitalize: "off",
21053
21114
  spellCheck: false,
21054
21115
  onChange: (event) => setApiKeyEnv(event.target.value)
@@ -21068,7 +21129,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
21068
21129
  "section",
21069
21130
  { className: "odc-card" },
21070
21131
  h("h3", null, "\u8BF7\u6C42\u65F6\u9650\u4E0E\u81EA\u52A8\u5237\u65B0"),
21071
- h("p", { className: "odc-hint" }, "\u6570\u503C\u5728\u79BB\u5F00\u8F93\u5165\u6846\u65F6\u6821\u9A8C\u5E76\u4FDD\u5B58\uFF1B\u7559\u7A7A\u6216\u8D8A\u754C\u4E0D\u4F1A\u5199\u5165\u3002"),
21132
+ h("p", { className: "odc-hint" }, "\u8F93\u5165\u6709\u6548\u8303\u56F4\u5185\u7684\u6574\u6570\uFF0C\u79BB\u5F00\u8F93\u5165\u6846\u540E\u4FDD\u5B58\u3002"),
21072
21133
  h(NumberField, {
21073
21134
  id: "odc-request-timeout",
21074
21135
  label: "\u8BF7\u6C42\u603B\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",
@@ -21119,14 +21180,32 @@ function loginInFlight(state) {
21119
21180
  var ACTIVATION_OPEN_LABELS = {
21120
21181
  opened: "\u5DF2\u5728\u65B0\u7A97\u53E3\u6253\u5F00\u5B98\u65B9\u6388\u6743\u9875\uFF1B\u8BF7\u5728\u8BE5\u7A97\u53E3\u786E\u8BA4\u8BBE\u5907\u7801\u3002",
21121
21182
  "no-link": "\u6388\u6743\u7801\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u7533\u8BF7\u3002",
21122
- "invalid-url": "\u6388\u6743\u94FE\u63A5\u672A\u901A\u8FC7\u6821\u9A8C\uFF0C\u8BF7\u590D\u5236\u94FE\u63A5\u624B\u52A8\u6253\u5F00\u3002",
21183
+ "invalid-url": "\u6388\u6743\u94FE\u63A5\u65E0\u6548\uFF0C\u8BF7\u53D6\u6D88\u5E76\u91CD\u65B0\u5F00\u59CB\u767B\u5F55\u3002",
21123
21184
  unavailable: "\u65E0\u6CD5\u542F\u52A8\u4E34\u65F6\u6D4F\u89C8\u5668\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u5B89\u88C5 Chrome\uFF1B\u4E5F\u53EF\u590D\u5236\u94FE\u63A5\u624B\u52A8\u6253\u5F00\u3002",
21124
21185
  failed: "\u4E34\u65F6\u6D4F\u89C8\u5668\u7A97\u53E3\u672A\u80FD\u6253\u5F00\uFF0C\u8BF7\u590D\u5236\u94FE\u63A5\u624B\u52A8\u6253\u5F00\u3002"
21125
21186
  };
21126
21187
  function LoginApproval({ login, onOpen, opening, notice }) {
21188
+ const mounted = useMounted();
21189
+ const copyVersion = React.useRef(0);
21190
+ const [copyState, setCopyState] = React.useState("idle");
21191
+ React.useEffect(() => {
21192
+ copyVersion.current += 1;
21193
+ setCopyState("idle");
21194
+ }, [login?.jobId, login?.state, login?.activationUrl]);
21127
21195
  if (login?.state !== "waiting" || login.userCode === void 0 || login.expiresAt === void 0) return null;
21128
21196
  const url2 = validateActivationUrl(login.activationUrl, login.userCode);
21129
21197
  if (url2 === null) return null;
21198
+ const copyLink = async () => {
21199
+ const version2 = ++copyVersion.current;
21200
+ setCopyState("copying");
21201
+ try {
21202
+ if (typeof navigator.clipboard?.writeText !== "function") throw new Error("clipboard-unavailable");
21203
+ await navigator.clipboard.writeText(url2);
21204
+ if (mounted.current && version2 === copyVersion.current) setCopyState("copied");
21205
+ } catch {
21206
+ if (mounted.current && version2 === copyVersion.current) setCopyState("manual");
21207
+ }
21208
+ };
21130
21209
  return h(
21131
21210
  "div",
21132
21211
  { className: "odc-readonly", "aria-label": "\u8BBE\u5907\u6388\u6743" },
@@ -21143,14 +21222,24 @@ function LoginApproval({ login, onOpen, opening, notice }) {
21143
21222
  onOpen?.();
21144
21223
  }
21145
21224
  }, opening === true ? "\u6B63\u5728\u6253\u5F00\u2026" : "\u5728\u65B0\u7A97\u53E3\u6253\u5F00\u6388\u6743\u9875"),
21146
- h("a", { className: "odc-button", href: url2, target: "_blank", rel: "noreferrer noopener" }, "\u590D\u5236\u94FE\u63A5\u624B\u52A8\u6253\u5F00")
21225
+ h("button", { className: "odc-button", type: "button", disabled: copyState === "copying", onClick: () => {
21226
+ void copyLink();
21227
+ } }, copyState === "copying" ? "\u6B63\u5728\u590D\u5236\u2026" : "\u590D\u5236\u6388\u6743\u94FE\u63A5"),
21228
+ h("a", { className: "odc-link", href: url2, target: "_blank", rel: "noreferrer noopener" }, "\u5B98\u65B9\u6388\u6743\u9875")
21147
21229
  ),
21230
+ copyState === "copied" ? h("p", { className: "odc-hint", role: "status" }, "\u94FE\u63A5\u5DF2\u590D\u5236\uFF0C\u53EF\u5728\u5E38\u7528\u6D4F\u89C8\u5668\u4E2D\u7C98\u8D34\u6253\u5F00\u3002") : null,
21231
+ copyState === "manual" ? h(
21232
+ "label",
21233
+ { className: "odc-field" },
21234
+ h("span", null, "\u8BF7\u9009\u62E9\u5E76\u590D\u5236\u6388\u6743\u94FE\u63A5"),
21235
+ h("input", { className: "odc-input", type: "text", readOnly: true, value: url2, onFocus: (event) => event.target.select() })
21236
+ ) : null,
21148
21237
  notice ? h(NoticeView, { notice }) : null,
21149
21238
  h("p", { className: "odc-hint" }, `\u6388\u6743\u7801\u6709\u6548\u81F3 ${formatTime(login.expiresAt)}\u3002\u5728\u6388\u6743\u7A97\u53E3\u786E\u8BA4\u540E\uFF0C\u8FD4\u56DE\u6B64\u9875\u67E5\u770B\u7ED3\u679C\u3002`),
21150
- h("p", { className: "odc-hint" }, "\u65B0\u7A97\u53E3\u662F\u72EC\u7ACB\u7684\u4E34\u65F6 Chrome\uFF0C\u4E0D\u4F1A\u8BFB\u53D6\u6216\u6539\u52A8\u4F60\u6B63\u5728\u4F7F\u7528\u7684\u6D4F\u89C8\u5668\u914D\u7F6E\uFF1B\u9700\u8981\u6CBF\u7528\u5DF2\u6709\u767B\u5F55\u6001\u65F6\uFF0C\u53F3\u952E\u590D\u5236\u94FE\u63A5\u5230\u5E38\u7528\u6D4F\u89C8\u5668\u3002\u4EC5\u786E\u8BA4\u4F60\u672C\u4EBA\u53D1\u8D77\u7684\u6388\u6743\u3002")
21239
+ h("p", { className: "odc-hint" }, "\u4E34\u65F6 Chrome \u7A97\u53E3\u9700\u8981\u5355\u72EC\u767B\u5F55\uFF1B\u4E5F\u53EF\u590D\u5236\u94FE\u63A5\u5230\u5DF2\u767B\u5F55\u7684\u5E38\u7528\u6D4F\u89C8\u5668\u3002\u4EC5\u786E\u8BA4\u4F60\u672C\u4EBA\u53D1\u8D77\u7684\u6388\u6743\u3002")
21151
21240
  );
21152
21241
  }
21153
- function Connection({ status, formSnapshot, setFormField, pendingField, caller, loadStatus, refreshAfterLogin }) {
21242
+ function Connection({ status, formSnapshot, setFormField, pendingField, caller, onLoginStatus, onStatus }) {
21154
21243
  const mounted = useMounted();
21155
21244
  const actionVersion = React.useRef(0);
21156
21245
  const [busy, setBusy] = React.useState(false);
@@ -21185,12 +21274,12 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21185
21274
  try {
21186
21275
  const next = await caller("startLogin", { expectedRevision: status.revision });
21187
21276
  if (!mounted.current || version2 !== actionVersion.current) return;
21277
+ onLoginStatus(next);
21188
21278
  setNotice(null);
21189
21279
  setActivationNotice(null);
21190
- await (next.state === "success" ? refreshAfterLogin() : loadStatus());
21191
21280
  } catch {
21192
21281
  autoOpenPending.current = false;
21193
- if (mounted.current && version2 === actionVersion.current) setNotice({ kind: "error", text: "\u65E0\u6CD5\u542F\u52A8\u767B\u5F55\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002" });
21282
+ if (mounted.current && version2 === actionVersion.current) setNotice({ kind: "error", text: "\u767B\u5F55\u8BF7\u6C42\u6682\u672A\u786E\u8BA4\uFF0C\u8BF7\u91CD\u8BD5\u3002" });
21194
21283
  } finally {
21195
21284
  if (mounted.current && version2 === actionVersion.current) setBusy(false);
21196
21285
  }
@@ -21200,10 +21289,11 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21200
21289
  const version2 = ++actionVersion.current;
21201
21290
  setBusy(true);
21202
21291
  try {
21203
- await caller("cancelLogin", { jobId: login.jobId });
21292
+ const next = await caller("cancelLogin", { jobId: login.jobId });
21204
21293
  if (!mounted.current || version2 !== actionVersion.current) return;
21205
- await loadStatus();
21206
- if (mounted.current) setNotice({ kind: "status", text: "\u5DF2\u8BF7\u6C42\u53D6\u6D88\u767B\u5F55\u3002" });
21294
+ autoOpenPending.current = false;
21295
+ onLoginStatus(next);
21296
+ setNotice({ kind: "status", text: next.message ?? LOGIN_LABELS[next.state] });
21207
21297
  } catch {
21208
21298
  if (mounted.current && version2 === actionVersion.current) setNotice({ kind: "error", text: "\u53D6\u6D88\u672A\u5B8C\u6210\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002" });
21209
21299
  } finally {
@@ -21220,15 +21310,15 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21220
21310
  setKeyBusy(true);
21221
21311
  setNotice(null);
21222
21312
  try {
21223
- await caller("saveApiKey", { value: apiKey, expectedRevision: status.revision });
21313
+ const next = await caller("saveApiKey", { value: apiKey, expectedRevision: status.revision });
21224
21314
  if (!mounted.current || version2 !== actionVersion.current) return;
21225
21315
  setApiKey("");
21226
- await loadStatus();
21227
- if (mounted.current) setNotice({ kind: "status", text: "API Key \u5DF2\u5B89\u5168\u4FDD\u5B58\u3002" });
21316
+ onStatus(next);
21317
+ setNotice({ kind: "status", text: next.apiKeySource === "reference" ? `API Key \u5DF2\u4FDD\u5B58\uFF1B\u5F53\u524D\u4ECD\u4F18\u5148\u4F7F\u7528\u73AF\u5883\u6216\u51ED\u636E\u5F15\u7528 ${next.config.apiKeyEnv}\u3002` : next.apiKeySource === "stored" ? "API Key \u5DF2\u4FDD\u5B58\u5E76\u7528\u4E8E\u5F53\u524D\u7F51\u5173\u3002" : "API Key \u5DF2\u4FDD\u5B58\u3002" });
21228
21318
  } catch {
21229
21319
  if (!mounted.current || version2 !== actionVersion.current) return;
21230
21320
  setApiKey("");
21231
- setNotice({ kind: "error", text: "API Key \u672A\u4FDD\u5B58\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002" });
21321
+ setNotice({ kind: "error", text: "\u4FDD\u5B58\u7ED3\u679C\u6682\u672A\u786E\u8BA4\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002" });
21232
21322
  } finally {
21233
21323
  if (mounted.current && version2 === actionVersion.current) setKeyBusy(false);
21234
21324
  }
@@ -21251,15 +21341,16 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21251
21341
  }
21252
21342
  };
21253
21343
  React.useEffect(() => {
21254
- if (!autoOpenPending.current || busy || keyBusy) return;
21344
+ if (!autoOpenPending.current || busy || keyBusy || opening || status === void 0) return;
21255
21345
  if (state === "waiting") {
21256
21346
  autoOpenPending.current = false;
21257
21347
  void openActivation();
21258
21348
  } else if (state === "error" || state === "cancelled" || state === "success") {
21259
21349
  autoOpenPending.current = false;
21260
21350
  }
21261
- }, [state, login?.jobId, busy, keyBusy]);
21351
+ }, [state, login?.jobId, busy, keyBusy, opening, status]);
21262
21352
  const desktopChecked = formSnapshot.value?.useDesktopCredential ?? status?.config.useDesktopCredential ?? true;
21353
+ const keySource = status?.apiKeySource === "reference" ? `\u73AF\u5883\u6216\u51ED\u636E\u5F15\u7528\uFF08${status.config.apiKeyEnv}\uFF09` : status?.apiKeySource === "stored" ? "\u5DF2\u4FDD\u5B58\u7684 API Key" : status?.apiKeySource === "device" ? "\u8BBE\u5907\u6388\u6743" : status?.apiKeyConfigured ? "\u5C1A\u672A\u786E\u8BA4" : "\u672A\u914D\u7F6E";
21263
21354
  return h(
21264
21355
  React.Fragment,
21265
21356
  null,
@@ -21275,7 +21366,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21275
21366
  checked: desktopChecked,
21276
21367
  disabled: formSnapshot.status !== "ready" || formSnapshot.value === void 0 || !formSnapshot.writable || pendingField.includes("useDesktopCredential"),
21277
21368
  label: "\u4F18\u5148\u4F7F\u7528\u684C\u9762\u767B\u5F55\u6001",
21278
- hint: "\u4EC5\u63A7\u5236\u8BFB\u53D6\u4F18\u5148\u7EA7\uFF0C\u4E0D\u4F1A\u4FEE\u6539\u6216\u5199\u56DE\u684C\u9762\u7AEF\u767B\u5F55\u6587\u4EF6\u3002",
21369
+ hint: "\u4F18\u5148\u663E\u793A\u684C\u9762\u7AEF\u767B\u5F55\u8D26\u53F7\u7684\u989D\u5EA6\u3002",
21279
21370
  onChange: (checked) => {
21280
21371
  void setFormField("useDesktopCredential", checked);
21281
21372
  }
@@ -21308,8 +21399,9 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21308
21399
  h(
21309
21400
  "section",
21310
21401
  { className: "odc-card" },
21311
- h("h3", null, "API Key\uFF08\u53EF\u9009\u8986\u76D6\uFF09"),
21312
- h("p", { className: "odc-hint" }, status?.apiKeyConfigured === true ? "\u5F53\u524D\u7F51\u5173\u5DF2\u6709\u53EF\u7528\u63A8\u7406\u51ED\u636E\u3002\u4F18\u5148\u7EA7\uFF1A\u73AF\u5883\u6216\u51ED\u636E\u5F15\u7528 \u2192 \u624B\u52A8\u4FDD\u5B58\u7684 API Key \u2192 \u8BBE\u5907\u6388\u6743\u4EE4\u724C\u3002" : "\u5F53\u524D\u7F51\u5173\u5C1A\u65E0\u63A8\u7406\u51ED\u636E\u3002\u53EF\u5B8C\u6210\u8BBE\u5907\u6388\u6743\u4EE5\u4F7F\u7528\u5B98\u65B9\u7F51\u5173\uFF0C\u6216\u4E3A\u5F53\u524D\u7F51\u5173\u5355\u72EC\u4FDD\u5B58 API Key\u3002"),
21402
+ h("h3", null, "API Key"),
21403
+ h("p", { className: "odc-meta", "aria-label": "\u5F53\u524D\u751F\u6548\u7684\u63A8\u7406\u51ED\u636E\u6765\u6E90" }, `\u5F53\u524D\u751F\u6548\u6765\u6E90\uFF1A${keySource}`),
21404
+ h("p", { className: "odc-hint" }, status?.apiKeyConfigured === true ? "\u5F53\u524D\u7F51\u5173\u5DF2\u914D\u7F6E\u63A8\u7406\u51ED\u636E\u3002\u53EF\u5728\u6B64\u4FDD\u5B58\u63D2\u4EF6\u4E13\u7528\u7684 API Key\u3002" : "\u5F53\u524D\u7F51\u5173\u5C1A\u65E0\u63A8\u7406\u51ED\u636E\u3002\u53EF\u5B8C\u6210\u8BBE\u5907\u6388\u6743\u4EE5\u4F7F\u7528\u5B98\u65B9\u7F51\u5173\uFF0C\u6216\u4E3A\u5F53\u524D\u7F51\u5173\u5355\u72EC\u4FDD\u5B58 API Key\u3002"),
21313
21405
  h(
21314
21406
  "form",
21315
21407
  { onSubmit: (event) => {
@@ -21378,6 +21470,19 @@ function SettingsPage({ caller, form }) {
21378
21470
  ...acceptedFormSnapshot,
21379
21471
  value: acceptedFormSnapshot.value === void 0 ? void 0 : { ...acceptedFormSnapshot.value, ...pendingValues }
21380
21472
  }), [acceptedFormSnapshot, pendingValues]);
21473
+ const acceptLoginStatus = React.useCallback((login) => {
21474
+ statusVersion.current += 1;
21475
+ loginVersion.current += 1;
21476
+ setStatus((previous) => previous === void 0 ? previous : { ...previous, login });
21477
+ setError(void 0);
21478
+ }, []);
21479
+ const acceptStatus = React.useCallback((next) => {
21480
+ statusVersion.current += 1;
21481
+ loginVersion.current += 1;
21482
+ setStatus(next);
21483
+ setModelsNotice(null);
21484
+ setError(void 0);
21485
+ }, []);
21381
21486
  const loadStatus = React.useCallback(async () => {
21382
21487
  const version2 = ++statusVersion.current;
21383
21488
  try {
@@ -21480,7 +21585,7 @@ function SettingsPage({ caller, form }) {
21480
21585
  if (!mounted.current || version2 !== modelsVersion.current) return;
21481
21586
  setStatus(next);
21482
21587
  setError(void 0);
21483
- setModelsNotice(next.modelsError === void 0 ? { kind: "status", text: `\u5DF2\u4ECE OpenAI \u5237\u65B0\u6A21\u578B\u5217\u8868\uFF0C\u5171 ${next.models.length} \u4E2A\u6A21\u578B\u3002` } : null);
21588
+ setModelsNotice(next.modelsError === void 0 ? { kind: "status", text: `\u5DF2\u4ECE\u5F53\u524D\u7F51\u5173\u5237\u65B0\u6A21\u578B\u76EE\u5F55\uFF0C\u5171 ${next.models.length} \u4E2A\u6A21\u578B\u3002` } : null);
21484
21589
  } catch {
21485
21590
  if (mounted.current && version2 === modelsVersion.current) setModelsNotice({ kind: "error", text: "\u6A21\u578B\u5237\u65B0\u672A\u5B8C\u6210\uFF0C\u8BF7\u68C0\u67E5\u51ED\u636E\u3001\u7F51\u5173\u4E0E\u7F51\u7EDC\u540E\u91CD\u8BD5\u3002" });
21486
21591
  } finally {
@@ -21501,10 +21606,7 @@ function SettingsPage({ caller, form }) {
21501
21606
  const login = await caller("loginStatus");
21502
21607
  if (stopped || !mounted.current || version2 !== loginVersion.current) return;
21503
21608
  setStatus((previous) => previous === void 0 ? previous : { ...previous, login });
21504
- if (!loginInFlight(login.state)) {
21505
- if (login.state === "success") void refresh();
21506
- else void loadStatus();
21507
- }
21609
+ if (!loginInFlight(login.state) && login.state !== "success") void loadStatus();
21508
21610
  } catch {
21509
21611
  }
21510
21612
  };
@@ -21518,6 +21620,11 @@ function SettingsPage({ caller, form }) {
21518
21620
  loginVersion.current += 1;
21519
21621
  };
21520
21622
  }, [caller, loadStatus, loginActive, mounted, refresh]);
21623
+ React.useEffect(() => {
21624
+ if (loginState !== "success") return;
21625
+ void loadStatus();
21626
+ void refresh(true);
21627
+ }, [loginState, status?.login.jobId, loadStatus, refresh]);
21521
21628
  const configuredSeconds = formSnapshot.value?.quotaRefreshSeconds ?? status?.config.quotaRefreshSeconds;
21522
21629
  const refreshIntervalSeconds = configuredSeconds === void 0 ? DEFAULT_QUOTA_REFRESH_SECONDS : normaliseQuotaRefreshSeconds(configuredSeconds);
21523
21630
  const quotaNextRefreshAt = status?.quota.nextRefreshAt;
@@ -21563,7 +21670,7 @@ function SettingsPage({ caller, form }) {
21563
21670
  notice: modelsNotice
21564
21671
  });
21565
21672
  } else if (tab === "connection") {
21566
- content = h(Connection, { status, formSnapshot, setFormField, pendingField, caller, loadStatus, refreshAfterLogin: refresh });
21673
+ content = h(Connection, { status, formSnapshot, setFormField, pendingField, caller, onLoginStatus: acceptLoginStatus, onStatus: acceptStatus });
21567
21674
  } else {
21568
21675
  content = h(Advanced, { status, formSnapshot, setFormField, pendingField });
21569
21676
  }
@@ -21571,7 +21678,7 @@ function SettingsPage({ caller, form }) {
21571
21678
  "div",
21572
21679
  { className: "odc-settings" },
21573
21680
  h("h2", null, "OpenDesign CoRouter"),
21574
- h("p", { className: "odc-intro" }, "\u5728\u4E00\u4E2A\u7B80\u6D01\u9762\u677F\u4E2D\u7BA1\u7406\u989D\u5EA6\u3001\u53CC Provider \u6A21\u578B\u3001\u767B\u5F55\u4E0E\u8FD0\u884C\u4FDD\u62A4\u3002"),
21681
+ h("p", { className: "odc-intro" }, "\u67E5\u770B\u989D\u5EA6\uFF0C\u7BA1\u7406\u6A21\u578B\u3001\u8FDE\u63A5\u4E0E\u8BF7\u6C42\u8BBE\u7F6E\u3002"),
21575
21682
  h("div", { className: "odc-tabs", role: "tablist", "aria-label": "CoRouter \u8BBE\u7F6E\u5206\u7C7B" }, TABS.map((item, index) => h("button", {
21576
21683
  key: item.id,
21577
21684
  ref: (node2) => {
@@ -3,7 +3,7 @@ export interface DeviceTokens {
3
3
  runtimeKey: string;
4
4
  }
5
5
  export declare const DEVICE_AUTH_ENDPOINT = "https://amr-api.open-design.ai/api/v1/cli/device-authorizations";
6
- export declare const DEVICE_AUTH_PLUGIN_VERSION = "0.1.6";
6
+ export declare const DEVICE_AUTH_PLUGIN_VERSION = "0.1.8";
7
7
  export declare const DEVICE_REQUEST_TIMEOUT_MS = 20000;
8
8
  /** One bounded launch step of the temporary activation window. */
9
9
  export declare const DEVICE_OPEN_TIMEOUT_MS = 30000;
@@ -122,9 +122,9 @@ function amount(value, label, negative = false) {
122
122
  if (typeof value !== "number" || !Number.isFinite(value) || !negative && value < 0) throw new Error(`${label} \u5FC5\u987B\u662F${negative ? "" : "\u975E\u8D1F"}\u6709\u9650\u6570\u5B57`);
123
123
  return value;
124
124
  }
125
- function positiveInteger(value, label, max) {
125
+ function positiveInteger(value, label, max, min = 1) {
126
126
  const result = count(value, label);
127
- if (result === 0 || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
127
+ if (result < min || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
128
128
  return result;
129
129
  }
130
130
  function parseEfforts(value) {
@@ -227,9 +227,9 @@ function parseStatusConfig(value) {
227
227
  apiKeyEnv,
228
228
  ...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
229
229
  ...value.modelSettings === void 0 ? {} : { modelSettings: parseModelSettingsMap(value.modelSettings) },
230
- ...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5) },
231
- ...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5) },
232
- ...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600) }
230
+ ...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5, 1e3) },
231
+ ...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5, 1e3) },
232
+ ...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600, 5) }
233
233
  };
234
234
  }
235
235
  function parseStatus(value) {
@@ -242,9 +242,13 @@ function parseStatus(value) {
242
242
  if (ids.has(model.id)) throw new Error(`\u6A21\u578B\u5217\u8868\u91CD\u590D\u4E86 id "${model.id}"`);
243
243
  ids.add(model.id);
244
244
  }
245
+ const apiKeyConfigured = flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA");
246
+ const apiKeySource = value.apiKeySource === void 0 ? void 0 : member(value.apiKeySource, ["reference", "stored", "device"], "\u63A8\u7406\u51ED\u636E\u6765\u6E90");
247
+ if (!apiKeyConfigured && apiKeySource !== void 0) throw new Error("\u672A\u914D\u7F6E\u51ED\u636E\u65F6\u4E0D\u80FD\u6307\u5B9A\u63A8\u7406\u51ED\u636E\u6765\u6E90");
245
248
  return {
246
249
  revision: text(value.revision, "\u914D\u7F6E\u7248\u672C", MAX_REVISION),
247
- apiKeyConfigured: flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
250
+ apiKeyConfigured,
251
+ ...apiKeySource === void 0 ? {} : { apiKeySource },
248
252
  ...value.sessionSource === void 0 ? {} : { sessionSource: member(value.sessionSource, SESSION_SOURCES, "\u767B\u5F55\u6001\u6765\u6E90") },
249
253
  quota: parseQuotaSnapshot(value.quota),
250
254
  login: parseLoginState(value.login),