dsh-opendesign-corouter 0.1.5 → 0.1.7

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.
@@ -8,22 +8,29 @@ function record(value) {
8
8
  }
9
9
 
10
10
  // src/device-auth.ts
11
- function validateActivationUrl(value, userCode) {
11
+ function validateActivationUrl(value, userCode, deviceId) {
12
12
  if (typeof value !== "string" || value.length > 512 || !/^https:\/\/open-design\.ai\/cloud\/cli\/activate(?:\?[^#]*)?$/u.test(value) || /[\s\\]/u.test(value)) return null;
13
13
  try {
14
14
  const url = new URL(value);
15
15
  if (url.origin !== "https://open-design.ai" || url.pathname !== "/cloud/cli/activate" || url.username || url.password || url.hash) return null;
16
16
  const entries = [...url.searchParams];
17
- if (entries.length > 1) return null;
18
- if (entries.length) {
17
+ if (entries.length === 2) {
18
+ if (entries.some(([key]) => key !== "deviceId" && key !== "userCode")) return null;
19
+ const id = url.searchParams.get("deviceId");
20
+ const code = url.searchParams.get("userCode");
21
+ if (!validDeviceId(id) || !validUserCode(code) || deviceId !== void 0 && id !== deviceId || userCode !== void 0 && code !== userCode) return null;
22
+ } else if (entries.length === 1) {
19
23
  const entry = entries[0];
20
24
  if (!["code", "user_code"].includes(entry[0]) || !validUserCode(entry[1]) || userCode !== void 0 && entry[1] !== userCode) return null;
21
- }
25
+ } else if (entries.length > 2) return null;
22
26
  return url.href;
23
27
  } catch {
24
28
  return null;
25
29
  }
26
30
  }
31
+ function validDeviceId(value) {
32
+ return typeof value === "string" && /^[a-z0-9_-]{1,200}$/iu.test(value);
33
+ }
27
34
  function validUserCode(value) {
28
35
  return typeof value === "string" && /^[a-z0-9][a-z0-9-]{3,31}$/iu.test(value);
29
36
  }
@@ -115,9 +122,9 @@ function amount(value, label, negative = false) {
115
122
  if (typeof value !== "number" || !Number.isFinite(value) || !negative && value < 0) throw new Error(`${label} \u5FC5\u987B\u662F${negative ? "" : "\u975E\u8D1F"}\u6709\u9650\u6570\u5B57`);
116
123
  return value;
117
124
  }
118
- function positiveInteger(value, label, max) {
125
+ function positiveInteger(value, label, max, min = 1) {
119
126
  const result = count(value, label);
120
- if (result === 0 || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
127
+ if (result < min || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
121
128
  return result;
122
129
  }
123
130
  function parseEfforts(value) {
@@ -220,9 +227,9 @@ function parseStatusConfig(value) {
220
227
  apiKeyEnv,
221
228
  ...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
222
229
  ...value.modelSettings === void 0 ? {} : { modelSettings: parseModelSettingsMap(value.modelSettings) },
223
- ...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5) },
224
- ...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5) },
225
- ...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600) }
230
+ ...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5, 1e3) },
231
+ ...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5, 1e3) },
232
+ ...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600, 5) }
226
233
  };
227
234
  }
228
235
  function parseStatus(value) {
@@ -235,9 +242,13 @@ function parseStatus(value) {
235
242
  if (ids.has(model.id)) throw new Error(`\u6A21\u578B\u5217\u8868\u91CD\u590D\u4E86 id "${model.id}"`);
236
243
  ids.add(model.id);
237
244
  }
245
+ const apiKeyConfigured = flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA");
246
+ const apiKeySource = value.apiKeySource === void 0 ? void 0 : member(value.apiKeySource, ["reference", "stored", "device"], "\u63A8\u7406\u51ED\u636E\u6765\u6E90");
247
+ if (!apiKeyConfigured && apiKeySource !== void 0) throw new Error("\u672A\u914D\u7F6E\u51ED\u636E\u65F6\u4E0D\u80FD\u6307\u5B9A\u63A8\u7406\u51ED\u636E\u6765\u6E90");
238
248
  return {
239
249
  revision: text(value.revision, "\u914D\u7F6E\u7248\u672C", MAX_REVISION),
240
- apiKeyConfigured: flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
250
+ apiKeyConfigured,
251
+ ...apiKeySource === void 0 ? {} : { apiKeySource },
241
252
  ...value.sessionSource === void 0 ? {} : { sessionSource: member(value.sessionSource, SESSION_SOURCES, "\u767B\u5F55\u6001\u6765\u6E90") },
242
253
  quota: parseQuotaSnapshot(value.quota),
243
254
  login: parseLoginState(value.login),
package/lib/index.js CHANGED
@@ -159,7 +159,7 @@ var MODELS = [
159
159
  reasoningEfforts: EFFORTS_LOW_HIGH
160
160
  },
161
161
  { id: "glm-5.2", name: "GLM-5.2", group: "paid" },
162
- // ── Moonshot(2) ───────────────────────────────────────────
162
+ // ── Moonshot(3) ───────────────────────────────────────────
163
163
  {
164
164
  id: "kimi-k2.7-code",
165
165
  name: "Kimi K2.7 Code",
@@ -170,7 +170,9 @@ var MODELS = [
170
170
  reasoningEfforts: EFFORTS_STD
171
171
  },
172
172
  { id: "kimi-k3", name: "Kimi K3", group: "paid" },
173
- // ── Google(2) ─────────────────────────────────────────────
173
+ { id: "kimi-k3.1-pro", name: "Kimi K3.1 Pro", group: "paid" },
174
+ // ── Google(3) ─────────────────────────────────────────────
175
+ { id: "gemini-4-argon", name: "Gemini 4 Argon", group: "paid" },
174
176
  { id: "gemini-3.8-flash", name: "Gemini 3.8 Flash", group: "paid" },
175
177
  { id: "gemini-3.7-flash", name: "Gemini 3.7 Flash", group: "paid" },
176
178
  // ── xAI(3) ────────────────────────────────────────────────
@@ -207,7 +209,11 @@ var MODELS = [
207
209
  reasoningEfforts: EFFORTS_STD
208
210
  },
209
211
  // ── Alibaba(1) ────────────────────────────────────────────
210
- { id: "qwen3.7-max", name: "Qwen3.7 Max", group: "paid" }
212
+ { id: "qwen3.7-max", name: "Qwen3.7 Max", group: "paid" },
213
+ // Official API additions; display labels for undocumented entries are local formatting.
214
+ { id: "minimax-m3.1-flash", name: "MiniMax M3.1 Flash", group: "plan" },
215
+ { id: "muse-spark-1.3", name: "Muse Spark 1.3", group: "paid" },
216
+ { id: "muse-wonder", name: "Muse Wonder", group: "paid" }
211
217
  ];
212
218
  var BY_ID = new Map(MODELS.map((model) => [model.id, model]));
213
219
  function findModel(id) {
@@ -296,7 +302,7 @@ var DEFAULT_BASE_URL = "https://amr-link.open-design.ai/v1";
296
302
  var Config = Schema.object({
297
303
  apiKeyEnv: Schema.string().max(128).pattern(/^[A-Za-z_][A-Za-z0-9_]*$/u).default("COROUTER_API_KEY").description("CoRouter API Key \u7684\u73AF\u5883\u53D8\u91CF\u6216 DSH \u51ED\u636E\u5F15\u7528\u540D").volatile(),
298
304
  baseURL: Schema.transform(Schema.string(), assertBaseURL).default(DEFAULT_BASE_URL).description("CoRouter \u7F51\u5173\u5730\u5740\uFF1B\u4E0D\u7528\u4E8E\u63A7\u5236\u53F0\u767B\u5F55\u6216\u989D\u5EA6\u67E5\u8BE2").volatile(),
299
- apiProtocol: Schema.union(API_PROTOCOL_IDS).default("chat-completions").description("\u63A8\u7406 API \u534F\u8BAE\uFF1B\u6A21\u578B\u53D1\u73B0\u59CB\u7EC8\u4F7F\u7528 OpenAI models \u63A5\u53E3").volatile(),
305
+ apiProtocol: Schema.union(API_PROTOCOL_IDS).default("chat-completions").description("\u7F51\u5173\u652F\u6301\u7684\u63A8\u7406\u534F\u8BAE\uFF1B\u6A21\u578B\u76EE\u5F55\u901A\u8FC7\u8BE5\u7F51\u5173\u7684\u517C\u5BB9\u63A5\u53E3\u8BFB\u53D6").volatile(),
300
306
  modelSettings: Schema.transform(Schema.dict(Schema.any()), parseModelSettingsMap).default({}).description("\u9010\u6A21\u578B\u542F\u7528\u72B6\u6001\u548C\u8BF7\u6C42\u53C2\u6570").volatile(),
301
307
  useDesktopCredential: Schema.boolean().default(true).description("\u4F18\u5148\u8BFB\u53D6 OpenDesign \u684C\u9762\u7AEF\u767B\u5F55\u6001\u67E5\u8BE2\u989D\u5EA6").volatile(),
302
308
  emptyTurnGuard: Schema.boolean().default(true).description("\u76D1\u63A7\u5957\u9910\u8D60\u9001\u6A21\u578B\u7684\u7A7A\u8F6E/\u534F\u8BAE\u6B8B\u6E23\uFF1B\u7531\u5BBF\u4E3B\u91CD\u8BD5\u7B56\u7565\u5904\u7406\uFF0C\u53EF\u80FD\u989D\u5916\u6D88\u8017\u8D60\u9001\u989D\u5EA6").volatile(),
@@ -2194,7 +2200,7 @@ import { randomUUID } from "node:crypto";
2194
2200
 
2195
2201
  // src/device-auth.ts
2196
2202
  var DEVICE_AUTH_ENDPOINT = "https://amr-api.open-design.ai/api/v1/cli/device-authorizations";
2197
- var DEVICE_AUTH_PLUGIN_VERSION = "0.1.5";
2203
+ var DEVICE_AUTH_PLUGIN_VERSION = "0.1.7";
2198
2204
  var DEVICE_REQUEST_TIMEOUT_MS = 2e4;
2199
2205
  var DEVICE_RESPONSE_MAX_BYTES = 65536;
2200
2206
  var DEVICE_POLL_MIN_MS = 1e3;
@@ -2206,17 +2212,21 @@ var DeviceAuthError = class extends Error {
2206
2212
  }
2207
2213
  code;
2208
2214
  };
2209
- function validateActivationUrl(value, userCode) {
2215
+ function validateActivationUrl(value, userCode, deviceId) {
2210
2216
  if (typeof value !== "string" || value.length > 512 || !/^https:\/\/open-design\.ai\/cloud\/cli\/activate(?:\?[^#]*)?$/u.test(value) || /[\s\\]/u.test(value)) return null;
2211
2217
  try {
2212
2218
  const url = new URL(value);
2213
2219
  if (url.origin !== "https://open-design.ai" || url.pathname !== "/cloud/cli/activate" || url.username || url.password || url.hash) return null;
2214
2220
  const entries = [...url.searchParams];
2215
- if (entries.length > 1) return null;
2216
- if (entries.length) {
2221
+ if (entries.length === 2) {
2222
+ if (entries.some(([key]) => key !== "deviceId" && key !== "userCode")) return null;
2223
+ const id = url.searchParams.get("deviceId");
2224
+ const code = url.searchParams.get("userCode");
2225
+ if (!validDeviceId(id) || !validUserCode(code) || deviceId !== void 0 && id !== deviceId || userCode !== void 0 && code !== userCode) return null;
2226
+ } else if (entries.length === 1) {
2217
2227
  const entry = entries[0];
2218
2228
  if (!["code", "user_code"].includes(entry[0]) || !validUserCode(entry[1]) || userCode !== void 0 && entry[1] !== userCode) return null;
2219
- }
2229
+ } else if (entries.length > 2) return null;
2220
2230
  return url.href;
2221
2231
  } catch {
2222
2232
  return null;
@@ -2225,6 +2235,9 @@ function validateActivationUrl(value, userCode) {
2225
2235
  function object(value) {
2226
2236
  return value !== null && typeof value === "object" && !Array.isArray(value);
2227
2237
  }
2238
+ function validDeviceId(value) {
2239
+ return typeof value === "string" && /^[a-z0-9_-]{1,200}$/iu.test(value);
2240
+ }
2228
2241
  function validUserCode(value) {
2229
2242
  return typeof value === "string" && /^[a-z0-9][a-z0-9-]{3,31}$/iu.test(value);
2230
2243
  }
@@ -2232,8 +2245,8 @@ function secret(value) {
2232
2245
  return typeof value === "string" && value.length > 0 && value.length <= 8192 && /^[\x21-\x7e]+$/u.test(value);
2233
2246
  }
2234
2247
  function parseDeviceAuthorization(value) {
2235
- if (!object(value) || typeof value.deviceId !== "string" || !/^[a-z0-9_-]{1,200}$/iu.test(value.deviceId) || !secret(value.deviceSecret) || !validUserCode(value.userCode)) throw new DeviceAuthError("opendesign/login-response");
2236
- const activationUrl = validateActivationUrl(value.activationUrl, value.userCode);
2248
+ if (!object(value) || !validDeviceId(value.deviceId) || !secret(value.deviceSecret) || !validUserCode(value.userCode)) throw new DeviceAuthError("opendesign/login-response");
2249
+ const activationUrl = validateActivationUrl(value.activationUrl, value.userCode, value.deviceId);
2237
2250
  if (!activationUrl || value.userCode.toLowerCase().includes(value.deviceSecret.toLowerCase()) || decodeURIComponent(activationUrl).toLowerCase().includes(value.deviceSecret.toLowerCase())) throw new DeviceAuthError("opendesign/login-response");
2238
2251
  const expiresAt = typeof value.expiresAt === "string" && /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(?:\.\d{1,3})?(?:Z|[+-]\d\d:\d\d)$/u.test(value.expiresAt) ? Date.parse(value.expiresAt) : NaN;
2239
2252
  if (!Number.isFinite(expiresAt) || typeof value.pollIntervalSeconds !== "number" || !Number.isFinite(value.pollIntervalSeconds) || value.pollIntervalSeconds <= 0) throw new DeviceAuthError("opendesign/login-response");
@@ -2252,6 +2265,7 @@ function parseDevicePoll(value) {
2252
2265
  if (["expired", "cancelled", "canceled", "denied", "rejected", "failed", "error"].includes(state)) throw new DeviceAuthError(state === "expired" ? "opendesign/login-expired" : "opendesign/login-denied");
2253
2266
  if (value.error !== void 0 && value.error !== null && value.error !== "") throw new DeviceAuthError("opendesign/login-response");
2254
2267
  const user = object(value.user) ? value.user : {};
2268
+ if ((state === "pending" || state === "authorization_pending") && [value.controlKey, value.runtimeKey, user.controlKey, user.runtimeKey].every((key) => key === void 0 || key === null)) return { state: "pending" };
2255
2269
  const topPresent = value.controlKey !== void 0 || value.runtimeKey !== void 0;
2256
2270
  const source = topPresent ? value : user;
2257
2271
  if (source.controlKey !== void 0 || source.runtimeKey !== void 0) {
@@ -3157,9 +3171,9 @@ function amount(value, label, negative = false) {
3157
3171
  if (typeof value !== "number" || !Number.isFinite(value) || !negative && value < 0) throw new Error(`${label} \u5FC5\u987B\u662F${negative ? "" : "\u975E\u8D1F"}\u6709\u9650\u6570\u5B57`);
3158
3172
  return value;
3159
3173
  }
3160
- function positiveInteger(value, label, max) {
3174
+ function positiveInteger(value, label, max, min = 1) {
3161
3175
  const result = count(value, label);
3162
- if (result === 0 || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
3176
+ if (result < min || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
3163
3177
  return result;
3164
3178
  }
3165
3179
  function parseEfforts(value) {
@@ -3262,9 +3276,9 @@ function parseStatusConfig(value) {
3262
3276
  apiKeyEnv,
3263
3277
  ...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
3264
3278
  ...value.modelSettings === void 0 ? {} : { modelSettings: parseModelSettingsMap(value.modelSettings) },
3265
- ...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5) },
3266
- ...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5) },
3267
- ...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600) }
3279
+ ...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5, 1e3) },
3280
+ ...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5, 1e3) },
3281
+ ...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600, 5) }
3268
3282
  };
3269
3283
  }
3270
3284
  function parseStatus(value) {
@@ -3277,9 +3291,13 @@ function parseStatus(value) {
3277
3291
  if (ids.has(model.id)) throw new Error(`\u6A21\u578B\u5217\u8868\u91CD\u590D\u4E86 id "${model.id}"`);
3278
3292
  ids.add(model.id);
3279
3293
  }
3294
+ const apiKeyConfigured = flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA");
3295
+ const apiKeySource = value.apiKeySource === void 0 ? void 0 : member(value.apiKeySource, ["reference", "stored", "device"], "\u63A8\u7406\u51ED\u636E\u6765\u6E90");
3296
+ if (!apiKeyConfigured && apiKeySource !== void 0) throw new Error("\u672A\u914D\u7F6E\u51ED\u636E\u65F6\u4E0D\u80FD\u6307\u5B9A\u63A8\u7406\u51ED\u636E\u6765\u6E90");
3280
3297
  return {
3281
3298
  revision: text(value.revision, "\u914D\u7F6E\u7248\u672C", MAX_REVISION),
3282
- apiKeyConfigured: flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
3299
+ apiKeyConfigured,
3300
+ ...apiKeySource === void 0 ? {} : { apiKeySource },
3283
3301
  ...value.sessionSource === void 0 ? {} : { sessionSource: member(value.sessionSource, SESSION_SOURCES, "\u767B\u5F55\u6001\u6765\u6E90") },
3284
3302
  quota: parseQuotaSnapshot(value.quota),
3285
3303
  login: parseLoginState(value.login),
@@ -3318,7 +3336,8 @@ var inject = ["llm"];
3318
3336
  var API_KEY = credentialKey(name, "api-key");
3319
3337
  var SESSION = credentialKey(name, "console");
3320
3338
  var hash = (value) => createHash("sha256").update(JSON.stringify(value) ?? "").digest("hex");
3321
- var needLogin = () => ({ state: "need-login", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), windows: [], balances: {}, note: "\u5C1A\u672A\u8BFB\u53D6\u989D\u5EA6\uFF1B\u53EF\u4F7F\u7528\u684C\u9762\u767B\u5F55\u6001\u6216\u5728\u8FDE\u63A5\u9875\u767B\u5F55" });
3339
+ var needLogin = () => ({ state: "need-login", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), windows: [], balances: {}, note: "\u8BF7\u5728\u8FDE\u63A5\u4E0E\u767B\u5F55\u9875\u5B8C\u6210\u8D26\u53F7\u6388\u6743\u540E\u8BFB\u53D6\u989D\u5EA6\u3002" });
3340
+ var unreadQuota = () => ({ state: "partial", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), windows: [], balances: {}, note: "\u989D\u5EA6\u5C1A\u672A\u8BFB\u53D6\uFF0C\u8BF7\u5237\u65B0\u989D\u5EA6\u3002" });
3322
3341
  function grantOf(value) {
3323
3342
  if (value?.kind !== "grant" || !record(value.payload)) return;
3324
3343
  if (value.payload.kind === "device") return deviceGrant(value.payload);
@@ -3337,7 +3356,7 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3337
3356
  __publicField(this, "_lifetime", new AbortController());
3338
3357
  __publicField(this, "_revision", randomUUID2());
3339
3358
  __publicField(this, "_fingerprint", "");
3340
- __publicField(this, "_quota", needLogin());
3359
+ __publicField(this, "_quota", unreadQuota());
3341
3360
  __publicField(this, "_quotaAt", 0);
3342
3361
  __publicField(this, "_quotaConfig", "");
3343
3362
  __publicField(this, "_quotaIdentity");
@@ -3403,15 +3422,15 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3403
3422
  async _key(ref, baseURL, apiRecord, sessionRecord) {
3404
3423
  const credentials = this.ctx.get("credentials");
3405
3424
  const ambient = credentials ? (await credentials.resolve(credentialRef(ref)))?.value : launchEnvironmentOf(this.ctx).get(ref)?.value;
3406
- if (ambient?.trim()) return ambient;
3407
- if (apiRecord?.kind === "api-key" && apiRecord.key?.trim()) return apiRecord.key;
3425
+ if (ambient?.trim()) return { key: ambient, source: "reference" };
3426
+ if (apiRecord?.kind === "api-key" && apiRecord.key?.trim()) return { key: apiRecord.key, source: "stored" };
3408
3427
  const grant = grantOf(sessionRecord);
3409
- return isOfficialRuntimeUrl(baseURL) && grant && "kind" in grant && grant.kind === "device" ? grant.runtimeKey : void 0;
3428
+ return isOfficialRuntimeUrl(baseURL) && grant && "kind" in grant && grant.kind === "device" ? { key: grant.runtimeKey, source: "device" } : void 0;
3410
3429
  }
3411
3430
  async resolveApiKey(ref, baseURL = this._config().baseURL) {
3412
3431
  const credentials = this.ctx.get("credentials");
3413
3432
  const [apiRecord, sessionRecord] = await Promise.all([credentials?.readRecord(API_KEY), credentials?.readRecord(SESSION)]);
3414
- return this._key(ref, baseURL, apiRecord, sessionRecord);
3433
+ return (await this._key(ref, baseURL, apiRecord, sessionRecord))?.key;
3415
3434
  }
3416
3435
  _invalidateModels() {
3417
3436
  const changed = this._modelsUpdatedAt !== void 0;
@@ -3431,8 +3450,9 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3431
3450
  async _state() {
3432
3451
  const credentials = this.ctx.get("credentials"), config = this._config();
3433
3452
  const [apiRecord, sessionRecord] = await Promise.all([credentials?.readRecord(API_KEY), credentials?.readRecord(SESSION)]);
3434
- const key = await this._key(config.apiKeyEnv, config.baseURL, apiRecord, sessionRecord);
3435
- const state = { apiRecord, sessionRecord, key, config };
3453
+ const resolved = await this._key(config.apiKeyEnv, config.baseURL, apiRecord, sessionRecord);
3454
+ const key = resolved?.key;
3455
+ const state = { apiRecord, sessionRecord, key, keySource: resolved?.source, config };
3436
3456
  const modelsFingerprint = hash({ key, baseURL: config.baseURL });
3437
3457
  if (modelsFingerprint !== this._modelsFingerprint) {
3438
3458
  this._modelsFingerprint = modelsFingerprint;
@@ -3454,7 +3474,7 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3454
3474
  _invalidateQuota() {
3455
3475
  this._quotaAt = 0;
3456
3476
  this._quotaEpoch++;
3457
- this._quota = needLogin();
3477
+ this._quota = unreadQuota();
3458
3478
  this._quotaIdentity = void 0;
3459
3479
  this._quotaController?.abort();
3460
3480
  this._quotaPending = void 0;
@@ -3469,6 +3489,7 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3469
3489
  return parseStatus({
3470
3490
  revision: this._revision,
3471
3491
  apiKeyConfigured: Boolean(state.key?.trim()),
3492
+ ...state.keySource ? { apiKeySource: state.keySource } : {},
3472
3493
  ...this._quota.source ? { sessionSource: this._quota.source } : {},
3473
3494
  quota: this._quota,
3474
3495
  login: this._login.status(),
@@ -3493,7 +3514,7 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3493
3514
  if (this._modelsPending) return this._modelsPending;
3494
3515
  const key = state.key;
3495
3516
  if (!key?.trim()) {
3496
- this._modelsError = "\u8BF7\u5148\u914D\u7F6E API Key\uFF0C\u518D\u4ECE OpenAI \u7AEF\u53E3\u62C9\u53D6\u6A21\u578B\u3002";
3517
+ this._modelsError = "\u8BF7\u5148\u914D\u7F6E API Key\uFF0C\u518D\u4ECE\u5F53\u524D\u7F51\u5173\u8BFB\u53D6\u6A21\u578B\u76EE\u5F55\u3002";
3497
3518
  return this.status();
3498
3519
  }
3499
3520
  const epoch = this._modelsEpoch;
@@ -3505,10 +3526,18 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3505
3526
  const models = await (this.dependencies.fetchModels ?? fetchModelCatalog)(state.config.baseURL, key, signal);
3506
3527
  await this._state();
3507
3528
  if (signal.aborted || epoch !== this._modelsEpoch) return this.status();
3529
+ const previousModels = this._models;
3530
+ const previousUpdatedAt = this._modelsUpdatedAt;
3508
3531
  this._models = models;
3509
3532
  this._modelsUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
3510
3533
  this._modelsError = void 0;
3511
- this.dependencies.modelsChanged?.();
3534
+ try {
3535
+ this.dependencies.modelsChanged?.();
3536
+ } catch {
3537
+ this._models = previousModels;
3538
+ this._modelsUpdatedAt = previousUpdatedAt;
3539
+ this._modelsError = "\u6A21\u578B\u76EE\u5F55\u5DF2\u8BFB\u53D6\uFF0C\u4F46\u6A21\u578B\u9009\u62E9\u5668\u66F4\u65B0\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002";
3540
+ }
3512
3541
  } catch (error) {
3513
3542
  if (!signal.aborted && epoch === this._modelsEpoch) this._modelsError = error instanceof ModelDiscoveryError ? error.message : "\u6A21\u578B\u5217\u8868\u66F4\u65B0\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
3514
3543
  }