dsh-opendesign-corouter 0.1.2 → 0.1.3

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.d.ts CHANGED
@@ -145,8 +145,9 @@ export interface OverviewProps {
145
145
  onRefresh: () => void;
146
146
  nextAutoRefreshAt?: string | undefined;
147
147
  refreshIntervalSeconds?: number | undefined;
148
+ onConnection?: (() => void) | undefined;
148
149
  }
149
- export declare function Overview({ status, busy, onRefresh, nextAutoRefreshAt, refreshIntervalSeconds }: OverviewProps): React.FunctionComponentElement<{
150
+ export declare function Overview({ status, busy, onRefresh, nextAutoRefreshAt, refreshIntervalSeconds, onConnection }: OverviewProps): React.FunctionComponentElement<{
150
151
  children?: React.ReactNode | undefined;
151
152
  }>;
152
153
  export interface ModelRowProps {
@@ -165,7 +166,7 @@ export interface ModelsProps {
165
166
  status: Status | undefined;
166
167
  formSnapshot: FormSnapshot;
167
168
  setFormField: (field: string, value: unknown) => Promise<boolean>;
168
- pendingField: string | null;
169
+ pendingField: readonly string[];
169
170
  onRefreshModels: () => void;
170
171
  refreshingModels: boolean;
171
172
  notice: Notice | null;
@@ -177,7 +178,7 @@ export interface AdvancedProps {
177
178
  status: Status | undefined;
178
179
  formSnapshot: FormSnapshot;
179
180
  setFormField: (field: string, value: unknown) => Promise<boolean>;
180
- pendingField: string | null;
181
+ pendingField: readonly string[];
181
182
  }
182
183
  export declare function Advanced({ status, formSnapshot, setFormField, pendingField }: AdvancedProps): React.FunctionComponentElement<{
183
184
  children?: React.ReactNode | undefined;
package/lib/client.js CHANGED
@@ -19942,56 +19942,45 @@ var API_PROTOCOL_OPTIONS = [
19942
19942
  ];
19943
19943
 
19944
19944
  // src/model-settings.ts
19945
- var MAX_ENTRIES = 512;
19946
- var MAX_MODEL_ID_LENGTH = 128;
19947
- var MODEL_ID = /^[A-Za-z0-9._:/-]{1,128}$/u;
19948
- var MAX_TEMPERATURE = 2;
19949
- var MAX_TOP_P = 1;
19950
- var MAX_TOKENS = 1e7;
19951
- var MAX_CONTEXT_WINDOW = 1e8;
19952
- var REASONING_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "ultra", "max"];
19953
- var RESERVED_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
19954
- var SETTINGS_FIELDS = /* @__PURE__ */ new Set(["enabled", "temperature", "topP", "maxTokens", "contextWindow", "reasoningEffort"]);
19955
- function flag(value) {
19956
- if (typeof value !== "boolean") throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 enabled \u5FC5\u987B\u662F\u5E03\u5C14\u503C");
19957
- return value;
19958
- }
19959
- function bounded(value, max, label) {
19960
- if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > max) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u7684 ${label} \u5FC5\u987B\u662F 0 \u5230 ${max} \u4E4B\u95F4\u7684\u6709\u9650\u6570\u5B57`);
19961
- return value;
19962
- }
19963
- function capacity(value, max, label) {
19964
- if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1 || value > max) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u7684 ${label} \u5FC5\u987B\u662F 1 \u5230 ${max} \u4E4B\u95F4\u7684\u6574\u6570`);
19965
- return value;
19966
- }
19967
- function effort(value) {
19968
- const hit = REASONING_EFFORTS.find((candidate) => candidate === value);
19969
- if (hit === void 0) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 reasoningEffort \u4E0D\u5728\u5141\u8BB8\u7684\u53D6\u503C\u5185");
19970
- return hit;
19971
- }
19972
- function settingsOf(value) {
19973
- if (!record2(value)) throw new Error("\u6BCF\u4E2A\u6A21\u578B\u7684\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
19974
- for (const field of Object.keys(value)) {
19975
- if (!SETTINGS_FIELDS.has(field)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u542B\u6709\u4E0D\u652F\u6301\u7684\u5B57\u6BB5");
19976
- }
19977
- const out = {};
19978
- if (value.enabled !== void 0) out.enabled = flag(value.enabled);
19979
- if (value.temperature !== void 0) out.temperature = bounded(value.temperature, MAX_TEMPERATURE, "temperature");
19980
- if (value.topP !== void 0) out.topP = bounded(value.topP, MAX_TOP_P, "topP");
19981
- if (value.maxTokens !== void 0) out.maxTokens = capacity(value.maxTokens, MAX_TOKENS, "maxTokens");
19982
- if (value.contextWindow !== void 0) out.contextWindow = capacity(value.contextWindow, MAX_CONTEXT_WINDOW, "contextWindow");
19983
- if (value.reasoningEffort !== void 0) out.reasoningEffort = effort(value.reasoningEffort);
19984
- return out;
19985
- }
19986
19945
  function parseModelSettingsMap(value) {
19987
- if (!record2(value)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
19946
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
19988
19947
  const keys = Object.keys(value);
19989
- if (keys.length > MAX_ENTRIES) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u6700\u591A\u5141\u8BB8 ${MAX_ENTRIES} \u4E2A\u6A21\u578B`);
19948
+ if (keys.length > 512) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u6700\u591A\u5141\u8BB8 512 \u4E2A\u6A21\u578B");
19949
+ const fields = /* @__PURE__ */ new Set(["enabled", "temperature", "topP", "maxTokens", "contextWindow", "reasoningEffort"]);
19950
+ const efforts = ["none", "minimal", "low", "medium", "high", "xhigh", "ultra", "max"];
19990
19951
  const out = {};
19991
19952
  for (const id of keys) {
19992
- if (RESERVED_KEYS.has(id)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u4E0D\u5141\u8BB8\u4FDD\u7559\u5B57\u6BB5\u540D");
19993
- if (!MODEL_ID.test(id)) throw new Error(`\u6A21\u578B ID \u5FC5\u987B\u662F 1\u2013${MAX_MODEL_ID_LENGTH} \u4F4D\u5B57\u6BCD\u3001\u6570\u5B57\u6216 . _ : / -`);
19994
- out[id] = settingsOf(value[id]);
19953
+ if (["__proto__", "constructor", "prototype"].includes(id)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u4E0D\u5141\u8BB8\u4FDD\u7559\u5B57\u6BB5\u540D");
19954
+ if (!/^[A-Za-z0-9._:/-]{1,128}$/u.test(id)) throw new Error("\u6A21\u578B ID \u5FC5\u987B\u662F 1\u2013128 \u4F4D\u5B57\u6BCD\u3001\u6570\u5B57\u6216 . _ : / -");
19955
+ const entry = value[id];
19956
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry)) throw new Error("\u6BCF\u4E2A\u6A21\u578B\u7684\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
19957
+ const settings = entry;
19958
+ for (const field of Object.keys(settings)) {
19959
+ if (!fields.has(field)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u542B\u6709\u4E0D\u652F\u6301\u7684\u5B57\u6BB5");
19960
+ }
19961
+ const parsed = {};
19962
+ if (settings.enabled !== void 0) {
19963
+ if (typeof settings.enabled !== "boolean") throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 enabled \u5FC5\u987B\u662F\u5E03\u5C14\u503C");
19964
+ parsed.enabled = settings.enabled;
19965
+ }
19966
+ for (const [field, max] of [["temperature", 2], ["topP", 1]]) {
19967
+ const item = settings[field];
19968
+ if (item === void 0) continue;
19969
+ if (typeof item !== "number" || !Number.isFinite(item) || item < 0 || item > max) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u7684 ${field} \u5FC5\u987B\u662F 0 \u5230 ${max} \u4E4B\u95F4\u7684\u6709\u9650\u6570\u5B57`);
19970
+ parsed[field] = item;
19971
+ }
19972
+ for (const [field, max] of [["maxTokens", 1e7], ["contextWindow", 1e8]]) {
19973
+ const item = settings[field];
19974
+ if (item === void 0) continue;
19975
+ if (typeof item !== "number" || !Number.isSafeInteger(item) || item < 1 || item > max) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u7684 ${field} \u5FC5\u987B\u662F 1 \u5230 ${max} \u4E4B\u95F4\u7684\u6574\u6570`);
19976
+ parsed[field] = item;
19977
+ }
19978
+ if (settings.reasoningEffort !== void 0) {
19979
+ if (typeof settings.reasoningEffort !== "string" || !efforts.includes(settings.reasoningEffort)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 reasoningEffort \u4E0D\u5728\u5141\u8BB8\u7684\u53D6\u503C\u5185");
19980
+ parsed.reasoningEffort = settings.reasoningEffort;
19981
+ }
19982
+ if (parsed.maxTokens !== void 0 && parsed.contextWindow !== void 0 && parsed.maxTokens >= parsed.contextWindow) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 maxTokens \u5FC5\u987B\u5C0F\u4E8E contextWindow");
19983
+ out[id] = parsed;
19995
19984
  }
19996
19985
  return out;
19997
19986
  }
@@ -20009,7 +19998,7 @@ var MAX_WINDOWS = 64;
20009
19998
  var MAX_API_KEY = 16384;
20010
19999
  var HTTP_ASCII = /^[\x21-\x7e]+$/u;
20011
20000
  var ENV_REF = /^[A-Za-z_][A-Za-z0-9_]*$/u;
20012
- var MODEL_ID2 = /^[A-Za-z0-9._:/-]{1,128}$/u;
20001
+ var MODEL_ID = /^[A-Za-z0-9._:/-]{1,128}$/u;
20013
20002
  var LOGIN_PHASES = ["idle", "launching", "waiting", "verifying", "success", "cancelled", "error"];
20014
20003
  var QUOTA_STATES = ["ok", "partial", "need-login", "error"];
20015
20004
  var SESSION_SOURCES = ["desktop", "login", "environment"];
@@ -20023,7 +20012,7 @@ function isoTime(value, label) {
20023
20012
  if (!Number.isFinite(Date.parse(time3))) throw new Error(`${label} \u5FC5\u987B\u662F ISO \u65F6\u95F4\u5B57\u7B26\u4E32`);
20024
20013
  return time3;
20025
20014
  }
20026
- function flag2(value, label) {
20015
+ function flag(value, label) {
20027
20016
  if (typeof value !== "boolean") throw new Error(`${label} \u5FC5\u987B\u662F\u5E03\u5C14\u503C`);
20028
20017
  return value;
20029
20018
  }
@@ -20079,11 +20068,11 @@ function parseQuotaSnapshot(value) {
20079
20068
  ...value.subscriptionPeriodStart === void 0 ? {} : { subscriptionPeriodStart: isoTime(value.subscriptionPeriodStart, "\u8BA2\u9605\u5468\u671F\u5F00\u59CB\u65F6\u95F4") },
20080
20069
  ...value.subscriptionPeriodEnd === void 0 ? {} : { subscriptionPeriodEnd: isoTime(value.subscriptionPeriodEnd, "\u8BA2\u9605\u5468\u671F\u7ED3\u675F\u65F6\u95F4") },
20081
20070
  ...value.nextRefreshAt === void 0 ? {} : { nextRefreshAt: isoTime(value.nextRefreshAt, "\u4E0B\u6B21\u81EA\u52A8\u5237\u65B0\u65F6\u95F4") },
20082
- ...value.stale === void 0 ? {} : { stale: flag2(value.stale, "\u5386\u53F2\u989D\u5EA6\u8BFB\u6570") },
20071
+ ...value.stale === void 0 ? {} : { stale: flag(value.stale, "\u5386\u53F2\u989D\u5EA6\u8BFB\u6570") },
20083
20072
  ...value.refreshFailures === void 0 ? {} : { refreshFailures: count(value.refreshFailures, "\u8FDE\u7EED\u5237\u65B0\u5931\u8D25\u6B21\u6570") },
20084
- ...value.autoRefreshPaused === void 0 ? {} : { autoRefreshPaused: flag2(value.autoRefreshPaused, "\u81EA\u52A8\u5237\u65B0\u6682\u505C\u72B6\u6001") },
20073
+ ...value.autoRefreshPaused === void 0 ? {} : { autoRefreshPaused: flag(value.autoRefreshPaused, "\u81EA\u52A8\u5237\u65B0\u6682\u505C\u72B6\u6001") },
20085
20074
  ...value.tier === void 0 ? {} : { tier: text(value.tier, "\u5957\u9910\u540D", MAX_TIER) },
20086
- ...value.eligible === void 0 ? {} : { eligible: flag2(value.eligible, "\u5957\u9910\u8D44\u683C") },
20075
+ ...value.eligible === void 0 ? {} : { eligible: flag(value.eligible, "\u5957\u9910\u8D44\u683C") },
20087
20076
  windows: windows.map(parseQuotaWindow),
20088
20077
  balances: {
20089
20078
  ...balances.subscriptionUsd === void 0 ? {} : { subscriptionUsd: amount(balances.subscriptionUsd, "\u8BA2\u9605\u4F59\u989D") },
@@ -20108,12 +20097,12 @@ function parseLoginState(value) {
20108
20097
  function parseStatusModel(value) {
20109
20098
  if (!record2(value)) throw new Error("\u6A21\u578B\u6761\u76EE\u5FC5\u987B\u662F\u5BF9\u8C61");
20110
20099
  const id = text(value.id, "\u6A21\u578B id", 128);
20111
- if (!MODEL_ID2.test(id)) throw new Error("\u6A21\u578B id \u542B\u4E0D\u5141\u8BB8\u7684\u5B57\u7B26");
20100
+ if (!MODEL_ID.test(id)) throw new Error("\u6A21\u578B id \u542B\u4E0D\u5141\u8BB8\u7684\u5B57\u7B26");
20112
20101
  return {
20113
20102
  id,
20114
20103
  name: text(value.name, "\u6A21\u578B\u540D", 128),
20115
20104
  group: member(value.group, MODEL_GROUPS, "\u6A21\u578B\u5206\u7EC4"),
20116
- ...value.enabled === void 0 ? {} : { enabled: flag2(value.enabled, "\u6A21\u578B\u542F\u7528\u72B6\u6001") },
20105
+ ...value.enabled === void 0 ? {} : { enabled: flag(value.enabled, "\u6A21\u578B\u542F\u7528\u72B6\u6001") },
20117
20106
  ...value.contextWindow === void 0 ? {} : { contextWindow: positiveInteger(value.contextWindow, "\u4E0A\u4E0B\u6587\u9884\u7B97", 1e8) },
20118
20107
  ...value.maxOutputTokens === void 0 ? {} : { maxOutputTokens: positiveInteger(value.maxOutputTokens, "\u6700\u5927\u8F93\u51FA", 1e7) },
20119
20108
  ...value.reasoningEfforts === void 0 ? {} : { reasoningEfforts: parseEfforts(value.reasoningEfforts) }
@@ -20124,8 +20113,8 @@ function parseStatusConfig(value) {
20124
20113
  const apiKeyEnv = text(value.apiKeyEnv, "\u51ED\u636E\u5F15\u7528\u540D", MAX_ENV_REF);
20125
20114
  if (!ENV_REF.test(apiKeyEnv)) throw new Error("\u51ED\u636E\u5F15\u7528\u540D\u5FC5\u987B\u662F\u5408\u6CD5\u6807\u8BC6\u7B26");
20126
20115
  return {
20127
- emptyTurnGuard: flag2(value.emptyTurnGuard, "\u7A7A\u8F6E\u4FDD\u62A4\u5F00\u5173"),
20128
- useDesktopCredential: flag2(value.useDesktopCredential, "\u684C\u9762\u767B\u5F55\u6001\u5F00\u5173"),
20116
+ emptyTurnGuard: flag(value.emptyTurnGuard, "\u7A7A\u8F6E\u4FDD\u62A4\u5F00\u5173"),
20117
+ useDesktopCredential: flag(value.useDesktopCredential, "\u684C\u9762\u767B\u5F55\u6001\u5F00\u5173"),
20129
20118
  baseURL: text(value.baseURL, "\u63A8\u7406\u5730\u5740", MAX_BASE_URL),
20130
20119
  apiKeyEnv,
20131
20120
  ...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
@@ -20147,7 +20136,7 @@ function parseStatus(value) {
20147
20136
  }
20148
20137
  return {
20149
20138
  revision: text(value.revision, "\u914D\u7F6E\u7248\u672C", MAX_REVISION),
20150
- apiKeyConfigured: flag2(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
20139
+ apiKeyConfigured: flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
20151
20140
  ...value.sessionSource === void 0 ? {} : { sessionSource: member(value.sessionSource, SESSION_SOURCES, "\u767B\u5F55\u6001\u6765\u6E90") },
20152
20141
  quota: parseQuotaSnapshot(value.quota),
20153
20142
  login: parseLoginState(value.login),
@@ -20215,7 +20204,7 @@ var DEFAULT_STREAM_IDLE_TIMEOUT_MS = 3e5;
20215
20204
  var MIN_STREAM_IDLE_TIMEOUT_MS = 1e3;
20216
20205
  var MAX_STREAM_IDLE_TIMEOUT_MS = 18e5;
20217
20206
  var MAX_OUTPUT_TOKENS = 1e7;
20218
- var MAX_CONTEXT_WINDOW2 = 1e8;
20207
+ var MAX_CONTEXT_WINDOW = 1e8;
20219
20208
  var GENERIC_ERROR = "\u64CD\u4F5C\u672A\u5B8C\u6210\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
20220
20209
  var LOGIN_LABELS = {
20221
20210
  idle: "\u5C1A\u672A\u5F00\u59CB\u72EC\u7ACB\u767B\u5F55",
@@ -20248,8 +20237,9 @@ function installStyles() {
20248
20237
  .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}
20249
20238
  .odc-model-details{margin-top:8px}.odc-model-details>summary{cursor:pointer;color:var(--dsw-alias-label-secondary,inherit);font-size:11px;line-height:1.7}.odc-model-editor{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2px 10px;margin-top:8px}
20250
20239
  .odc-field{display:grid;gap:6px;margin-top:14px}.odc-field-compact{margin-top:8px}.odc-field label,.odc-switch-text{font-size:12px;font-weight:550}.odc-input{width:100%;min-width:0;min-height:34px;padding:7px 9px;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}.odc-field-compact .odc-input{min-height:30px;padding:5px 8px;font-size:11px}.odc-input::placeholder{color:var(--dsw-alias-label-secondary,inherit);opacity:1}.odc-input:disabled{opacity:.55}
20251
- .odc-switch{display:flex;align-items:flex-start;gap:10px;cursor:pointer}.odc-switch input{width:16px;height:16px;flex:none;margin:2px 0 0;accent-color:var(--dsw-alias-brand-primary,Highlight)}.odc-switch>span{display:grid;gap:4px;min-width:0}.odc-switch:has(input:disabled){cursor:not-allowed;opacity:.6}.odc-divider{height:1px;border:0;background:var(--dsw-alias-border-l4,transparent);margin:2px 0}.odc-link{color:var(--dsw-alias-brand-primary,inherit);text-underline-offset:3px}
20240
+ .odc-switch{display:flex;align-items:center;gap:12px;min-height:44px;padding:6px 2px;cursor:pointer}.odc-switch input{appearance:auto;width:20px;height:20px;flex:none;margin:0;cursor:inherit;accent-color:var(--dsw-alias-brand-primary,Highlight)}.odc-switch>span{display:grid;gap:4px;min-width:0}.odc-switch:has(input:disabled){cursor:not-allowed;opacity:.6}.odc-divider{height:1px;border:0;background:var(--dsw-alias-border-l4,transparent);margin:2px 0}.odc-link{color:var(--dsw-alias-brand-primary,inherit);text-underline-offset:3px}
20252
20241
  .odc-readonly{display:grid;gap:10px;margin-top:14px;padding:10px 12px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,transparent)}.odc-code{display:block;min-width:0;color:var(--dsw-alias-label-primary,inherit);font-family:ui-monospace,'Cascadia Mono',Consolas,monospace;font-size:11px;line-height:1.6;overflow-wrap:anywhere}
20242
+ .odc-timing{padding:12px 0;border-top:1px solid var(--dsw-alias-border-l4,transparent)}.odc-timing .odc-metric{min-height:0}.odc-settings>.odc-notice{margin-bottom:14px}.odc-model-details>summary{min-height:32px;padding:6px 0}
20253
20243
  .odc-field-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))}
20254
20244
  .odc-settings :focus-visible{outline:2px solid var(--dsw-alias-brand-primary,Highlight);outline-offset:3px}@media(max-width:680px){.odc-quota-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.odc-model-groups{grid-template-columns:1fr}.odc-model-editor{grid-template-columns:1fr}}@media(max-width:380px){.odc-quota-grid{grid-template-columns:1fr}.odc-card{padding:12px}}
20255
20245
  `;
@@ -20391,12 +20381,12 @@ function QuotaView({ quota, nextAutoRefreshAt, refreshIntervalSeconds }) {
20391
20381
  {
20392
20382
  label: "\u8BA2\u9605\u8D26\u671F\u7ED3\u675F",
20393
20383
  value: formatTime(quota.subscriptionPeriodEnd),
20394
- hint: `\u8D26\u671F\u5F00\u59CB\uFF1A${formatTime(quota.subscriptionPeriodStart)} \xB7 \u672A\u77E5\u65F6\u95F4\u4E0D\u63A8\u65AD`
20384
+ hint: `\u8D26\u671F\u5F00\u59CB\uFF1A${formatTime(quota.subscriptionPeriodStart)}`
20395
20385
  },
20396
20386
  {
20397
20387
  label: "\u4E0B\u6B21\u989D\u5EA6\u6062\u590D",
20398
20388
  value: formatTime(nextWindowResetAt(quota.windows, Date.now())),
20399
- hint: "\u53EA\u53D6\u7A97\u53E3 resetsAt \u4E2D\u6700\u65E9\u7684\u672A\u5230\u671F\u65F6\u95F4\uFF1B\u65E0\u7A97\u53E3\u6216\u672A\u77E5\u65F6\u4FDD\u6301 \u2014"
20389
+ hint: "\u6700\u65E9\u6062\u590D\u7684\u8D60\u9001\u7A97\u53E3\uFF1B\u4E0D\u4EE3\u8868\u94B1\u5305\u5230\u8D26\u65F6\u95F4"
20400
20390
  },
20401
20391
  {
20402
20392
  label: "\u4E0B\u6B21\u81EA\u52A8\u5237\u65B0",
@@ -20455,15 +20445,20 @@ function QuotaView({ quota, nextAutoRefreshAt, refreshIntervalSeconds }) {
20455
20445
  h("strong", { className: "odc-metric-value" }, metric.value),
20456
20446
  h("span", { className: "odc-hint" }, metric.hint)
20457
20447
  ))),
20458
- h("div", { className: "odc-quota-grid" }, timing.map((metric) => h(
20448
+ h("div", { className: "odc-quota-grid odc-timing", "aria-label": "\u989D\u5EA6\u65F6\u95F4\u5B89\u6392" }, timing.map((metric) => h(
20459
20449
  "div",
20460
- { className: "odc-card odc-metric", key: metric.label },
20450
+ { className: "odc-metric", key: metric.label },
20461
20451
  h("span", { className: "odc-label" }, metric.label),
20462
20452
  h("strong", { className: "odc-metric-value odc-metric-text" }, metric.value),
20463
20453
  h("span", { className: "odc-hint" }, metric.hint)
20464
20454
  ))),
20465
20455
  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` : ""}`),
20466
- h("p", { className: "odc-hint" }, "\u989D\u5EA6\u6570\u636E\u53EA\u8BFB\u5C55\u793A\uFF0C\u4E0D\u5199\u5165\u8D26\u53F7\u6216\u684C\u9762\u51ED\u636E\uFF1B\u684C\u9762\u767B\u5F55\u6001\u4E0D\u53EF\u7528\u65F6\u4F1A\u81EA\u52A8\u56DE\u9000\u5230\u5DF2\u4FDD\u5B58\u4F1A\u8BDD\u3002"),
20456
+ h(
20457
+ "details",
20458
+ { className: "odc-model-details" },
20459
+ h("summary", null, "\u5982\u4F55\u7406\u89E3\u8FD9\u4E9B\u989D\u5EA6\uFF1F"),
20460
+ 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")
20461
+ ),
20467
20462
  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
20468
20463
  );
20469
20464
  }
@@ -20525,10 +20520,21 @@ function quotaAutoRefresh(secondsRaw, nextRefreshAt, now, backingOff = false) {
20525
20520
  const delayMs = Number.isFinite(planDelay) && planDelay > 0 ? backingOff ? plannedDelay : Math.min(intervalMs, plannedDelay) : intervalMs;
20526
20521
  return { delayMs, at: new Date(now + delayMs).toISOString(), intervalSeconds };
20527
20522
  }
20528
- function Overview({ status, busy, onRefresh, nextAutoRefreshAt, refreshIntervalSeconds }) {
20523
+ function Overview({ status, busy, onRefresh, nextAutoRefreshAt, refreshIntervalSeconds, onConnection }) {
20529
20524
  return h(
20530
20525
  React.Fragment,
20531
20526
  null,
20527
+ status !== void 0 && (status.apiKeyConfigured === false || status.quota.state === "need-login") ? h(
20528
+ "section",
20529
+ { className: "odc-card odc-row", "aria-label": "\u8FDE\u63A5\u5F85\u5B8C\u6210" },
20530
+ h(
20531
+ "div",
20532
+ null,
20533
+ h("h3", null, "\u5148\u5B8C\u6210\u8FDE\u63A5"),
20534
+ h("p", { className: "odc-hint" }, status.apiKeyConfigured === false ? "\u63A8\u7406\u5C1A\u7F3A API Key\uFF1B\u989D\u5EA6\u767B\u5F55\u4E0E\u63A8\u7406\u51ED\u636E\u5206\u522B\u914D\u7F6E\u3002" : "API Key \u5DF2\u914D\u7F6E\uFF1B\u767B\u5F55\u540E\u5373\u53EF\u67E5\u770B\u8D26\u53F7\u989D\u5EA6\u3002")
20535
+ ),
20536
+ onConnection === void 0 ? null : h("button", { type: "button", className: "odc-button odc-button-primary", onClick: onConnection }, "\u524D\u5F80\u8FDE\u63A5\u4E0E\u767B\u5F55")
20537
+ ) : null,
20532
20538
  h(
20533
20539
  "div",
20534
20540
  { className: "odc-card-head" },
@@ -20542,7 +20548,7 @@ var NUMERIC_FIELDS = {
20542
20548
  temperature: { label: "\u6E29\u5EA6", hint: "0\u20132\uFF1B\u7559\u7A7A\u7EE7\u627F\u9ED8\u8BA4\u3002", min: 0, max: 2 },
20543
20549
  topP: { label: "Top P", hint: "0\u20131\uFF1B\u7559\u7A7A\u7EE7\u627F\u9ED8\u8BA4\u3002", min: 0, max: 1 },
20544
20550
  maxTokens: { label: "\u6700\u5927\u8F93\u51FA\uFF08tokens\uFF09", hint: "\u6B63\u6574\u6570\uFF1B\u7559\u7A7A\u7EE7\u627F\u76EE\u5F55\u9ED8\u8BA4\u3002", min: 1, max: MAX_OUTPUT_TOKENS, integer: true },
20545
- contextWindow: { label: "\u4E0A\u4E0B\u6587\u9884\u7B97\uFF08tokens\uFF09", hint: "\u6B63\u6574\u6570\uFF1B\u7559\u7A7A\u7EE7\u627F\u76EE\u5F55\u9ED8\u8BA4\u3002", min: 1, max: MAX_CONTEXT_WINDOW2, integer: true }
20551
+ contextWindow: { label: "\u4E0A\u4E0B\u6587\u9884\u7B97\uFF08tokens\uFF09", hint: "\u6B63\u6574\u6570\uFF1B\u7559\u7A7A\u7EE7\u627F\u76EE\u5F55\u9ED8\u8BA4\u3002", min: 1, max: MAX_CONTEXT_WINDOW, integer: true }
20546
20552
  };
20547
20553
  var NUMERIC_ORDER = ["temperature", "topP", "maxTokens", "contextWindow"];
20548
20554
  function OptionalNumberField({ id, field, value, disabled, resetToken, onSave }) {
@@ -20627,12 +20633,12 @@ function EffortField({ id, model, value, disabled, onChange }) {
20627
20633
  const next = event.target.value;
20628
20634
  void (async () => {
20629
20635
  const saved = await onChange(next);
20630
- if (mounted.current && !saved) setError("\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u8BF7\u91CD\u8BD5\u3002");
20636
+ if (mounted.current) setError(saved ? void 0 : "\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u8BF7\u91CD\u8BD5\u3002");
20631
20637
  })();
20632
20638
  }
20633
20639
  }, [
20634
20640
  h("option", { key: "", value: "" }, "\u7EE7\u627F\u9ED8\u8BA4"),
20635
- ...options.map((effort2) => h("option", { key: effort2, value: effort2 }, effort2))
20641
+ ...options.map((effort) => h("option", { key: effort, value: effort }, effort))
20636
20642
  ]),
20637
20643
  h("small", {
20638
20644
  className: error62 === void 0 ? "odc-hint" : "odc-hint odc-field-error",
@@ -20650,13 +20656,19 @@ function ModelRow({ model, settings, authoritative, writable, pending, onCommit
20650
20656
  const hasOverrides = Object.keys(settings).length > 0;
20651
20657
  const commit = async (next) => {
20652
20658
  const saved = await onCommit(next);
20653
- if (mounted.current && !saved) setError("\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u8BF7\u91CD\u8BD5\u3002");
20659
+ if (mounted.current) setError(saved ? void 0 : "\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u8BF7\u91CD\u8BD5\u3002");
20654
20660
  return saved;
20655
20661
  };
20656
20662
  const saveField = async (key, value) => {
20657
20663
  const next = { ...settings };
20658
20664
  if (value === void 0) delete next[key];
20659
20665
  else next[key] = value;
20666
+ const output2 = next.maxTokens ?? model.maxOutputTokens;
20667
+ const context = next.contextWindow ?? model.contextWindow;
20668
+ if (output2 !== void 0 && context !== void 0 && output2 >= context) {
20669
+ setError("\u6700\u5927\u8F93\u51FA\u5FC5\u987B\u5C0F\u4E8E\u4E0A\u4E0B\u6587\u9884\u7B97\uFF1B\u8BF7\u5148\u589E\u5927\u4E0A\u4E0B\u6587\u9884\u7B97\u6216\u51CF\u5C0F\u6700\u5927\u8F93\u51FA\u3002");
20670
+ return false;
20671
+ }
20660
20672
  setError(void 0);
20661
20673
  return commit(next);
20662
20674
  };
@@ -20698,11 +20710,12 @@ function ModelRow({ model, settings, authoritative, writable, pending, onCommit
20698
20710
  } }, "\u91CD\u7F6E")
20699
20711
  )
20700
20712
  ),
20701
- h("p", { className: "odc-model-meta" }, facts),
20702
20713
  h(
20703
20714
  "details",
20704
20715
  { className: "odc-model-details" },
20705
- h("summary", { "aria-label": `${model.name} \u53C2\u6570\u8BBE\u7F6E` }, "\u53C2\u6570\u8BBE\u7F6E"),
20716
+ h("summary", { "aria-label": `${model.name} \u53C2\u6570\u8BBE\u7F6E` }, hasOverrides ? "\u53C2\u6570\u8BBE\u7F6E \xB7 \u5DF2\u81EA\u5B9A\u4E49" : "\u53C2\u6570\u8BBE\u7F6E \xB7 \u4F7F\u7528\u9ED8\u8BA4\u503C"),
20717
+ h("p", { className: "odc-model-meta" }, facts),
20718
+ h("p", { className: "odc-hint" }, "\u6570\u503C\u79BB\u5F00\u8F93\u5165\u6846\u540E\u4FDD\u5B58\uFF0C\u7559\u7A7A\u7EE7\u627F\u9ED8\u8BA4\u3002"),
20706
20719
  h(
20707
20720
  "div",
20708
20721
  { className: "odc-model-editor" },
@@ -20735,10 +20748,12 @@ function ModelRow({ model, settings, authoritative, writable, pending, onCommit
20735
20748
  }
20736
20749
  function ModelGroup({ title, group, models, settingsMap, authoritative, writable, pending, onCommit }) {
20737
20750
  const [query, setQuery] = React.useState("");
20751
+ const [expanded, setExpanded] = React.useState(false);
20738
20752
  const id = React.useId();
20739
20753
  const normalized = query.trim().toLocaleLowerCase();
20740
20754
  const groupModels = models.filter((model) => model.group === group);
20741
20755
  const filtered = groupModels.filter((model) => normalized === "" || `${model.name} ${model.id}`.toLocaleLowerCase().includes(normalized));
20756
+ const visible = normalized !== "" || expanded ? filtered : filtered.slice(0, 6);
20742
20757
  const enabledCount = groupModels.filter((model) => modelEnabled(model, settingsMap[model.id], authoritative)).length;
20743
20758
  return h(
20744
20759
  "section",
@@ -20755,10 +20770,10 @@ function ModelGroup({ title, group, models, settingsMap, authoritative, writable
20755
20770
  className: "odc-input",
20756
20771
  type: "search",
20757
20772
  value: query,
20758
- placeholder: "\u8F93\u5165\u6A21\u578B\u540D\u79F0\u6216 ID",
20773
+ placeholder: "\u641C\u7D22\u5168\u90E8\u6A21\u578B\u7684\u540D\u79F0\u6216 ID",
20759
20774
  onChange: (event) => setQuery(event.target.value)
20760
20775
  }),
20761
- filtered.length === 0 ? h("p", { className: "odc-hint", role: "status" }, "\u6CA1\u6709\u5339\u914D\u7684\u6A21\u578B\u3002") : h("ul", { className: "odc-model-list" }, filtered.map((model) => h(ModelRow, {
20776
+ filtered.length === 0 ? h("p", { className: "odc-hint", role: "status" }, "\u6CA1\u6709\u5339\u914D\u7684\u6A21\u578B\u3002") : h("ul", { id: `${id}-list`, className: "odc-model-list" }, visible.map((model) => h(ModelRow, {
20762
20777
  key: model.id,
20763
20778
  model,
20764
20779
  settings: modelSettingsEntry(settingsMap, model.id),
@@ -20766,15 +20781,23 @@ function ModelGroup({ title, group, models, settingsMap, authoritative, writable
20766
20781
  writable,
20767
20782
  pending,
20768
20783
  onCommit: (next) => onCommit(model.id, next)
20769
- })))
20784
+ }))),
20785
+ normalized === "" && filtered.length > 6 ? h("button", {
20786
+ type: "button",
20787
+ className: "odc-button",
20788
+ style: { marginTop: 12 },
20789
+ "aria-expanded": expanded,
20790
+ "aria-controls": `${id}-list`,
20791
+ onClick: () => setExpanded((value) => !value)
20792
+ }, expanded ? "\u6536\u8D77\u6A21\u578B\u5217\u8868" : `\u663E\u793A\u5168\u90E8 ${filtered.length} \u4E2A\u6A21\u578B`) : null
20770
20793
  );
20771
20794
  }
20772
20795
  function Models({ status, formSnapshot, setFormField, pendingField, onRefreshModels, refreshingModels, notice }) {
20773
20796
  const formReady = formSnapshot.status === "ready" && formSnapshot.value !== void 0;
20774
20797
  const settingsMap = formReady ? formSnapshot.value?.modelSettings ?? {} : status?.config.modelSettings ?? {};
20775
20798
  const authoritative = formReady || status?.config.modelSettings !== void 0;
20776
- const writable = formSnapshot.writable;
20777
- const pending = pendingField === "modelSettings";
20799
+ const writable = formSnapshot.status === "ready" && formSnapshot.value !== void 0 && formSnapshot.writable;
20800
+ const pending = pendingField.includes("modelSettings");
20778
20801
  const latestSettings = React.useRef(settingsMap);
20779
20802
  React.useEffect(() => {
20780
20803
  latestSettings.current = settingsMap;
@@ -20886,7 +20909,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
20886
20909
  React.useEffect(() => {
20887
20910
  setApiKeyEnv(formSnapshot.value?.apiKeyEnv ?? status?.config.apiKeyEnv ?? "");
20888
20911
  }, [formSnapshot.value?.apiKeyEnv, status?.config.apiKeyEnv]);
20889
- const writable = formSnapshot.writable;
20912
+ const writable = formSnapshot.status === "ready" && formSnapshot.value !== void 0 && formSnapshot.writable;
20890
20913
  const configuredProtocol = formSnapshot.value?.apiProtocol ?? status?.config.apiProtocol;
20891
20914
  const protocol = configuredProtocol !== void 0 && API_PROTOCOL_OPTIONS.some((option) => option.id === configuredProtocol) ? configuredProtocol : "chat-completions";
20892
20915
  const baseURL = formSnapshot.value?.baseURL ?? status?.config.baseURL ?? "";
@@ -20896,8 +20919,8 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
20896
20919
  const selected = API_PROTOCOL_OPTIONS.find((option) => option.id === protocol);
20897
20920
  const saveKeyRef = async () => {
20898
20921
  const value = apiKeyEnv.trim();
20899
- if (value === "") {
20900
- setKeyNotice({ kind: "error", text: "\u914D\u7F6E\u503C\u4E0D\u80FD\u4E3A\u7A7A\u3002" });
20922
+ if (!/^[A-Za-z_][A-Za-z0-9_]{0,127}$/u.test(value)) {
20923
+ setKeyNotice({ kind: "error", text: "\u5F15\u7528\u540D\u9700\u4E3A 1\u2013128 \u4F4D\u5B57\u6BCD\u3001\u6570\u5B57\u6216\u4E0B\u5212\u7EBF\uFF0C\u4E14\u4E0D\u80FD\u4EE5\u6570\u5B57\u5F00\u5934\u3002" });
20901
20924
  return;
20902
20925
  }
20903
20926
  setKeyNotice(null);
@@ -20918,7 +20941,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
20918
20941
  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"),
20919
20942
  h("div", { style: { marginTop: 14 } }, h(Switch, {
20920
20943
  checked: formSnapshot.value?.emptyTurnGuard ?? status?.config.emptyTurnGuard ?? true,
20921
- disabled: !writable || pendingField === "emptyTurnGuard",
20944
+ disabled: !writable || pendingField.includes("emptyTurnGuard"),
20922
20945
  label: "\u542F\u7528\u7A7A\u8F6E\u76D1\u63A7",
20923
20946
  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`,
20924
20947
  onChange: (checked) => {
@@ -20939,7 +20962,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
20939
20962
  id: "odc-api-protocol",
20940
20963
  className: "odc-input",
20941
20964
  value: protocol,
20942
- disabled: !writable || pendingField === "apiProtocol",
20965
+ disabled: !writable || pendingField.includes("apiProtocol"),
20943
20966
  onChange: (event) => {
20944
20967
  void setFormField("apiProtocol", event.target.value);
20945
20968
  }
@@ -20988,7 +21011,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
20988
21011
  h(
20989
21012
  "div",
20990
21013
  { className: "odc-actions", style: { marginTop: 10 } },
20991
- h("button", { className: "odc-button", type: "button", disabled: !writable || pendingField === "apiKeyEnv", onClick: () => {
21014
+ h("button", { className: "odc-button", type: "button", disabled: !writable || pendingField.includes("apiKeyEnv"), onClick: () => {
20992
21015
  void saveKeyRef();
20993
21016
  } }, "\u4FDD\u5B58\u5F15\u7528\u540D")
20994
21017
  ),
@@ -21007,7 +21030,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
21007
21030
  min: MIN_REQUEST_TIMEOUT_MS,
21008
21031
  max: MAX_REQUEST_TIMEOUT_MS,
21009
21032
  integer: true,
21010
- disabled: !writable || pendingField === "requestTimeoutMs",
21033
+ disabled: !writable || pendingField.includes("requestTimeoutMs"),
21011
21034
  onCommit: (value) => setFormField("requestTimeoutMs", value)
21012
21035
  }),
21013
21036
  h(NumberField, {
@@ -21018,7 +21041,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
21018
21041
  min: MIN_STREAM_IDLE_TIMEOUT_MS,
21019
21042
  max: MAX_STREAM_IDLE_TIMEOUT_MS,
21020
21043
  integer: true,
21021
- disabled: !writable || pendingField === "streamIdleTimeoutMs",
21044
+ disabled: !writable || pendingField.includes("streamIdleTimeoutMs"),
21022
21045
  onCommit: (value) => setFormField("streamIdleTimeoutMs", value)
21023
21046
  }),
21024
21047
  h(NumberField, {
@@ -21029,7 +21052,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
21029
21052
  min: MIN_QUOTA_REFRESH_SECONDS,
21030
21053
  max: MAX_QUOTA_REFRESH_SECONDS,
21031
21054
  integer: true,
21032
- disabled: !writable || pendingField === "quotaRefreshSeconds",
21055
+ disabled: !writable || pendingField.includes("quotaRefreshSeconds"),
21033
21056
  onCommit: (value) => setFormField("quotaRefreshSeconds", value)
21034
21057
  })
21035
21058
  )
@@ -21060,7 +21083,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21060
21083
  const state = login?.state ?? "idle";
21061
21084
  const inFlight = loginInFlight(state);
21062
21085
  const startLogin = async () => {
21063
- if (status === void 0 || busy) return;
21086
+ if (status === void 0 || busy || keyBusy) return;
21064
21087
  const version2 = ++actionVersion.current;
21065
21088
  setBusy(true);
21066
21089
  setNotice({ kind: "status", text: "\u6B63\u5728\u542F\u52A8\u5B98\u65B9\u767B\u5F55\u2026" });
@@ -21076,7 +21099,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21076
21099
  }
21077
21100
  };
21078
21101
  const cancelLogin = async () => {
21079
- if (login?.jobId == null || busy) return;
21102
+ if (login?.jobId == null || busy || keyBusy) return;
21080
21103
  const version2 = ++actionVersion.current;
21081
21104
  setBusy(true);
21082
21105
  try {
@@ -21092,7 +21115,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21092
21115
  };
21093
21116
  const saveKey = async (event) => {
21094
21117
  event.preventDefault();
21095
- if (status === void 0 || keyBusy || apiKey.trim() === "") {
21118
+ if (status === void 0 || busy || inFlight || keyBusy || apiKey.trim() === "") {
21096
21119
  if (apiKey.trim() === "") setNotice({ kind: "error", text: "\u8BF7\u8F93\u5165 API Key \u540E\u518D\u4FDD\u5B58\u3002" });
21097
21120
  return;
21098
21121
  }
@@ -21127,7 +21150,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21127
21150
  { style: { marginTop: 14 } },
21128
21151
  h(Switch, {
21129
21152
  checked: desktopChecked,
21130
- disabled: !formSnapshot.writable || pendingField === "useDesktopCredential",
21153
+ disabled: formSnapshot.status !== "ready" || formSnapshot.value === void 0 || !formSnapshot.writable || pendingField.includes("useDesktopCredential"),
21131
21154
  label: "\u4F18\u5148\u4F7F\u7528\u684C\u9762\u767B\u5F55\u6001",
21132
21155
  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",
21133
21156
  onChange: (checked) => {
@@ -21145,10 +21168,10 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21145
21168
  h(
21146
21169
  "div",
21147
21170
  { className: "odc-actions", style: { marginTop: 14 } },
21148
- h("button", { className: "odc-button odc-button-primary", type: "button", disabled: status === void 0 || busy || inFlight, onClick: () => {
21171
+ h("button", { className: "odc-button odc-button-primary", type: "button", disabled: status === void 0 || busy || keyBusy || inFlight, onClick: () => {
21149
21172
  void startLogin();
21150
21173
  } }, "\u767B\u5F55\u5E76\u4FDD\u5B58\u4F1A\u8BDD"),
21151
- inFlight ? h("button", { className: "odc-button", type: "button", disabled: busy || login?.jobId == null, onClick: () => {
21174
+ inFlight ? h("button", { className: "odc-button", type: "button", disabled: busy || keyBusy || login?.jobId == null, onClick: () => {
21152
21175
  void cancelLogin();
21153
21176
  } }, "\u53D6\u6D88\u767B\u5F55") : null,
21154
21177
  h("a", { className: "odc-link", href: OFFICIAL_SITE, target: "_blank", rel: "noreferrer noopener" }, "\u6253\u5F00 CoRouter \u5B98\u7F51")
@@ -21178,7 +21201,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21178
21201
  autoComplete: "new-password",
21179
21202
  autoCapitalize: "off",
21180
21203
  spellCheck: false,
21181
- disabled: status === void 0 || keyBusy,
21204
+ disabled: status === void 0 || busy || inFlight || keyBusy,
21182
21205
  placeholder: "\u4EC5\u7528\u4E8E\u672C\u6B21\u4FDD\u5B58\uFF0C\u4E0D\u4F1A\u56DE\u586B",
21183
21206
  onChange: (event) => setApiKey(event.target.value)
21184
21207
  }),
@@ -21187,7 +21210,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21187
21210
  h(
21188
21211
  "div",
21189
21212
  { className: "odc-actions", style: { marginTop: 12 } },
21190
- h("button", { className: "odc-button", type: "submit", disabled: status === void 0 || keyBusy || apiKey.trim() === "" }, keyBusy ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58 API Key")
21213
+ h("button", { className: "odc-button", type: "submit", disabled: status === void 0 || busy || inFlight || keyBusy || apiKey.trim() === "" }, keyBusy ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58 API Key")
21191
21214
  )
21192
21215
  )
21193
21216
  )
@@ -21210,7 +21233,8 @@ function SettingsPage({ caller, form }) {
21210
21233
  const [refreshing, setRefreshing] = React.useState(false);
21211
21234
  const [refreshingModels, setRefreshingModels] = React.useState(false);
21212
21235
  const [modelsNotice, setModelsNotice] = React.useState(null);
21213
- const [pendingField, setPendingField] = React.useState(null);
21236
+ const [pendingField, setPendingField] = React.useState([]);
21237
+ const writeTail = React.useRef(Promise.resolve());
21214
21238
  const [formNotice, setFormNotice] = React.useState(null);
21215
21239
  const [scheduleTick, setScheduleTick] = React.useState(0);
21216
21240
  const statusVersion = React.useRef(0);
@@ -21219,7 +21243,15 @@ function SettingsPage({ caller, form }) {
21219
21243
  const modelsVersion = React.useRef(0);
21220
21244
  const tabRefs = React.useRef([]);
21221
21245
  const baseId = React.useId();
21222
- const formSnapshot = useFormSnapshot(form);
21246
+ const acceptedFormSnapshot = useFormSnapshot(form);
21247
+ const [pendingValues, setPendingValues] = React.useState({});
21248
+ const writeVersions = React.useRef(/* @__PURE__ */ new Map());
21249
+ const nextWriteVersion = React.useRef(0);
21250
+ const batchWriteFailed = React.useRef(false);
21251
+ const formSnapshot = React.useMemo(() => ({
21252
+ ...acceptedFormSnapshot,
21253
+ value: acceptedFormSnapshot.value === void 0 ? void 0 : { ...acceptedFormSnapshot.value, ...pendingValues }
21254
+ }), [acceptedFormSnapshot, pendingValues]);
21223
21255
  const loadStatus = React.useCallback(async () => {
21224
21256
  const version2 = ++statusVersion.current;
21225
21257
  try {
@@ -21263,6 +21295,7 @@ function SettingsPage({ caller, form }) {
21263
21295
  }
21264
21296
  }, [caller, loadStatus, mounted]);
21265
21297
  React.useEffect(() => {
21298
+ void loadStatus();
21266
21299
  void refresh();
21267
21300
  return () => {
21268
21301
  statusVersion.current += 1;
@@ -21272,20 +21305,41 @@ function SettingsPage({ caller, form }) {
21272
21305
  refreshBusy.current = false;
21273
21306
  forcedRefreshPending.current = false;
21274
21307
  };
21275
- }, [refresh]);
21308
+ }, [loadStatus, refresh]);
21276
21309
  const setFormField = React.useCallback(async (field, value) => {
21277
- setPendingField(field);
21278
- setFormNotice(null);
21310
+ const snapshot = form.getSnapshot();
21311
+ if (snapshot.status !== "ready" || snapshot.value === void 0 || !snapshot.writable || writeVersions.current.has(field)) return false;
21312
+ if (writeVersions.current.size === 0) batchWriteFailed.current = false;
21313
+ const version2 = ++nextWriteVersion.current;
21314
+ writeVersions.current.set(field, version2);
21315
+ setPendingField([...writeVersions.current.keys()]);
21316
+ setPendingValues((previous) => ({ ...previous, [field]: value }));
21317
+ setFormNotice({ kind: "status", text: "\u6B63\u5728\u4FDD\u5B58\u8BBE\u7F6E\u2026" });
21279
21318
  try {
21280
- const accepted = await form.set(field, value);
21281
- if (mounted.current) setFormNotice(accepted ? { kind: "status", text: "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002" } : { kind: "error", text: "\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u8BF7\u91CD\u8BD5\u3002" });
21282
- if (accepted && (field === "useDesktopCredential" || field === "quotaRefreshSeconds")) await refresh(true);
21319
+ const operation = writeTail.current.then(() => mounted.current ? form.set(field, value) : false);
21320
+ writeTail.current = operation.then(() => {
21321
+ }, () => {
21322
+ });
21323
+ const accepted = await operation;
21324
+ if (!accepted) batchWriteFailed.current = true;
21325
+ if (accepted && mounted.current && (field === "useDesktopCredential" || field === "quotaRefreshSeconds")) void refresh(true);
21283
21326
  return accepted;
21284
21327
  } catch {
21285
- if (mounted.current) setFormNotice({ kind: "error", text: GENERIC_ERROR });
21328
+ batchWriteFailed.current = true;
21286
21329
  return false;
21287
21330
  } finally {
21288
- if (mounted.current) setPendingField(null);
21331
+ if (writeVersions.current.get(field) === version2) {
21332
+ writeVersions.current.delete(field);
21333
+ if (mounted.current) {
21334
+ setPendingValues((previous) => {
21335
+ const next = { ...previous };
21336
+ delete next[field];
21337
+ return next;
21338
+ });
21339
+ setPendingField([...writeVersions.current.keys()]);
21340
+ if (writeVersions.current.size === 0) setFormNotice(batchWriteFailed.current ? { kind: "error", text: "\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u5DF2\u6062\u590D\u539F\u503C\uFF0C\u8BF7\u91CD\u8BD5\u3002" } : { kind: "status", text: "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002" });
21341
+ }
21342
+ }
21289
21343
  }
21290
21344
  }, [form, mounted, refresh]);
21291
21345
  const refreshModelsBusy = React.useRef(false);
@@ -21366,6 +21420,7 @@ function SettingsPage({ caller, form }) {
21366
21420
  onRefresh: () => {
21367
21421
  void refresh(true);
21368
21422
  },
21423
+ onConnection: () => selectTab("connection"),
21369
21424
  nextAutoRefreshAt: schedule?.at,
21370
21425
  refreshIntervalSeconds
21371
21426
  });
@@ -21412,6 +21467,8 @@ function SettingsPage({ caller, form }) {
21412
21467
  tabRefs.current[TABS.findIndex((candidate) => candidate.id === next)]?.focus();
21413
21468
  }
21414
21469
  }, item.label))),
21470
+ acceptedFormSnapshot.status !== "ready" || acceptedFormSnapshot.value === void 0 ? h(NoticeView, { notice: { kind: "status", text: acceptedFormSnapshot.status === "unavailable" ? "\u914D\u7F6E\u6682\u4E0D\u53EF\u7528\uFF0C\u8BF7\u68C0\u67E5\u63D2\u4EF6\u662F\u5426\u5DF2\u542F\u7528\u3002" : "\u6B63\u5728\u8F7D\u5165\u914D\u7F6E\uFF0C\u5B8C\u6210\u540E\u5373\u53EF\u4FEE\u6539\u3002" } }) : !acceptedFormSnapshot.writable ? h(NoticeView, { notice: { kind: "status", text: "\u5F53\u524D\u8BBE\u7F6E\u4E3A\u53EA\u8BFB\uFF0C\u65E0\u6CD5\u4FDD\u5B58\u4FEE\u6539\u3002" } }) : null,
21471
+ h(NoticeView, { notice: formNotice }),
21415
21472
  h("div", {
21416
21473
  className: "odc-panel",
21417
21474
  role: "tabpanel",
@@ -21420,8 +21477,7 @@ function SettingsPage({ caller, form }) {
21420
21477
  "aria-labelledby": `${baseId}-tab-${tab}`
21421
21478
  }, content),
21422
21479
  loading ? h("p", { className: "odc-meta", role: "status" }, "\u6B63\u5728\u8FDE\u63A5\u670D\u52A1\u2026") : null,
21423
- error62 !== void 0 ? h(NoticeView, { notice: { kind: "error", text: error62 } }) : null,
21424
- h(NoticeView, { notice: formNotice })
21480
+ error62 !== void 0 ? h(NoticeView, { notice: { kind: "error", text: error62 } }) : null
21425
21481
  );
21426
21482
  }
21427
21483
  var name = "dsh-opendesign-corouter";