dsh-opendesign-corouter 0.1.2 → 0.1.4

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
@@ -32,6 +32,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
32
32
  var client_exports = {};
33
33
  __export(client_exports, {
34
34
  Advanced: () => Advanced,
35
+ LoginApproval: () => LoginApproval,
35
36
  ModelRow: () => ModelRow,
36
37
  Models: () => Models,
37
38
  Overview: () => Overview,
@@ -19925,6 +19926,27 @@ function record2(value) {
19925
19926
  return value !== null && typeof value === "object" && !Array.isArray(value);
19926
19927
  }
19927
19928
 
19929
+ // src/device-auth.ts
19930
+ function validateActivationUrl(value, userCode) {
19931
+ if (typeof value !== "string" || value.length > 512 || !/^https:\/\/open-design\.ai\/cloud\/cli\/activate(?:\?[^#]*)?$/u.test(value) || /[\s\\]/u.test(value)) return null;
19932
+ try {
19933
+ const url2 = new URL(value);
19934
+ if (url2.origin !== "https://open-design.ai" || url2.pathname !== "/cloud/cli/activate" || url2.username || url2.password || url2.hash) return null;
19935
+ const entries = [...url2.searchParams];
19936
+ if (entries.length > 1) return null;
19937
+ if (entries.length) {
19938
+ const entry = entries[0];
19939
+ if (!["code", "user_code"].includes(entry[0]) || !validUserCode(entry[1]) || userCode !== void 0 && entry[1] !== userCode) return null;
19940
+ }
19941
+ return url2.href;
19942
+ } catch {
19943
+ return null;
19944
+ }
19945
+ }
19946
+ function validUserCode(value) {
19947
+ return typeof value === "string" && /^[a-z0-9][a-z0-9-]{3,31}$/iu.test(value);
19948
+ }
19949
+
19928
19950
  // src/protocol-options.ts
19929
19951
  var API_PROTOCOL_IDS = ["chat-completions", "responses", "messages"];
19930
19952
  function openAiBaseURL(baseURL) {
@@ -19942,56 +19964,45 @@ var API_PROTOCOL_OPTIONS = [
19942
19964
  ];
19943
19965
 
19944
19966
  // 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
19967
  function parseModelSettingsMap(value) {
19987
- if (!record2(value)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
19968
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
19988
19969
  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`);
19970
+ if (keys.length > 512) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u6700\u591A\u5141\u8BB8 512 \u4E2A\u6A21\u578B");
19971
+ const fields = /* @__PURE__ */ new Set(["enabled", "temperature", "topP", "maxTokens", "contextWindow", "reasoningEffort"]);
19972
+ const efforts = ["none", "minimal", "low", "medium", "high", "xhigh", "ultra", "max"];
19990
19973
  const out = {};
19991
19974
  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]);
19975
+ if (["__proto__", "constructor", "prototype"].includes(id)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u4E0D\u5141\u8BB8\u4FDD\u7559\u5B57\u6BB5\u540D");
19976
+ 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 . _ : / -");
19977
+ const entry = value[id];
19978
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry)) throw new Error("\u6BCF\u4E2A\u6A21\u578B\u7684\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
19979
+ const settings = entry;
19980
+ for (const field of Object.keys(settings)) {
19981
+ if (!fields.has(field)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u542B\u6709\u4E0D\u652F\u6301\u7684\u5B57\u6BB5");
19982
+ }
19983
+ const parsed = {};
19984
+ if (settings.enabled !== void 0) {
19985
+ if (typeof settings.enabled !== "boolean") throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 enabled \u5FC5\u987B\u662F\u5E03\u5C14\u503C");
19986
+ parsed.enabled = settings.enabled;
19987
+ }
19988
+ for (const [field, max] of [["temperature", 2], ["topP", 1]]) {
19989
+ const item = settings[field];
19990
+ if (item === void 0) continue;
19991
+ 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`);
19992
+ parsed[field] = item;
19993
+ }
19994
+ for (const [field, max] of [["maxTokens", 1e7], ["contextWindow", 1e8]]) {
19995
+ const item = settings[field];
19996
+ if (item === void 0) continue;
19997
+ 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`);
19998
+ parsed[field] = item;
19999
+ }
20000
+ if (settings.reasoningEffort !== void 0) {
20001
+ 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");
20002
+ parsed.reasoningEffort = settings.reasoningEffort;
20003
+ }
20004
+ 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");
20005
+ out[id] = parsed;
19995
20006
  }
19996
20007
  return out;
19997
20008
  }
@@ -20009,7 +20020,7 @@ var MAX_WINDOWS = 64;
20009
20020
  var MAX_API_KEY = 16384;
20010
20021
  var HTTP_ASCII = /^[\x21-\x7e]+$/u;
20011
20022
  var ENV_REF = /^[A-Za-z_][A-Za-z0-9_]*$/u;
20012
- var MODEL_ID2 = /^[A-Za-z0-9._:/-]{1,128}$/u;
20023
+ var MODEL_ID = /^[A-Za-z0-9._:/-]{1,128}$/u;
20013
20024
  var LOGIN_PHASES = ["idle", "launching", "waiting", "verifying", "success", "cancelled", "error"];
20014
20025
  var QUOTA_STATES = ["ok", "partial", "need-login", "error"];
20015
20026
  var SESSION_SOURCES = ["desktop", "login", "environment"];
@@ -20023,7 +20034,7 @@ function isoTime(value, label) {
20023
20034
  if (!Number.isFinite(Date.parse(time3))) throw new Error(`${label} \u5FC5\u987B\u662F ISO \u65F6\u95F4\u5B57\u7B26\u4E32`);
20024
20035
  return time3;
20025
20036
  }
20026
- function flag2(value, label) {
20037
+ function flag(value, label) {
20027
20038
  if (typeof value !== "boolean") throw new Error(`${label} \u5FC5\u987B\u662F\u5E03\u5C14\u503C`);
20028
20039
  return value;
20029
20040
  }
@@ -20079,11 +20090,11 @@ function parseQuotaSnapshot(value) {
20079
20090
  ...value.subscriptionPeriodStart === void 0 ? {} : { subscriptionPeriodStart: isoTime(value.subscriptionPeriodStart, "\u8BA2\u9605\u5468\u671F\u5F00\u59CB\u65F6\u95F4") },
20080
20091
  ...value.subscriptionPeriodEnd === void 0 ? {} : { subscriptionPeriodEnd: isoTime(value.subscriptionPeriodEnd, "\u8BA2\u9605\u5468\u671F\u7ED3\u675F\u65F6\u95F4") },
20081
20092
  ...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") },
20093
+ ...value.stale === void 0 ? {} : { stale: flag(value.stale, "\u5386\u53F2\u989D\u5EA6\u8BFB\u6570") },
20083
20094
  ...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") },
20095
+ ...value.autoRefreshPaused === void 0 ? {} : { autoRefreshPaused: flag(value.autoRefreshPaused, "\u81EA\u52A8\u5237\u65B0\u6682\u505C\u72B6\u6001") },
20085
20096
  ...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") },
20097
+ ...value.eligible === void 0 ? {} : { eligible: flag(value.eligible, "\u5957\u9910\u8D44\u683C") },
20087
20098
  windows: windows.map(parseQuotaWindow),
20088
20099
  balances: {
20089
20100
  ...balances.subscriptionUsd === void 0 ? {} : { subscriptionUsd: amount(balances.subscriptionUsd, "\u8BA2\u9605\u4F59\u989D") },
@@ -20097,9 +20108,19 @@ function parseLoginState(value) {
20097
20108
  if (!record2(value)) throw new Error("\u767B\u5F55\u72B6\u6001\u5FC5\u987B\u662F\u5BF9\u8C61");
20098
20109
  const jobId = value.jobId;
20099
20110
  if (jobId !== null && jobId !== void 0 && typeof jobId !== "string") throw new Error("\u767B\u5F55\u4EFB\u52A1 id \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216 null");
20111
+ const state = member(value.state, LOGIN_PHASES, "\u767B\u5F55\u9636\u6BB5");
20112
+ let approval = {};
20113
+ if (state === "waiting" && (value.activationUrl !== void 0 || value.userCode !== void 0 || value.expiresAt !== void 0)) {
20114
+ const userCode = text(value.userCode, "\u8BBE\u5907\u6388\u6743\u7801", 64);
20115
+ if (!/^[A-Za-z0-9-]+$/u.test(userCode)) throw new Error("\u8BBE\u5907\u6388\u6743\u7801\u683C\u5F0F\u65E0\u6548");
20116
+ const activationUrl = validateActivationUrl(value.activationUrl, userCode);
20117
+ if (activationUrl === null) throw new Error("\u8BBE\u5907\u6388\u6743\u94FE\u63A5\u65E0\u6548");
20118
+ approval = { activationUrl, userCode, expiresAt: isoTime(value.expiresAt, "\u8BBE\u5907\u6388\u6743\u5230\u671F\u65F6\u95F4") };
20119
+ }
20100
20120
  return {
20101
20121
  jobId: typeof jobId === "string" && jobId.length > 0 ? text(jobId, "\u767B\u5F55\u4EFB\u52A1 id", MAX_JOB_ID) : null,
20102
- state: member(value.state, LOGIN_PHASES, "\u767B\u5F55\u9636\u6BB5"),
20122
+ state,
20123
+ ...approval,
20103
20124
  ...value.message === void 0 ? {} : { message: text(value.message, "\u767B\u5F55\u8BF4\u660E", MAX_MESSAGE) },
20104
20125
  ...value.startedAt === void 0 ? {} : { startedAt: isoTime(value.startedAt, "\u767B\u5F55\u5F00\u59CB\u65F6\u95F4") },
20105
20126
  ...value.finishedAt === void 0 ? {} : { finishedAt: isoTime(value.finishedAt, "\u767B\u5F55\u7ED3\u675F\u65F6\u95F4") }
@@ -20108,12 +20129,12 @@ function parseLoginState(value) {
20108
20129
  function parseStatusModel(value) {
20109
20130
  if (!record2(value)) throw new Error("\u6A21\u578B\u6761\u76EE\u5FC5\u987B\u662F\u5BF9\u8C61");
20110
20131
  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");
20132
+ if (!MODEL_ID.test(id)) throw new Error("\u6A21\u578B id \u542B\u4E0D\u5141\u8BB8\u7684\u5B57\u7B26");
20112
20133
  return {
20113
20134
  id,
20114
20135
  name: text(value.name, "\u6A21\u578B\u540D", 128),
20115
20136
  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") },
20137
+ ...value.enabled === void 0 ? {} : { enabled: flag(value.enabled, "\u6A21\u578B\u542F\u7528\u72B6\u6001") },
20117
20138
  ...value.contextWindow === void 0 ? {} : { contextWindow: positiveInteger(value.contextWindow, "\u4E0A\u4E0B\u6587\u9884\u7B97", 1e8) },
20118
20139
  ...value.maxOutputTokens === void 0 ? {} : { maxOutputTokens: positiveInteger(value.maxOutputTokens, "\u6700\u5927\u8F93\u51FA", 1e7) },
20119
20140
  ...value.reasoningEfforts === void 0 ? {} : { reasoningEfforts: parseEfforts(value.reasoningEfforts) }
@@ -20124,8 +20145,8 @@ function parseStatusConfig(value) {
20124
20145
  const apiKeyEnv = text(value.apiKeyEnv, "\u51ED\u636E\u5F15\u7528\u540D", MAX_ENV_REF);
20125
20146
  if (!ENV_REF.test(apiKeyEnv)) throw new Error("\u51ED\u636E\u5F15\u7528\u540D\u5FC5\u987B\u662F\u5408\u6CD5\u6807\u8BC6\u7B26");
20126
20147
  return {
20127
- emptyTurnGuard: flag2(value.emptyTurnGuard, "\u7A7A\u8F6E\u4FDD\u62A4\u5F00\u5173"),
20128
- useDesktopCredential: flag2(value.useDesktopCredential, "\u684C\u9762\u767B\u5F55\u6001\u5F00\u5173"),
20148
+ emptyTurnGuard: flag(value.emptyTurnGuard, "\u7A7A\u8F6E\u4FDD\u62A4\u5F00\u5173"),
20149
+ useDesktopCredential: flag(value.useDesktopCredential, "\u684C\u9762\u767B\u5F55\u6001\u5F00\u5173"),
20129
20150
  baseURL: text(value.baseURL, "\u63A8\u7406\u5730\u5740", MAX_BASE_URL),
20130
20151
  apiKeyEnv,
20131
20152
  ...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
@@ -20147,7 +20168,7 @@ function parseStatus(value) {
20147
20168
  }
20148
20169
  return {
20149
20170
  revision: text(value.revision, "\u914D\u7F6E\u7248\u672C", MAX_REVISION),
20150
- apiKeyConfigured: flag2(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
20171
+ apiKeyConfigured: flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
20151
20172
  ...value.sessionSource === void 0 ? {} : { sessionSource: member(value.sessionSource, SESSION_SOURCES, "\u767B\u5F55\u6001\u6765\u6E90") },
20152
20173
  quota: parseQuotaSnapshot(value.quota),
20153
20174
  login: parseLoginState(value.login),
@@ -20215,14 +20236,14 @@ var DEFAULT_STREAM_IDLE_TIMEOUT_MS = 3e5;
20215
20236
  var MIN_STREAM_IDLE_TIMEOUT_MS = 1e3;
20216
20237
  var MAX_STREAM_IDLE_TIMEOUT_MS = 18e5;
20217
20238
  var MAX_OUTPUT_TOKENS = 1e7;
20218
- var MAX_CONTEXT_WINDOW2 = 1e8;
20239
+ var MAX_CONTEXT_WINDOW = 1e8;
20219
20240
  var GENERIC_ERROR = "\u64CD\u4F5C\u672A\u5B8C\u6210\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
20220
20241
  var LOGIN_LABELS = {
20221
20242
  idle: "\u5C1A\u672A\u5F00\u59CB\u72EC\u7ACB\u767B\u5F55",
20222
- launching: "\u6B63\u5728\u6253\u5F00\u5B98\u65B9\u767B\u5F55\u9875\u9762\u2026",
20223
- waiting: "\u7B49\u5F85\u4F60\u5728\u5B98\u65B9\u9875\u9762\u5B8C\u6210\u767B\u5F55\u2026",
20224
- verifying: "\u6B63\u5728\u9A8C\u8BC1\u5E76\u4FDD\u5B58\u4F1A\u8BDD\u2026",
20225
- success: "\u767B\u5F55\u6210\u529F\uFF0C\u4F1A\u8BDD\u5DF2\u4FDD\u5B58\u3002",
20243
+ launching: "\u6B63\u5728\u7533\u8BF7\u8BBE\u5907\u6388\u6743\u7801\u2026",
20244
+ waiting: "\u8BF7\u6253\u5F00\u6388\u6743\u9875\uFF0C\u5728\u5E38\u7528\u6D4F\u89C8\u5668\u4E2D\u786E\u8BA4\u672C\u6B21\u767B\u5F55\u3002",
20245
+ verifying: "\u6B63\u5728\u4FDD\u5B58\u8BBE\u5907\u6388\u6743\u2026",
20246
+ success: "\u767B\u5F55\u6210\u529F\uFF0C\u8BBE\u5907\u6388\u6743\u5DF2\u4FDD\u5B58\u3002",
20226
20247
  cancelled: "\u5DF2\u53D6\u6D88\u672C\u6B21\u767B\u5F55\u3002",
20227
20248
  error: "\u767B\u5F55\u672A\u5B8C\u6210\uFF0C\u8BF7\u91CD\u8BD5\u3002"
20228
20249
  };
@@ -20248,8 +20269,9 @@ function installStyles() {
20248
20269
  .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
20270
  .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
20271
  .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}
20272
+ .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
20273
  .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}
20274
+ .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
20275
  .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
20276
  .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
20277
  `;
@@ -20391,12 +20413,12 @@ function QuotaView({ quota, nextAutoRefreshAt, refreshIntervalSeconds }) {
20391
20413
  {
20392
20414
  label: "\u8BA2\u9605\u8D26\u671F\u7ED3\u675F",
20393
20415
  value: formatTime(quota.subscriptionPeriodEnd),
20394
- hint: `\u8D26\u671F\u5F00\u59CB\uFF1A${formatTime(quota.subscriptionPeriodStart)} \xB7 \u672A\u77E5\u65F6\u95F4\u4E0D\u63A8\u65AD`
20416
+ hint: `\u8D26\u671F\u5F00\u59CB\uFF1A${formatTime(quota.subscriptionPeriodStart)}`
20395
20417
  },
20396
20418
  {
20397
20419
  label: "\u4E0B\u6B21\u989D\u5EA6\u6062\u590D",
20398
20420
  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"
20421
+ hint: "\u6700\u65E9\u6062\u590D\u7684\u8D60\u9001\u7A97\u53E3\uFF1B\u4E0D\u4EE3\u8868\u94B1\u5305\u5230\u8D26\u65F6\u95F4"
20400
20422
  },
20401
20423
  {
20402
20424
  label: "\u4E0B\u6B21\u81EA\u52A8\u5237\u65B0",
@@ -20455,15 +20477,20 @@ function QuotaView({ quota, nextAutoRefreshAt, refreshIntervalSeconds }) {
20455
20477
  h("strong", { className: "odc-metric-value" }, metric.value),
20456
20478
  h("span", { className: "odc-hint" }, metric.hint)
20457
20479
  ))),
20458
- h("div", { className: "odc-quota-grid" }, timing.map((metric) => h(
20480
+ h("div", { className: "odc-quota-grid odc-timing", "aria-label": "\u989D\u5EA6\u65F6\u95F4\u5B89\u6392" }, timing.map((metric) => h(
20459
20481
  "div",
20460
- { className: "odc-card odc-metric", key: metric.label },
20482
+ { className: "odc-metric", key: metric.label },
20461
20483
  h("span", { className: "odc-label" }, metric.label),
20462
20484
  h("strong", { className: "odc-metric-value odc-metric-text" }, metric.value),
20463
20485
  h("span", { className: "odc-hint" }, metric.hint)
20464
20486
  ))),
20465
20487
  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"),
20488
+ h(
20489
+ "details",
20490
+ { className: "odc-model-details" },
20491
+ h("summary", null, "\u5982\u4F55\u7406\u89E3\u8FD9\u4E9B\u989D\u5EA6\uFF1F"),
20492
+ 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")
20493
+ ),
20467
20494
  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
20495
  );
20469
20496
  }
@@ -20525,10 +20552,21 @@ function quotaAutoRefresh(secondsRaw, nextRefreshAt, now, backingOff = false) {
20525
20552
  const delayMs = Number.isFinite(planDelay) && planDelay > 0 ? backingOff ? plannedDelay : Math.min(intervalMs, plannedDelay) : intervalMs;
20526
20553
  return { delayMs, at: new Date(now + delayMs).toISOString(), intervalSeconds };
20527
20554
  }
20528
- function Overview({ status, busy, onRefresh, nextAutoRefreshAt, refreshIntervalSeconds }) {
20555
+ function Overview({ status, busy, onRefresh, nextAutoRefreshAt, refreshIntervalSeconds, onConnection }) {
20529
20556
  return h(
20530
20557
  React.Fragment,
20531
20558
  null,
20559
+ status !== void 0 && (status.apiKeyConfigured === false || status.quota.state === "need-login") ? h(
20560
+ "section",
20561
+ { className: "odc-card odc-row", "aria-label": "\u8FDE\u63A5\u5F85\u5B8C\u6210" },
20562
+ h(
20563
+ "div",
20564
+ null,
20565
+ h("h3", null, "\u5148\u5B8C\u6210\u8FDE\u63A5"),
20566
+ h("p", { className: "odc-hint" }, status.apiKeyConfigured === false ? "\u5C1A\u65E0\u5F53\u524D\u7F51\u5173\u7684\u63A8\u7406\u51ED\u636E\uFF1B\u53EF\u5B8C\u6210\u8BBE\u5907\u6388\u6743\u6216\u5355\u72EC\u914D\u7F6E API Key\u3002" : "API Key \u5DF2\u914D\u7F6E\uFF1B\u767B\u5F55\u540E\u5373\u53EF\u67E5\u770B\u8D26\u53F7\u989D\u5EA6\u3002")
20567
+ ),
20568
+ onConnection === void 0 ? null : h("button", { type: "button", className: "odc-button odc-button-primary", onClick: onConnection }, "\u524D\u5F80\u8FDE\u63A5\u4E0E\u767B\u5F55")
20569
+ ) : null,
20532
20570
  h(
20533
20571
  "div",
20534
20572
  { className: "odc-card-head" },
@@ -20542,7 +20580,7 @@ var NUMERIC_FIELDS = {
20542
20580
  temperature: { label: "\u6E29\u5EA6", hint: "0\u20132\uFF1B\u7559\u7A7A\u7EE7\u627F\u9ED8\u8BA4\u3002", min: 0, max: 2 },
20543
20581
  topP: { label: "Top P", hint: "0\u20131\uFF1B\u7559\u7A7A\u7EE7\u627F\u9ED8\u8BA4\u3002", min: 0, max: 1 },
20544
20582
  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 }
20583
+ 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
20584
  };
20547
20585
  var NUMERIC_ORDER = ["temperature", "topP", "maxTokens", "contextWindow"];
20548
20586
  function OptionalNumberField({ id, field, value, disabled, resetToken, onSave }) {
@@ -20627,12 +20665,12 @@ function EffortField({ id, model, value, disabled, onChange }) {
20627
20665
  const next = event.target.value;
20628
20666
  void (async () => {
20629
20667
  const saved = await onChange(next);
20630
- if (mounted.current && !saved) setError("\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u8BF7\u91CD\u8BD5\u3002");
20668
+ if (mounted.current) setError(saved ? void 0 : "\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u8BF7\u91CD\u8BD5\u3002");
20631
20669
  })();
20632
20670
  }
20633
20671
  }, [
20634
20672
  h("option", { key: "", value: "" }, "\u7EE7\u627F\u9ED8\u8BA4"),
20635
- ...options.map((effort2) => h("option", { key: effort2, value: effort2 }, effort2))
20673
+ ...options.map((effort) => h("option", { key: effort, value: effort }, effort))
20636
20674
  ]),
20637
20675
  h("small", {
20638
20676
  className: error62 === void 0 ? "odc-hint" : "odc-hint odc-field-error",
@@ -20650,13 +20688,19 @@ function ModelRow({ model, settings, authoritative, writable, pending, onCommit
20650
20688
  const hasOverrides = Object.keys(settings).length > 0;
20651
20689
  const commit = async (next) => {
20652
20690
  const saved = await onCommit(next);
20653
- if (mounted.current && !saved) setError("\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u8BF7\u91CD\u8BD5\u3002");
20691
+ if (mounted.current) setError(saved ? void 0 : "\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u8BF7\u91CD\u8BD5\u3002");
20654
20692
  return saved;
20655
20693
  };
20656
20694
  const saveField = async (key, value) => {
20657
20695
  const next = { ...settings };
20658
20696
  if (value === void 0) delete next[key];
20659
20697
  else next[key] = value;
20698
+ const output2 = next.maxTokens ?? model.maxOutputTokens;
20699
+ const context = next.contextWindow ?? model.contextWindow;
20700
+ if (output2 !== void 0 && context !== void 0 && output2 >= context) {
20701
+ 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");
20702
+ return false;
20703
+ }
20660
20704
  setError(void 0);
20661
20705
  return commit(next);
20662
20706
  };
@@ -20698,11 +20742,12 @@ function ModelRow({ model, settings, authoritative, writable, pending, onCommit
20698
20742
  } }, "\u91CD\u7F6E")
20699
20743
  )
20700
20744
  ),
20701
- h("p", { className: "odc-model-meta" }, facts),
20702
20745
  h(
20703
20746
  "details",
20704
20747
  { className: "odc-model-details" },
20705
- h("summary", { "aria-label": `${model.name} \u53C2\u6570\u8BBE\u7F6E` }, "\u53C2\u6570\u8BBE\u7F6E"),
20748
+ 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"),
20749
+ h("p", { className: "odc-model-meta" }, facts),
20750
+ h("p", { className: "odc-hint" }, "\u6570\u503C\u79BB\u5F00\u8F93\u5165\u6846\u540E\u4FDD\u5B58\uFF0C\u7559\u7A7A\u7EE7\u627F\u9ED8\u8BA4\u3002"),
20706
20751
  h(
20707
20752
  "div",
20708
20753
  { className: "odc-model-editor" },
@@ -20735,10 +20780,12 @@ function ModelRow({ model, settings, authoritative, writable, pending, onCommit
20735
20780
  }
20736
20781
  function ModelGroup({ title, group, models, settingsMap, authoritative, writable, pending, onCommit }) {
20737
20782
  const [query, setQuery] = React.useState("");
20783
+ const [expanded, setExpanded] = React.useState(false);
20738
20784
  const id = React.useId();
20739
20785
  const normalized = query.trim().toLocaleLowerCase();
20740
20786
  const groupModels = models.filter((model) => model.group === group);
20741
20787
  const filtered = groupModels.filter((model) => normalized === "" || `${model.name} ${model.id}`.toLocaleLowerCase().includes(normalized));
20788
+ const visible = normalized !== "" || expanded ? filtered : filtered.slice(0, 6);
20742
20789
  const enabledCount = groupModels.filter((model) => modelEnabled(model, settingsMap[model.id], authoritative)).length;
20743
20790
  return h(
20744
20791
  "section",
@@ -20755,10 +20802,10 @@ function ModelGroup({ title, group, models, settingsMap, authoritative, writable
20755
20802
  className: "odc-input",
20756
20803
  type: "search",
20757
20804
  value: query,
20758
- placeholder: "\u8F93\u5165\u6A21\u578B\u540D\u79F0\u6216 ID",
20805
+ placeholder: "\u641C\u7D22\u5168\u90E8\u6A21\u578B\u7684\u540D\u79F0\u6216 ID",
20759
20806
  onChange: (event) => setQuery(event.target.value)
20760
20807
  }),
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, {
20808
+ 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
20809
  key: model.id,
20763
20810
  model,
20764
20811
  settings: modelSettingsEntry(settingsMap, model.id),
@@ -20766,15 +20813,23 @@ function ModelGroup({ title, group, models, settingsMap, authoritative, writable
20766
20813
  writable,
20767
20814
  pending,
20768
20815
  onCommit: (next) => onCommit(model.id, next)
20769
- })))
20816
+ }))),
20817
+ normalized === "" && filtered.length > 6 ? h("button", {
20818
+ type: "button",
20819
+ className: "odc-button",
20820
+ style: { marginTop: 12 },
20821
+ "aria-expanded": expanded,
20822
+ "aria-controls": `${id}-list`,
20823
+ onClick: () => setExpanded((value) => !value)
20824
+ }, expanded ? "\u6536\u8D77\u6A21\u578B\u5217\u8868" : `\u663E\u793A\u5168\u90E8 ${filtered.length} \u4E2A\u6A21\u578B`) : null
20770
20825
  );
20771
20826
  }
20772
20827
  function Models({ status, formSnapshot, setFormField, pendingField, onRefreshModels, refreshingModels, notice }) {
20773
20828
  const formReady = formSnapshot.status === "ready" && formSnapshot.value !== void 0;
20774
20829
  const settingsMap = formReady ? formSnapshot.value?.modelSettings ?? {} : status?.config.modelSettings ?? {};
20775
20830
  const authoritative = formReady || status?.config.modelSettings !== void 0;
20776
- const writable = formSnapshot.writable;
20777
- const pending = pendingField === "modelSettings";
20831
+ const writable = formSnapshot.status === "ready" && formSnapshot.value !== void 0 && formSnapshot.writable;
20832
+ const pending = pendingField.includes("modelSettings");
20778
20833
  const latestSettings = React.useRef(settingsMap);
20779
20834
  React.useEffect(() => {
20780
20835
  latestSettings.current = settingsMap;
@@ -20886,7 +20941,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
20886
20941
  React.useEffect(() => {
20887
20942
  setApiKeyEnv(formSnapshot.value?.apiKeyEnv ?? status?.config.apiKeyEnv ?? "");
20888
20943
  }, [formSnapshot.value?.apiKeyEnv, status?.config.apiKeyEnv]);
20889
- const writable = formSnapshot.writable;
20944
+ const writable = formSnapshot.status === "ready" && formSnapshot.value !== void 0 && formSnapshot.writable;
20890
20945
  const configuredProtocol = formSnapshot.value?.apiProtocol ?? status?.config.apiProtocol;
20891
20946
  const protocol = configuredProtocol !== void 0 && API_PROTOCOL_OPTIONS.some((option) => option.id === configuredProtocol) ? configuredProtocol : "chat-completions";
20892
20947
  const baseURL = formSnapshot.value?.baseURL ?? status?.config.baseURL ?? "";
@@ -20896,8 +20951,8 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
20896
20951
  const selected = API_PROTOCOL_OPTIONS.find((option) => option.id === protocol);
20897
20952
  const saveKeyRef = async () => {
20898
20953
  const value = apiKeyEnv.trim();
20899
- if (value === "") {
20900
- setKeyNotice({ kind: "error", text: "\u914D\u7F6E\u503C\u4E0D\u80FD\u4E3A\u7A7A\u3002" });
20954
+ if (!/^[A-Za-z_][A-Za-z0-9_]{0,127}$/u.test(value)) {
20955
+ 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
20956
  return;
20902
20957
  }
20903
20958
  setKeyNotice(null);
@@ -20918,7 +20973,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
20918
20973
  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
20974
  h("div", { style: { marginTop: 14 } }, h(Switch, {
20920
20975
  checked: formSnapshot.value?.emptyTurnGuard ?? status?.config.emptyTurnGuard ?? true,
20921
- disabled: !writable || pendingField === "emptyTurnGuard",
20976
+ disabled: !writable || pendingField.includes("emptyTurnGuard"),
20922
20977
  label: "\u542F\u7528\u7A7A\u8F6E\u76D1\u63A7",
20923
20978
  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
20979
  onChange: (checked) => {
@@ -20939,7 +20994,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
20939
20994
  id: "odc-api-protocol",
20940
20995
  className: "odc-input",
20941
20996
  value: protocol,
20942
- disabled: !writable || pendingField === "apiProtocol",
20997
+ disabled: !writable || pendingField.includes("apiProtocol"),
20943
20998
  onChange: (event) => {
20944
20999
  void setFormField("apiProtocol", event.target.value);
20945
21000
  }
@@ -20988,7 +21043,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
20988
21043
  h(
20989
21044
  "div",
20990
21045
  { className: "odc-actions", style: { marginTop: 10 } },
20991
- h("button", { className: "odc-button", type: "button", disabled: !writable || pendingField === "apiKeyEnv", onClick: () => {
21046
+ h("button", { className: "odc-button", type: "button", disabled: !writable || pendingField.includes("apiKeyEnv"), onClick: () => {
20992
21047
  void saveKeyRef();
20993
21048
  } }, "\u4FDD\u5B58\u5F15\u7528\u540D")
20994
21049
  ),
@@ -21007,7 +21062,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
21007
21062
  min: MIN_REQUEST_TIMEOUT_MS,
21008
21063
  max: MAX_REQUEST_TIMEOUT_MS,
21009
21064
  integer: true,
21010
- disabled: !writable || pendingField === "requestTimeoutMs",
21065
+ disabled: !writable || pendingField.includes("requestTimeoutMs"),
21011
21066
  onCommit: (value) => setFormField("requestTimeoutMs", value)
21012
21067
  }),
21013
21068
  h(NumberField, {
@@ -21018,7 +21073,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
21018
21073
  min: MIN_STREAM_IDLE_TIMEOUT_MS,
21019
21074
  max: MAX_STREAM_IDLE_TIMEOUT_MS,
21020
21075
  integer: true,
21021
- disabled: !writable || pendingField === "streamIdleTimeoutMs",
21076
+ disabled: !writable || pendingField.includes("streamIdleTimeoutMs"),
21022
21077
  onCommit: (value) => setFormField("streamIdleTimeoutMs", value)
21023
21078
  }),
21024
21079
  h(NumberField, {
@@ -21029,7 +21084,7 @@ function Advanced({ status, formSnapshot, setFormField, pendingField }) {
21029
21084
  min: MIN_QUOTA_REFRESH_SECONDS,
21030
21085
  max: MAX_QUOTA_REFRESH_SECONDS,
21031
21086
  integer: true,
21032
- disabled: !writable || pendingField === "quotaRefreshSeconds",
21087
+ disabled: !writable || pendingField.includes("quotaRefreshSeconds"),
21033
21088
  onCommit: (value) => setFormField("quotaRefreshSeconds", value)
21034
21089
  })
21035
21090
  )
@@ -21046,6 +21101,24 @@ function Switch({ checked, disabled, label, hint, onChange }) {
21046
21101
  function loginInFlight(state) {
21047
21102
  return state === "launching" || state === "waiting" || state === "verifying";
21048
21103
  }
21104
+ function LoginApproval({ login }) {
21105
+ if (login?.state !== "waiting" || login.userCode === void 0 || login.expiresAt === void 0) return null;
21106
+ const url2 = validateActivationUrl(login.activationUrl, login.userCode);
21107
+ if (url2 === null) return null;
21108
+ return h(
21109
+ "div",
21110
+ { className: "odc-readonly", "aria-label": "\u8BBE\u5907\u6388\u6743" },
21111
+ h("span", { className: "odc-label" }, "\u6838\u5BF9\u6388\u6743\u7801"),
21112
+ h("code", { className: "odc-metric-value", "aria-label": "\u8BBE\u5907\u6388\u6743\u7801" }, login.userCode),
21113
+ h(
21114
+ "div",
21115
+ { className: "odc-actions" },
21116
+ h("a", { className: "odc-button odc-button-primary", href: url2, target: "_blank", rel: "noreferrer noopener" }, "\u6253\u5F00\u6388\u6743\u9875")
21117
+ ),
21118
+ h("p", { className: "odc-hint" }, `\u6388\u6743\u7801\u6709\u6548\u81F3 ${formatTime(login.expiresAt)}\u3002\u5728\u5E38\u7528\u6D4F\u89C8\u5668\u786E\u8BA4\u540E\uFF0C\u8FD4\u56DE\u6B64\u9875\u67E5\u770B\u7ED3\u679C\u3002`),
21119
+ h("p", { className: "odc-hint" }, "\u53EF\u53F3\u952E\u590D\u5236\u6388\u6743\u94FE\u63A5\u5230\u5E38\u7528\u6D4F\u89C8\u5668\uFF1B\u5BC6\u7801\u7BA1\u7406\u5668\u548C\u81EA\u52A8\u586B\u5145\u7531\u6D4F\u89C8\u5668\u6B63\u5E38\u63D0\u4F9B\u3002\u4EC5\u786E\u8BA4\u4F60\u672C\u4EBA\u53D1\u8D77\u7684\u6388\u6743\u3002")
21120
+ );
21121
+ }
21049
21122
  function Connection({ status, formSnapshot, setFormField, pendingField, caller, loadStatus, refreshAfterLogin }) {
21050
21123
  const mounted = useMounted();
21051
21124
  const actionVersion = React.useRef(0);
@@ -21060,14 +21133,14 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21060
21133
  const state = login?.state ?? "idle";
21061
21134
  const inFlight = loginInFlight(state);
21062
21135
  const startLogin = async () => {
21063
- if (status === void 0 || busy) return;
21136
+ if (status === void 0 || busy || keyBusy) return;
21064
21137
  const version2 = ++actionVersion.current;
21065
21138
  setBusy(true);
21066
- setNotice({ kind: "status", text: "\u6B63\u5728\u542F\u52A8\u5B98\u65B9\u767B\u5F55\u2026" });
21139
+ setNotice({ kind: "status", text: "\u6B63\u5728\u7533\u8BF7\u8BBE\u5907\u6388\u6743\u2026" });
21067
21140
  try {
21068
21141
  const next = await caller("startLogin", { expectedRevision: status.revision });
21069
21142
  if (!mounted.current || version2 !== actionVersion.current) return;
21070
- setNotice({ kind: "status", text: "\u8BF7\u5728\u6253\u5F00\u7684\u5B98\u65B9\u9875\u9762\u4E2D\u4EB2\u81EA\u5B8C\u6210\u767B\u5F55\u3002" });
21143
+ setNotice(null);
21071
21144
  await (next.state === "success" ? refreshAfterLogin() : loadStatus());
21072
21145
  } catch {
21073
21146
  if (mounted.current && version2 === actionVersion.current) setNotice({ kind: "error", text: "\u65E0\u6CD5\u542F\u52A8\u767B\u5F55\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002" });
@@ -21076,7 +21149,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21076
21149
  }
21077
21150
  };
21078
21151
  const cancelLogin = async () => {
21079
- if (login?.jobId == null || busy) return;
21152
+ if (login?.jobId == null || busy || keyBusy) return;
21080
21153
  const version2 = ++actionVersion.current;
21081
21154
  setBusy(true);
21082
21155
  try {
@@ -21092,7 +21165,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21092
21165
  };
21093
21166
  const saveKey = async (event) => {
21094
21167
  event.preventDefault();
21095
- if (status === void 0 || keyBusy || apiKey.trim() === "") {
21168
+ if (status === void 0 || busy || inFlight || keyBusy || apiKey.trim() === "") {
21096
21169
  if (apiKey.trim() === "") setNotice({ kind: "error", text: "\u8BF7\u8F93\u5165 API Key \u540E\u518D\u4FDD\u5B58\u3002" });
21097
21170
  return;
21098
21171
  }
@@ -21127,7 +21200,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21127
21200
  { style: { marginTop: 14 } },
21128
21201
  h(Switch, {
21129
21202
  checked: desktopChecked,
21130
- disabled: !formSnapshot.writable || pendingField === "useDesktopCredential",
21203
+ disabled: formSnapshot.status !== "ready" || formSnapshot.value === void 0 || !formSnapshot.writable || pendingField.includes("useDesktopCredential"),
21131
21204
  label: "\u4F18\u5148\u4F7F\u7528\u684C\u9762\u767B\u5F55\u6001",
21132
21205
  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
21206
  onChange: (checked) => {
@@ -21140,27 +21213,28 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21140
21213
  h(
21141
21214
  "section",
21142
21215
  { className: "odc-card" },
21143
- h("h3", null, "\u72EC\u7ACB\u767B\u5F55"),
21144
- h("p", { className: "odc-hint" }, "\u767B\u5F55\u9700\u7531\u4F60\u5728\u5B98\u65B9\u9875\u9762\u4EB2\u81EA\u5B8C\u6210\uFF1B\u63D2\u4EF6\u4E0D\u4F1A\u4EE3\u586B\u8D26\u53F7\u6216\u5BC6\u7801\u3002\u9A8C\u8BC1\u901A\u8FC7\u540E\u624D\u4FDD\u5B58\u4F1A\u8BDD\u3002"),
21216
+ h("h3", null, "\u8BBE\u5907\u6388\u6743\u767B\u5F55"),
21217
+ h("p", { className: "odc-hint" }, "\u7533\u8BF7\u6388\u6743\u7801\u540E\uFF0C\u5728\u5E38\u7528\u6D4F\u89C8\u5668\u6253\u5F00\u5B98\u65B9\u6388\u6743\u9875\u3002\u6CBF\u7528\u5DF2\u6709\u767B\u5F55\u72B6\u6001\u3001\u5BC6\u7801\u7BA1\u7406\u5668\u548C\u81EA\u52A8\u586B\u5145\uFF1B\u786E\u8BA4\u540E\u81EA\u52A8\u4FDD\u5B58\u8BBE\u5907\u4EE4\u724C\uFF0C\u7528\u4E8E\u67E5\u8BE2\u989D\u5EA6\u53CA\u5B98\u65B9\u7F51\u5173\u63A8\u7406\u3002"),
21145
21218
  h(
21146
21219
  "div",
21147
21220
  { className: "odc-actions", style: { marginTop: 14 } },
21148
- h("button", { className: "odc-button odc-button-primary", type: "button", disabled: status === void 0 || busy || inFlight, onClick: () => {
21221
+ h("button", { className: "odc-button odc-button-primary", type: "button", disabled: status === void 0 || busy || keyBusy || inFlight, onClick: () => {
21149
21222
  void startLogin();
21150
- } }, "\u767B\u5F55\u5E76\u4FDD\u5B58\u4F1A\u8BDD"),
21151
- inFlight ? h("button", { className: "odc-button", type: "button", disabled: busy || login?.jobId == null, onClick: () => {
21223
+ } }, "\u5F00\u59CB\u8BBE\u5907\u6388\u6743"),
21224
+ inFlight ? h("button", { className: "odc-button", type: "button", disabled: busy || keyBusy || login?.jobId == null, onClick: () => {
21152
21225
  void cancelLogin();
21153
21226
  } }, "\u53D6\u6D88\u767B\u5F55") : null,
21154
21227
  h("a", { className: "odc-link", href: OFFICIAL_SITE, target: "_blank", rel: "noreferrer noopener" }, "\u6253\u5F00 CoRouter \u5B98\u7F51")
21155
21228
  ),
21156
- h("p", { className: "odc-meta", role: state === "error" ? "alert" : "status" }, LOGIN_LABELS[state]),
21229
+ h(LoginApproval, { login }),
21230
+ h("p", { className: "odc-meta", role: state === "error" ? "alert" : "status" }, login?.message ?? LOGIN_LABELS[state]),
21157
21231
  h(NoticeView, { notice })
21158
21232
  ),
21159
21233
  h(
21160
21234
  "section",
21161
21235
  { className: "odc-card" },
21162
- h("h3", null, "API Key"),
21163
- h("p", { className: "odc-hint" }, status?.apiKeyConfigured === true ? "\u5DF2\u914D\u7F6E API Key\u3002\u4FDD\u5B58\u4EC5\u66FF\u6362\u672C\u63D2\u4EF6\u4FDD\u5B58\u7684 Key\uFF1B\u73AF\u5883\u53D8\u91CF\u6216\u5DF2\u6709\u51ED\u636E\u5F15\u7528\u4ECD\u4F18\u5148\u3002" : "\u5C1A\u672A\u914D\u7F6E API Key\uFF1B\u63A8\u7406\u9700\u8981 CoRouter Key\uFF0C\u989D\u5EA6\u767B\u5F55\u4E0D\u80FD\u4EE3\u66FF\u3002"),
21236
+ h("h3", null, "API Key\uFF08\u53EF\u9009\u8986\u76D6\uFF09"),
21237
+ 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"),
21164
21238
  h(
21165
21239
  "form",
21166
21240
  { onSubmit: (event) => {
@@ -21178,7 +21252,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21178
21252
  autoComplete: "new-password",
21179
21253
  autoCapitalize: "off",
21180
21254
  spellCheck: false,
21181
- disabled: status === void 0 || keyBusy,
21255
+ disabled: status === void 0 || busy || inFlight || keyBusy,
21182
21256
  placeholder: "\u4EC5\u7528\u4E8E\u672C\u6B21\u4FDD\u5B58\uFF0C\u4E0D\u4F1A\u56DE\u586B",
21183
21257
  onChange: (event) => setApiKey(event.target.value)
21184
21258
  }),
@@ -21187,7 +21261,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21187
21261
  h(
21188
21262
  "div",
21189
21263
  { 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")
21264
+ 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
21265
  )
21192
21266
  )
21193
21267
  )
@@ -21210,7 +21284,8 @@ function SettingsPage({ caller, form }) {
21210
21284
  const [refreshing, setRefreshing] = React.useState(false);
21211
21285
  const [refreshingModels, setRefreshingModels] = React.useState(false);
21212
21286
  const [modelsNotice, setModelsNotice] = React.useState(null);
21213
- const [pendingField, setPendingField] = React.useState(null);
21287
+ const [pendingField, setPendingField] = React.useState([]);
21288
+ const writeTail = React.useRef(Promise.resolve());
21214
21289
  const [formNotice, setFormNotice] = React.useState(null);
21215
21290
  const [scheduleTick, setScheduleTick] = React.useState(0);
21216
21291
  const statusVersion = React.useRef(0);
@@ -21219,7 +21294,15 @@ function SettingsPage({ caller, form }) {
21219
21294
  const modelsVersion = React.useRef(0);
21220
21295
  const tabRefs = React.useRef([]);
21221
21296
  const baseId = React.useId();
21222
- const formSnapshot = useFormSnapshot(form);
21297
+ const acceptedFormSnapshot = useFormSnapshot(form);
21298
+ const [pendingValues, setPendingValues] = React.useState({});
21299
+ const writeVersions = React.useRef(/* @__PURE__ */ new Map());
21300
+ const nextWriteVersion = React.useRef(0);
21301
+ const batchWriteFailed = React.useRef(false);
21302
+ const formSnapshot = React.useMemo(() => ({
21303
+ ...acceptedFormSnapshot,
21304
+ value: acceptedFormSnapshot.value === void 0 ? void 0 : { ...acceptedFormSnapshot.value, ...pendingValues }
21305
+ }), [acceptedFormSnapshot, pendingValues]);
21223
21306
  const loadStatus = React.useCallback(async () => {
21224
21307
  const version2 = ++statusVersion.current;
21225
21308
  try {
@@ -21263,6 +21346,7 @@ function SettingsPage({ caller, form }) {
21263
21346
  }
21264
21347
  }, [caller, loadStatus, mounted]);
21265
21348
  React.useEffect(() => {
21349
+ void loadStatus();
21266
21350
  void refresh();
21267
21351
  return () => {
21268
21352
  statusVersion.current += 1;
@@ -21272,20 +21356,41 @@ function SettingsPage({ caller, form }) {
21272
21356
  refreshBusy.current = false;
21273
21357
  forcedRefreshPending.current = false;
21274
21358
  };
21275
- }, [refresh]);
21359
+ }, [loadStatus, refresh]);
21276
21360
  const setFormField = React.useCallback(async (field, value) => {
21277
- setPendingField(field);
21278
- setFormNotice(null);
21361
+ const snapshot = form.getSnapshot();
21362
+ if (snapshot.status !== "ready" || snapshot.value === void 0 || !snapshot.writable || writeVersions.current.has(field)) return false;
21363
+ if (writeVersions.current.size === 0) batchWriteFailed.current = false;
21364
+ const version2 = ++nextWriteVersion.current;
21365
+ writeVersions.current.set(field, version2);
21366
+ setPendingField([...writeVersions.current.keys()]);
21367
+ setPendingValues((previous) => ({ ...previous, [field]: value }));
21368
+ setFormNotice({ kind: "status", text: "\u6B63\u5728\u4FDD\u5B58\u8BBE\u7F6E\u2026" });
21279
21369
  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);
21370
+ const operation = writeTail.current.then(() => mounted.current ? form.set(field, value) : false);
21371
+ writeTail.current = operation.then(() => {
21372
+ }, () => {
21373
+ });
21374
+ const accepted = await operation;
21375
+ if (!accepted) batchWriteFailed.current = true;
21376
+ if (accepted && mounted.current && (field === "useDesktopCredential" || field === "quotaRefreshSeconds")) void refresh(true);
21283
21377
  return accepted;
21284
21378
  } catch {
21285
- if (mounted.current) setFormNotice({ kind: "error", text: GENERIC_ERROR });
21379
+ batchWriteFailed.current = true;
21286
21380
  return false;
21287
21381
  } finally {
21288
- if (mounted.current) setPendingField(null);
21382
+ if (writeVersions.current.get(field) === version2) {
21383
+ writeVersions.current.delete(field);
21384
+ if (mounted.current) {
21385
+ setPendingValues((previous) => {
21386
+ const next = { ...previous };
21387
+ delete next[field];
21388
+ return next;
21389
+ });
21390
+ setPendingField([...writeVersions.current.keys()]);
21391
+ 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" });
21392
+ }
21393
+ }
21289
21394
  }
21290
21395
  }, [form, mounted, refresh]);
21291
21396
  const refreshModelsBusy = React.useRef(false);
@@ -21366,6 +21471,7 @@ function SettingsPage({ caller, form }) {
21366
21471
  onRefresh: () => {
21367
21472
  void refresh(true);
21368
21473
  },
21474
+ onConnection: () => selectTab("connection"),
21369
21475
  nextAutoRefreshAt: schedule?.at,
21370
21476
  refreshIntervalSeconds
21371
21477
  });
@@ -21412,6 +21518,8 @@ function SettingsPage({ caller, form }) {
21412
21518
  tabRefs.current[TABS.findIndex((candidate) => candidate.id === next)]?.focus();
21413
21519
  }
21414
21520
  }, item.label))),
21521
+ 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,
21522
+ h(NoticeView, { notice: formNotice }),
21415
21523
  h("div", {
21416
21524
  className: "odc-panel",
21417
21525
  role: "tabpanel",
@@ -21420,8 +21528,7 @@ function SettingsPage({ caller, form }) {
21420
21528
  "aria-labelledby": `${baseId}-tab-${tab}`
21421
21529
  }, content),
21422
21530
  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 })
21531
+ error62 !== void 0 ? h(NoticeView, { notice: { kind: "error", text: error62 } }) : null
21425
21532
  );
21426
21533
  }
21427
21534
  var name = "dsh-opendesign-corouter";