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/index.js CHANGED
@@ -228,96 +228,59 @@ function inferenceEndpoint(baseURL, protocol) {
228
228
  return baseURL.trim() === "" ? suffix : `${openAiBaseURL(baseURL.trim())}${suffix}`;
229
229
  }
230
230
 
231
- // src/util.ts
232
- function record(value) {
233
- return value !== null && typeof value === "object" && !Array.isArray(value);
234
- }
235
- function finite(value) {
236
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
237
- }
238
- function safeSecret(raw) {
239
- const value = raw.trim();
240
- if (!value || /[^\x20-\x7e]/u.test(value)) throw new Error("\u51ED\u636E\u4E3A\u7A7A\u6216\u542B\u6709\u4E0D\u53EF\u7528\u4E8E HTTP \u8BF7\u6C42\u5934\u7684\u5B57\u7B26");
241
- return value;
242
- }
243
- function combinedSignal(signal, timeoutMs) {
244
- const deadline = AbortSignal.timeout(timeoutMs);
245
- return signal ? AbortSignal.any([signal, deadline]) : deadline;
246
- }
247
- function sleep(ms, signal) {
248
- return new Promise((resolve) => {
249
- if (signal.aborted) return resolve();
250
- const done = () => {
251
- clearTimeout(timer);
252
- signal.removeEventListener("abort", done);
253
- resolve();
254
- };
255
- const timer = setTimeout(done, ms);
256
- signal.addEventListener("abort", done, { once: true });
257
- });
258
- }
259
-
260
231
  // src/model-settings.ts
261
- var MAX_ENTRIES = 512;
262
- var MAX_MODEL_ID_LENGTH = 128;
263
- var MODEL_ID = /^[A-Za-z0-9._:/-]{1,128}$/u;
264
- var MAX_TEMPERATURE = 2;
265
- var MAX_TOP_P = 1;
266
- var MAX_TOKENS = 1e7;
267
- var MAX_CONTEXT_WINDOW = 1e8;
268
- var REASONING_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "ultra", "max"];
269
232
  var RESERVED_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
270
- var SETTINGS_FIELDS = /* @__PURE__ */ new Set(["enabled", "temperature", "topP", "maxTokens", "contextWindow", "reasoningEffort"]);
271
- function flag(value) {
272
- if (typeof value !== "boolean") throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 enabled \u5FC5\u987B\u662F\u5E03\u5C14\u503C");
273
- return value;
274
- }
275
- function bounded(value, max, label) {
276
- 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`);
277
- return value;
278
- }
279
- function capacity(value, max, label) {
280
- 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`);
281
- return value;
282
- }
283
- function effort(value) {
284
- const hit = REASONING_EFFORTS.find((candidate) => candidate === value);
285
- if (hit === void 0) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 reasoningEffort \u4E0D\u5728\u5141\u8BB8\u7684\u53D6\u503C\u5185");
286
- return hit;
287
- }
288
- function settingsOf(value) {
289
- if (!record(value)) throw new Error("\u6BCF\u4E2A\u6A21\u578B\u7684\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
290
- for (const field of Object.keys(value)) {
291
- if (!SETTINGS_FIELDS.has(field)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u542B\u6709\u4E0D\u652F\u6301\u7684\u5B57\u6BB5");
292
- }
293
- const out = {};
294
- if (value.enabled !== void 0) out.enabled = flag(value.enabled);
295
- if (value.temperature !== void 0) out.temperature = bounded(value.temperature, MAX_TEMPERATURE, "temperature");
296
- if (value.topP !== void 0) out.topP = bounded(value.topP, MAX_TOP_P, "topP");
297
- if (value.maxTokens !== void 0) out.maxTokens = capacity(value.maxTokens, MAX_TOKENS, "maxTokens");
298
- if (value.contextWindow !== void 0) out.contextWindow = capacity(value.contextWindow, MAX_CONTEXT_WINDOW, "contextWindow");
299
- if (value.reasoningEffort !== void 0) out.reasoningEffort = effort(value.reasoningEffort);
300
- return out;
301
- }
302
233
  function parseModelSettingsMap(value) {
303
- if (!record(value)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
234
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
304
235
  const keys = Object.keys(value);
305
- if (keys.length > MAX_ENTRIES) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u6700\u591A\u5141\u8BB8 ${MAX_ENTRIES} \u4E2A\u6A21\u578B`);
236
+ if (keys.length > 512) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u6700\u591A\u5141\u8BB8 512 \u4E2A\u6A21\u578B");
237
+ const fields = /* @__PURE__ */ new Set(["enabled", "temperature", "topP", "maxTokens", "contextWindow", "reasoningEffort"]);
238
+ const efforts = ["none", "minimal", "low", "medium", "high", "xhigh", "ultra", "max"];
306
239
  const out = {};
307
240
  for (const id of keys) {
308
- if (RESERVED_KEYS.has(id)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u4E0D\u5141\u8BB8\u4FDD\u7559\u5B57\u6BB5\u540D");
309
- 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 . _ : / -`);
310
- out[id] = settingsOf(value[id]);
241
+ if (["__proto__", "constructor", "prototype"].includes(id)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u4E0D\u5141\u8BB8\u4FDD\u7559\u5B57\u6BB5\u540D");
242
+ 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 . _ : / -");
243
+ const entry = value[id];
244
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry)) throw new Error("\u6BCF\u4E2A\u6A21\u578B\u7684\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
245
+ const settings = entry;
246
+ for (const field of Object.keys(settings)) {
247
+ if (!fields.has(field)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u542B\u6709\u4E0D\u652F\u6301\u7684\u5B57\u6BB5");
248
+ }
249
+ const parsed = {};
250
+ if (settings.enabled !== void 0) {
251
+ if (typeof settings.enabled !== "boolean") throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 enabled \u5FC5\u987B\u662F\u5E03\u5C14\u503C");
252
+ parsed.enabled = settings.enabled;
253
+ }
254
+ for (const [field, max] of [["temperature", 2], ["topP", 1]]) {
255
+ const item = settings[field];
256
+ if (item === void 0) continue;
257
+ 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`);
258
+ parsed[field] = item;
259
+ }
260
+ for (const [field, max] of [["maxTokens", 1e7], ["contextWindow", 1e8]]) {
261
+ const item = settings[field];
262
+ if (item === void 0) continue;
263
+ 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`);
264
+ parsed[field] = item;
265
+ }
266
+ if (settings.reasoningEffort !== void 0) {
267
+ 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");
268
+ parsed.reasoningEffort = settings.reasoningEffort;
269
+ }
270
+ 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");
271
+ out[id] = parsed;
311
272
  }
312
273
  return out;
313
274
  }
314
275
  function applyModelSettings(row, settings) {
315
276
  const { contextWindow, maxTokens } = settings ?? {};
316
277
  if (contextWindow === void 0 && maxTokens === void 0) return { ...row };
278
+ if (contextWindow !== void 0) parseModelSettingsMap({ model: { contextWindow } });
279
+ if (maxTokens !== void 0) parseModelSettingsMap({ model: { maxTokens } });
317
280
  return {
318
281
  ...row,
319
- ...contextWindow === void 0 ? {} : { contextWindow: capacity(contextWindow, MAX_CONTEXT_WINDOW, "contextWindow") },
320
- ...maxTokens === void 0 ? {} : { maxOutputTokens: capacity(maxTokens, MAX_TOKENS, "maxTokens") }
282
+ ...contextWindow === void 0 ? {} : { contextWindow },
283
+ ...maxTokens === void 0 ? {} : { maxOutputTokens: maxTokens }
321
284
  };
322
285
  }
323
286
  function isModelEnabled(id, settings = {}) {
@@ -331,10 +294,10 @@ var PLAN_PROVIDER = "opendesign-corouter-plan";
331
294
  var PAID_PROVIDER = "opendesign-corouter-paid";
332
295
  var DEFAULT_BASE_URL = "https://amr-link.open-design.ai/v1";
333
296
  var Config = Schema.object({
334
- apiKeyEnv: Schema.string().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(),
335
- baseURL: Schema.transform(Schema.string(), (value) => assertBaseURL(value)).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(),
297
+ 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
+ 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(),
336
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(),
337
- modelSettings: Schema.transform(Schema.dict(Schema.any()), (value) => parseModelSettingsMap(value)).default({}).description("\u9010\u6A21\u578B\u542F\u7528\u72B6\u6001\u548C\u8BF7\u6C42\u53C2\u6570").volatile(),
300
+ modelSettings: Schema.transform(Schema.dict(Schema.any()), parseModelSettingsMap).default({}).description("\u9010\u6A21\u578B\u542F\u7528\u72B6\u6001\u548C\u8BF7\u6C42\u53C2\u6570").volatile(),
338
301
  useDesktopCredential: Schema.boolean().default(true).description("\u4F18\u5148\u8BFB\u53D6 OpenDesign \u684C\u9762\u7AEF\u767B\u5F55\u6001\u67E5\u8BE2\u989D\u5EA6").volatile(),
339
302
  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(),
340
303
  quotaRefreshSeconds: Schema.natural().min(5).max(3600).default(60).description("\u989D\u5EA6\u81EA\u52A8\u5237\u65B0\u95F4\u9694\uFF08\u79D2\uFF09").volatile(),
@@ -342,6 +305,7 @@ var Config = Schema.object({
342
305
  streamIdleTimeoutMs: Schema.natural().min(1e3).max(18e5).default(3e5).description("\u6D41\u5F0F\u54CD\u5E94\u65E0\u6570\u636E\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09").volatile()
343
306
  });
344
307
  function assertBaseURL(raw) {
308
+ if (raw.length > 2048) throw new Error("\u63A8\u7406 Base URL \u6700\u591A\u5141\u8BB8 2048 \u5B57\u7B26");
345
309
  let url;
346
310
  try {
347
311
  url = new URL(raw);
@@ -350,7 +314,9 @@ function assertBaseURL(raw) {
350
314
  }
351
315
  if (!["https:", "http:"].includes(url.protocol) || url.username || url.password || url.search || url.hash) throw new Error("\u63A8\u7406 Base URL \u4E0D\u53EF\u5305\u542B\u51ED\u636E\u3001\u67E5\u8BE2\u4E32\u6216\u7247\u6BB5");
352
316
  if (url.protocol === "http:" && !["localhost", "127.0.0.1", "[::1]"].includes(url.hostname)) throw new Error("\u975E\u672C\u673A\u63A8\u7406\u5730\u5740\u5FC5\u987B\u4F7F\u7528 HTTPS");
353
- return url.href.replace(/\/+$/u, "");
317
+ const normalized = url.href.replace(/\/+$/u, "");
318
+ if (normalized.length > 2048) throw new Error("\u63A8\u7406 Base URL \u6700\u591A\u5141\u8BB8 2048 \u5B57\u7B26");
319
+ return normalized;
354
320
  }
355
321
  function readConfig(config) {
356
322
  return {
@@ -462,6 +428,35 @@ function estimateTokens(value) {
462
428
  // src/stream.ts
463
429
  import { LlmError as LlmError4, ToolCallId } from "@deepseek-ai/dsh-llm";
464
430
 
431
+ // src/util.ts
432
+ function record(value) {
433
+ return value !== null && typeof value === "object" && !Array.isArray(value);
434
+ }
435
+ function finite(value) {
436
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
437
+ }
438
+ function safeSecret(raw) {
439
+ const value = raw.trim();
440
+ if (!value || /[^\x20-\x7e]/u.test(value)) throw new Error("\u51ED\u636E\u4E3A\u7A7A\u6216\u542B\u6709\u4E0D\u53EF\u7528\u4E8E HTTP \u8BF7\u6C42\u5934\u7684\u5B57\u7B26");
441
+ return value;
442
+ }
443
+ function combinedSignal(signal, timeoutMs) {
444
+ const deadline = AbortSignal.timeout(timeoutMs);
445
+ return signal ? AbortSignal.any([signal, deadline]) : deadline;
446
+ }
447
+ function sleep(ms, signal) {
448
+ return new Promise((resolve) => {
449
+ if (signal.aborted) return resolve();
450
+ const done = () => {
451
+ clearTimeout(timer);
452
+ signal.removeEventListener("abort", done);
453
+ resolve();
454
+ };
455
+ const timer = setTimeout(done, ms);
456
+ signal.addEventListener("abort", done, { once: true });
457
+ });
458
+ }
459
+
465
460
  // src/protocols/errors.ts
466
461
  import {
467
462
  ACCOUNT_QUOTA_EXCEEDED_CODE,
@@ -1130,12 +1125,12 @@ function buildMessagesRequest(ctx) {
1130
1125
  if (ctx.topP !== void 0) body.top_p = ctx.topP;
1131
1126
  if (options.stop?.length) body.stop_sequences = options.stop;
1132
1127
  if (options.reasoningEffort !== void 0) {
1133
- const effort2 = String(options.reasoningEffort);
1134
- if (effort2 === "none") body.thinking = { type: "disabled" };
1135
- else if (THINKING_EFFORTS.includes(effort2)) {
1128
+ const effort = String(options.reasoningEffort);
1129
+ if (effort === "none") body.thinking = { type: "disabled" };
1130
+ else if (THINKING_EFFORTS.includes(effort)) {
1136
1131
  body.thinking = { type: "adaptive" };
1137
- body.output_config = { effort: effort2 };
1138
- } else throw new LlmError7(`Anthropic Messages \u534F\u8BAE\u4E0D\u63A5\u53D7\u601D\u8003\u6DF1\u5EA6\u300C${effort2}\u300D`, "UNSUPPORTED_OPTION");
1132
+ body.output_config = { effort };
1133
+ } else throw new LlmError7(`Anthropic Messages \u534F\u8BAE\u4E0D\u63A5\u53D7\u601D\u8003\u6DF1\u5EA6\u300C${effort}\u300D`, "UNSUPPORTED_OPTION");
1139
1134
  }
1140
1135
  return { url: messagesURL(ctx.baseURL), headers: streamHeaders(ctx.apiKey, { "anthropic-version": ANTHROPIC_VERSION }), body };
1141
1136
  }
@@ -1330,7 +1325,7 @@ import {
1330
1325
  LlmError as LlmError8,
1331
1326
  ToolCallId as ToolCallId3
1332
1327
  } from "@deepseek-ai/dsh-llm";
1333
- var REASONING_EFFORTS2 = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
1328
+ var REASONING_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
1334
1329
  function userContent(text2, images) {
1335
1330
  if (!images.length) return text2;
1336
1331
  return [
@@ -1390,9 +1385,9 @@ function buildResponsesRequest(ctx) {
1390
1385
  body.max_output_tokens = options.maxTokens;
1391
1386
  }
1392
1387
  if (options.reasoningEffort !== void 0) {
1393
- const effort2 = String(options.reasoningEffort);
1394
- if (!REASONING_EFFORTS2.includes(effort2)) throw new LlmError8(`Responses \u534F\u8BAE\u4E0D\u63A5\u53D7\u601D\u8003\u6DF1\u5EA6\u300C${effort2}\u300D`, "UNSUPPORTED_OPTION");
1395
- body.reasoning = { effort: effort2, summary: "auto" };
1388
+ const effort = String(options.reasoningEffort);
1389
+ if (!REASONING_EFFORTS.includes(effort)) throw new LlmError8(`Responses \u534F\u8BAE\u4E0D\u63A5\u53D7\u601D\u8003\u6DF1\u5EA6\u300C${effort}\u300D`, "UNSUPPORTED_OPTION");
1390
+ body.reasoning = { effort, summary: "auto" };
1396
1391
  }
1397
1392
  if (options.stop?.length) throw new LlmError8("Responses \u534F\u8BAE\u4E0D\u652F\u6301 stop \u5E8F\u5217", "UNSUPPORTED_OPTION");
1398
1393
  return { url: inferenceEndpoint(ctx.baseURL, "responses"), headers: streamHeaders(ctx.apiKey), body };
@@ -1485,6 +1480,18 @@ async function* streamResponses(body, signal, idleMs) {
1485
1480
  }
1486
1481
  out.push({ type: "tool-call-delta", index: call.index, id: ToolCallId3(call.id), ...name2, argumentsDelta: delta });
1487
1482
  }
1483
+ function completeCall(call, item, out) {
1484
+ const args = item.arguments;
1485
+ let delta = "";
1486
+ if (args !== void 0) {
1487
+ if (typeof args !== "string" || !args.startsWith(call.args)) {
1488
+ throw new LlmError8("OpenDesign\uFF1A\u5DE5\u5177\u8C03\u7528\u5B8C\u6574\u53C2\u6570\u4E0E\u6D41\u5F0F\u589E\u91CF\u4E0D\u4E00\u81F4", "INVALID_RESPONSE");
1489
+ }
1490
+ delta = args.slice(call.args.length);
1491
+ call.args = args;
1492
+ }
1493
+ flushCall(call, delta, out);
1494
+ }
1488
1495
  function keyFor(value, kind, outputIndex) {
1489
1496
  const itemId = str(value.item_id) ?? (outputIndex === void 0 ? void 0 : keyByOutput.get(outputIndex));
1490
1497
  return `${kind}:${itemId ?? `idx:${outputIndex ?? -1}`}`;
@@ -1496,10 +1503,10 @@ async function* streamResponses(body, signal, idleMs) {
1496
1503
  if (item.type === "function_call") {
1497
1504
  const itemId = str(item.id) ?? str(item.call_id);
1498
1505
  const callId = str(item.call_id) ?? itemId;
1499
- if (!callId || [...calls.values()].some((call2) => call2.id === callId)) continue;
1500
- const call = callState(`call:${itemId ?? callId}`, item, out);
1501
- call.args = str(item.arguments) ?? call.args;
1502
- flushCall(call, call.args, out);
1506
+ if (!callId) continue;
1507
+ const existing = [...calls].find(([, call2]) => call2.id === callId);
1508
+ const call = callState(existing?.[0] ?? `call:${itemId ?? callId}`, item, out);
1509
+ completeCall(call, item, out);
1503
1510
  continue;
1504
1511
  }
1505
1512
  if (item.type === "message") {
@@ -1612,11 +1619,7 @@ async function* streamResponses(body, signal, idleMs) {
1612
1619
  const outputIndex = int(value.output_index);
1613
1620
  if (item.type === "function_call") {
1614
1621
  const call = callState(keyFor(value, "call", outputIndex), item, out);
1615
- const args = str(item.arguments);
1616
- if (args !== void 0 && call.args === "") {
1617
- call.args = args;
1618
- flushCall(call, args, out);
1619
- } else flushCall(call, "", out);
1622
+ completeCall(call, item, out);
1620
1623
  } else if (item.type === "message") {
1621
1624
  const key = `text:${str(item.id) ?? `idx:${outputIndex ?? -1}`}:0`;
1622
1625
  if (!texts.has(key)) {
@@ -1787,13 +1790,13 @@ var CoRouterAdapter = class extends LlmAdapter {
1787
1790
  if (room < 1) throw new LlmError10("\u5F53\u524D\u8F93\u5165\u6CA1\u6709\u4E3A\u8F93\u51FA\u7559\u4E0B\u4E0A\u4E0B\u6587\u7A7A\u95F4", "CONTEXT_WINDOW_EXCEEDED");
1788
1791
  maxTokens = Math.min(capped, Math.floor(room));
1789
1792
  }
1790
- const effort2 = options.reasoningEffort ?? (setting.reasoningEffort ? ReasoningEffortId(setting.reasoningEffort) : void 0);
1791
- if (effort2 !== void 0 && row.reasoningEfforts && !row.reasoningEfforts.includes(effort2)) throw new LlmError10("\u8BE5\u6A21\u578B\u4E0D\u652F\u6301\u6240\u9009\u601D\u8003\u6DF1\u5EA6", "UNSUPPORTED_OPTION");
1793
+ const effort = options.reasoningEffort ?? (setting.reasoningEffort ? ReasoningEffortId(setting.reasoningEffort) : void 0);
1794
+ if (effort !== void 0 && row.reasoningEfforts && !row.reasoningEfforts.includes(effort)) throw new LlmError10("\u8BE5\u6A21\u578B\u4E0D\u652F\u6301\u6240\u9009\u601D\u8003\u6DF1\u5EA6", "UNSUPPORTED_OPTION");
1792
1795
  const effective = {
1793
1796
  ...projectedOptions,
1794
1797
  ...(options.temperature ?? setting.temperature) === void 0 ? {} : { temperature: options.temperature ?? setting.temperature },
1795
1798
  ...maxTokens === void 0 ? {} : { maxTokens },
1796
- ...effort2 === void 0 ? {} : { reasoningEffort: effort2 }
1799
+ ...effort === void 0 ? {} : { reasoningEffort: effort }
1797
1800
  };
1798
1801
  const protocol = protocolFor(protocolId);
1799
1802
  const request = protocol.build({ baseURL: config.baseURL, apiKey: key, model: row, options: effective, images, ...setting.topP === void 0 ? {} : { topP: setting.topP } });
@@ -1859,7 +1862,7 @@ var DISCOVERY_TIMEOUT_MS = 2e4;
1859
1862
  var MAX_DISCOVERY_BODY_BYTES = 2 * 1024 * 1024;
1860
1863
  var MAX_MODELS = 512;
1861
1864
  var MAX_MODEL_NAME_LENGTH = 128;
1862
- var MODEL_ID2 = /^[A-Za-z0-9._:/-]{1,128}$/u;
1865
+ var MODEL_ID = /^[A-Za-z0-9._:/-]{1,128}$/u;
1863
1866
  var MEDIA_MODEL_ID = /^(?:gpt-image-|nano-banana-|seedream-|imagen-|veo-|doubao-seedance-|sora-)/u;
1864
1867
  var MESSAGES2 = {
1865
1868
  url: "\u6A21\u578B\u53D1\u73B0\u5730\u5740\u65E0\u6548\uFF1A\u5FC5\u987B\u662F\u7EDD\u5BF9 HTTP(S) \u5730\u5740\uFF0C\u4E14\u4E0D\u542B\u51ED\u636E\u3001\u67E5\u8BE2\u4E32\u6216\u7247\u6BB5",
@@ -1933,7 +1936,7 @@ function normalize(body) {
1933
1936
  const seen = /* @__PURE__ */ new Set();
1934
1937
  const rows = [];
1935
1938
  for (const value of body.data) {
1936
- if (!record(value) || typeof value.id !== "string" || !MODEL_ID2.test(value.id) || ["__proto__", "constructor", "prototype"].includes(value.id)) continue;
1939
+ if (!record(value) || typeof value.id !== "string" || !MODEL_ID.test(value.id) || ["__proto__", "constructor", "prototype"].includes(value.id)) continue;
1937
1940
  if (MEDIA_MODEL_ID.test(value.id) || seen.has(value.id)) continue;
1938
1941
  seen.add(value.id);
1939
1942
  const known = findModel(value.id);
@@ -2249,7 +2252,7 @@ var ConsoleLogin = class {
2249
2252
  job.status.jobId = job.id;
2250
2253
  job.status.startedAt = job.startedAt;
2251
2254
  this.job = job;
2252
- job.timer = setTimeout(() => this.finish(job, "cancelled", "\u767B\u5F55\u5DF2\u8D85\u8FC7\u4E94\u5206\u949F\uFF0C\u8BF7\u91CD\u65B0\u5F00\u59CB"), this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
2255
+ job.timer = setTimeout(() => this.requestCancellation(job, "\u767B\u5F55\u5DF2\u8D85\u8FC7\u4E94\u5206\u949F\uFF0C\u8BF7\u91CD\u65B0\u5F00\u59CB"), this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
2253
2256
  job.timer.unref?.();
2254
2257
  job.capturedAt = Promise.resolve().then(() => this.callbacks.capture(job.expectedRevision)).then((captured) => {
2255
2258
  job.captured = captured;
@@ -2269,25 +2272,31 @@ var ConsoleLogin = class {
2269
2272
  cancel(request) {
2270
2273
  const job = this.job;
2271
2274
  if (!job || job.status.jobId !== request.jobId) return this.status();
2272
- if (job.committing) {
2273
- job.cancelRequested = true;
2274
- job.controller.abort();
2275
- return this.status();
2276
- }
2277
- if (ACTIVE.has(job.status.state)) this.finish(job, "cancelled", "\u767B\u5F55\u5DF2\u53D6\u6D88\uFF0C\u672A\u4FDD\u5B58 Cookie");
2275
+ this.requestCancellation(job, "\u767B\u5F55\u5DF2\u53D6\u6D88\uFF0C\u672A\u4FDD\u5B58 Cookie");
2278
2276
  return this.status();
2279
2277
  }
2280
2278
  /** Plugin teardown: abort the attempt and close the browser. */
2281
2279
  dispose() {
2282
2280
  const job = this.job;
2283
- if (job && job.committing) {
2284
- job.cancelRequested = true;
2285
- job.controller.abort();
2286
- } else if (job && ACTIVE.has(job.status.state)) {
2287
- this.finish(job, "cancelled", "\u670D\u52A1\u5DF2\u5378\u8F7D\uFF0C\u767B\u5F55\u5DF2\u53D6\u6D88");
2288
- }
2281
+ if (job) this.requestCancellation(job, "\u670D\u52A1\u5DF2\u5378\u8F7D\uFF0C\u767B\u5F55\u5DF2\u53D6\u6D88");
2289
2282
  this.disposed = true;
2290
2283
  }
2284
+ /** Every cancellation source must let an in-flight atomic store decide the final outcome. */
2285
+ requestCancellation(job, message) {
2286
+ if (this.job !== job || !ACTIVE.has(job.status.state)) return;
2287
+ if (!job.committing) {
2288
+ this.finish(job, "cancelled", message);
2289
+ return;
2290
+ }
2291
+ if (!job.cancelRequested) {
2292
+ job.cancellationMessage = message;
2293
+ job.status.message = "\u6B63\u5728\u786E\u8BA4\u4F1A\u8BDD\u4FDD\u5B58\u7ED3\u679C";
2294
+ }
2295
+ job.cancelRequested = true;
2296
+ this.stopTimer(job);
2297
+ job.controller.abort();
2298
+ void this.close(job);
2299
+ }
2291
2300
  alive(job) {
2292
2301
  if (this.disposed || this.job !== job) return false;
2293
2302
  if (job.controller.signal.aborted && !job.committing) return false;
@@ -2325,7 +2334,7 @@ var ConsoleLogin = class {
2325
2334
  const browser = await launch(job.controller.signal);
2326
2335
  if (!browser) return null;
2327
2336
  job.browser = browser;
2328
- browser.on?.("disconnected", () => this.finish(job, "cancelled", "\u767B\u5F55\u7A97\u53E3\u5DF2\u5173\u95ED\uFF0C\u672A\u4FDD\u5B58 Cookie"));
2337
+ browser.on?.("disconnected", () => this.requestCancellation(job, "\u767B\u5F55\u7A97\u53E3\u5DF2\u5173\u95ED\uFF0C\u672A\u4FDD\u5B58 Cookie"));
2329
2338
  return browser;
2330
2339
  }
2331
2340
  async run(job) {
@@ -2342,7 +2351,7 @@ var ConsoleLogin = class {
2342
2351
  return;
2343
2352
  }
2344
2353
  const page = await context.newPage();
2345
- page.on?.("close", () => this.finish(job, "cancelled", "\u767B\u5F55\u7A97\u53E3\u5DF2\u5173\u95ED\uFF0C\u672A\u4FDD\u5B58 Cookie"));
2354
+ page.on?.("close", () => this.requestCancellation(job, "\u767B\u5F55\u7A97\u53E3\u5DF2\u5173\u95ED\uFF0C\u672A\u4FDD\u5B58 Cookie"));
2346
2355
  if (!this.alive(job)) {
2347
2356
  await this.close(job);
2348
2357
  return;
@@ -2416,7 +2425,7 @@ var ConsoleLogin = class {
2416
2425
  } catch (error) {
2417
2426
  job.committing = false;
2418
2427
  if (job.cancelRequested || job.controller.signal.aborted) {
2419
- this.finish(job, "cancelled", "\u767B\u5F55\u5DF2\u53D6\u6D88\uFF0C\u672A\u4FDD\u5B58 Cookie");
2428
+ this.finish(job, "cancelled", job.cancellationMessage ?? "\u767B\u5F55\u5DF2\u53D6\u6D88\uFF0C\u672A\u4FDD\u5B58 Cookie");
2420
2429
  return "cancelled";
2421
2430
  }
2422
2431
  if (FATAL_COMMIT_CODES.has(errorCode(error) ?? "")) {
@@ -2611,6 +2620,7 @@ async function readDesktopQuota(session, signal, runner = runVela, fetcher = fet
2611
2620
  consoleJson(`${session.apiUrl}/api/v1/wallet/balance`, session, deadline, fetcher),
2612
2621
  cli
2613
2622
  ]);
2623
+ if (wallet.status === "rejected" && wallet.reason instanceof ConsoleError && wallet.reason.kind === "auth") throw wallet.reason;
2614
2624
  const walletBalances = wallet.status === "fulfilled" ? normalizeBalances(wallet.value) : {};
2615
2625
  const cliBalances = funding.status === "fulfilled" && "balance" in funding.value ? normalizeBalances({ balanceUsd: funding.value.balance }) : {};
2616
2626
  const windows = funding.status === "fulfilled" ? funding.value.windows : [];
@@ -2623,7 +2633,7 @@ async function readDesktopQuota(session, signal, runner = runVela, fetcher = fet
2623
2633
  }
2624
2634
  const tier = (funding.status === "fulfilled" ? funding.value.tier : void 0) ?? session.plan;
2625
2635
  const updatedAt = funding.status === "fulfilled" && funding.value.generatedAt || (/* @__PURE__ */ new Date()).toISOString();
2626
- const note = noSubscription ? "\u684C\u9762\u767B\u5F55\u6001\u663E\u793A\u8BE5\u8D26\u53F7\u6CA1\u6709 Design Plan \u8BA2\u9605\uFF1B\u672A\u8BFB\u5230\u7684\u5206\u6C60\u4FDD\u6301\u672A\u77E5\u3002\u5982\u9700\u5B8C\u6574\u5206\u6C60\uFF0C\u8BF7\u5728\u8FDE\u63A5\u9875\u767B\u5F55\u5E76\u5173\u95ED\u201C\u4F18\u5148\u684C\u9762\u767B\u5F55\u6001\u201D\u3002" : !windows.length ? "\u684C\u9762\u767B\u5F55\u6001\u672A\u8FD4\u56DE\u5957\u9910\u7A97\u53E3\uFF1B\u5DF2\u8BFB\u5230\u7684\u94B1\u5305\u4F59\u989D\u7167\u5E38\u663E\u793A\uFF0C\u672A\u8BFB\u5230\u7684\u5206\u6C60\u4FDD\u6301\u672A\u77E5\u3002\u5982\u9700\u5B8C\u6574\u5206\u6C60\uFF0C\u8BF7\u5728\u8FDE\u63A5\u9875\u767B\u5F55\u5E76\u5173\u95ED\u201C\u4F18\u5148\u684C\u9762\u767B\u5F55\u6001\u201D\u3002" : "\u684C\u9762\u767B\u5F55\u6001\u90E8\u5206\u63A5\u53E3\u6743\u9650\u53D7\u9650\uFF1B\u672A\u8BFB\u5230\u7684\u5206\u6C60\u663E\u793A\u672A\u77E5\u3002\u5982\u9700\u5B8C\u6574\u5206\u6C60\uFF0C\u8BF7\u5728\u8FDE\u63A5\u9875\u767B\u5F55\u5E76\u5173\u95ED\u201C\u4F18\u5148\u684C\u9762\u767B\u5F55\u6001\u201D\u3002";
2636
+ const note = noSubscription ? "\u684C\u9762\u767B\u5F55\u6001\u663E\u793A\u8BE5\u8D26\u53F7\u6CA1\u6709 Design Plan \u8BA2\u9605\uFF1B\u672A\u8BFB\u5230\u7684\u5206\u6C60\u4FDD\u6301\u672A\u77E5\u3002\u53EF\u5728\u8FDE\u63A5\u9875\u5B8C\u6210\u72EC\u7ACB\u767B\u5F55\uFF0C\u63D2\u4EF6\u4F1A\u4F18\u5148\u91C7\u7528\u53EF\u8BFB\u53D6\u7684\u5B8C\u6574\u989D\u5EA6\u3002" : !windows.length ? "\u684C\u9762\u767B\u5F55\u6001\u672A\u8FD4\u56DE\u5957\u9910\u7A97\u53E3\uFF1B\u5DF2\u8BFB\u5230\u7684\u94B1\u5305\u4F59\u989D\u7167\u5E38\u663E\u793A\uFF0C\u672A\u8BFB\u5230\u7684\u5206\u6C60\u4FDD\u6301\u672A\u77E5\u3002\u53EF\u5728\u8FDE\u63A5\u9875\u5B8C\u6210\u72EC\u7ACB\u767B\u5F55\uFF0C\u63D2\u4EF6\u4F1A\u4F18\u5148\u91C7\u7528\u53EF\u8BFB\u53D6\u7684\u5B8C\u6574\u989D\u5EA6\u3002" : "\u684C\u9762\u767B\u5F55\u6001\u90E8\u5206\u63A5\u53E3\u6743\u9650\u53D7\u9650\uFF1B\u672A\u8BFB\u5230\u7684\u5206\u6C60\u663E\u793A\u672A\u77E5\u3002\u53EF\u5728\u8FDE\u63A5\u9875\u5B8C\u6210\u72EC\u7ACB\u767B\u5F55\uFF0C\u63D2\u4EF6\u4F1A\u4F18\u5148\u91C7\u7528\u53EF\u8BFB\u53D6\u7684\u5B8C\u6574\u989D\u5EA6\u3002";
2627
2637
  return {
2628
2638
  state: "partial",
2629
2639
  source: "desktop",
@@ -2649,7 +2659,7 @@ var MAX_WINDOWS = 64;
2649
2659
  var MAX_API_KEY = 16384;
2650
2660
  var HTTP_ASCII = /^[\x21-\x7e]+$/u;
2651
2661
  var ENV_REF = /^[A-Za-z_][A-Za-z0-9_]*$/u;
2652
- var MODEL_ID3 = /^[A-Za-z0-9._:/-]{1,128}$/u;
2662
+ var MODEL_ID2 = /^[A-Za-z0-9._:/-]{1,128}$/u;
2653
2663
  var LOGIN_PHASES = ["idle", "launching", "waiting", "verifying", "success", "cancelled", "error"];
2654
2664
  var QUOTA_STATES = ["ok", "partial", "need-login", "error"];
2655
2665
  var SESSION_SOURCES = ["desktop", "login", "environment"];
@@ -2663,7 +2673,7 @@ function isoTime(value, label) {
2663
2673
  if (!Number.isFinite(Date.parse(time))) throw new Error(`${label} \u5FC5\u987B\u662F ISO \u65F6\u95F4\u5B57\u7B26\u4E32`);
2664
2674
  return time;
2665
2675
  }
2666
- function flag2(value, label) {
2676
+ function flag(value, label) {
2667
2677
  if (typeof value !== "boolean") throw new Error(`${label} \u5FC5\u987B\u662F\u5E03\u5C14\u503C`);
2668
2678
  return value;
2669
2679
  }
@@ -2719,11 +2729,11 @@ function parseQuotaSnapshot(value) {
2719
2729
  ...value.subscriptionPeriodStart === void 0 ? {} : { subscriptionPeriodStart: isoTime(value.subscriptionPeriodStart, "\u8BA2\u9605\u5468\u671F\u5F00\u59CB\u65F6\u95F4") },
2720
2730
  ...value.subscriptionPeriodEnd === void 0 ? {} : { subscriptionPeriodEnd: isoTime(value.subscriptionPeriodEnd, "\u8BA2\u9605\u5468\u671F\u7ED3\u675F\u65F6\u95F4") },
2721
2731
  ...value.nextRefreshAt === void 0 ? {} : { nextRefreshAt: isoTime(value.nextRefreshAt, "\u4E0B\u6B21\u81EA\u52A8\u5237\u65B0\u65F6\u95F4") },
2722
- ...value.stale === void 0 ? {} : { stale: flag2(value.stale, "\u5386\u53F2\u989D\u5EA6\u8BFB\u6570") },
2732
+ ...value.stale === void 0 ? {} : { stale: flag(value.stale, "\u5386\u53F2\u989D\u5EA6\u8BFB\u6570") },
2723
2733
  ...value.refreshFailures === void 0 ? {} : { refreshFailures: count(value.refreshFailures, "\u8FDE\u7EED\u5237\u65B0\u5931\u8D25\u6B21\u6570") },
2724
- ...value.autoRefreshPaused === void 0 ? {} : { autoRefreshPaused: flag2(value.autoRefreshPaused, "\u81EA\u52A8\u5237\u65B0\u6682\u505C\u72B6\u6001") },
2734
+ ...value.autoRefreshPaused === void 0 ? {} : { autoRefreshPaused: flag(value.autoRefreshPaused, "\u81EA\u52A8\u5237\u65B0\u6682\u505C\u72B6\u6001") },
2725
2735
  ...value.tier === void 0 ? {} : { tier: text(value.tier, "\u5957\u9910\u540D", MAX_TIER) },
2726
- ...value.eligible === void 0 ? {} : { eligible: flag2(value.eligible, "\u5957\u9910\u8D44\u683C") },
2736
+ ...value.eligible === void 0 ? {} : { eligible: flag(value.eligible, "\u5957\u9910\u8D44\u683C") },
2727
2737
  windows: windows.map(parseQuotaWindow),
2728
2738
  balances: {
2729
2739
  ...balances.subscriptionUsd === void 0 ? {} : { subscriptionUsd: amount(balances.subscriptionUsd, "\u8BA2\u9605\u4F59\u989D") },
@@ -2748,12 +2758,12 @@ function parseLoginState(value) {
2748
2758
  function parseStatusModel(value) {
2749
2759
  if (!record(value)) throw new Error("\u6A21\u578B\u6761\u76EE\u5FC5\u987B\u662F\u5BF9\u8C61");
2750
2760
  const id = text(value.id, "\u6A21\u578B id", 128);
2751
- if (!MODEL_ID3.test(id)) throw new Error("\u6A21\u578B id \u542B\u4E0D\u5141\u8BB8\u7684\u5B57\u7B26");
2761
+ if (!MODEL_ID2.test(id)) throw new Error("\u6A21\u578B id \u542B\u4E0D\u5141\u8BB8\u7684\u5B57\u7B26");
2752
2762
  return {
2753
2763
  id,
2754
2764
  name: text(value.name, "\u6A21\u578B\u540D", 128),
2755
2765
  group: member(value.group, MODEL_GROUPS, "\u6A21\u578B\u5206\u7EC4"),
2756
- ...value.enabled === void 0 ? {} : { enabled: flag2(value.enabled, "\u6A21\u578B\u542F\u7528\u72B6\u6001") },
2766
+ ...value.enabled === void 0 ? {} : { enabled: flag(value.enabled, "\u6A21\u578B\u542F\u7528\u72B6\u6001") },
2757
2767
  ...value.contextWindow === void 0 ? {} : { contextWindow: positiveInteger(value.contextWindow, "\u4E0A\u4E0B\u6587\u9884\u7B97", 1e8) },
2758
2768
  ...value.maxOutputTokens === void 0 ? {} : { maxOutputTokens: positiveInteger(value.maxOutputTokens, "\u6700\u5927\u8F93\u51FA", 1e7) },
2759
2769
  ...value.reasoningEfforts === void 0 ? {} : { reasoningEfforts: parseEfforts(value.reasoningEfforts) }
@@ -2764,8 +2774,8 @@ function parseStatusConfig(value) {
2764
2774
  const apiKeyEnv = text(value.apiKeyEnv, "\u51ED\u636E\u5F15\u7528\u540D", MAX_ENV_REF);
2765
2775
  if (!ENV_REF.test(apiKeyEnv)) throw new Error("\u51ED\u636E\u5F15\u7528\u540D\u5FC5\u987B\u662F\u5408\u6CD5\u6807\u8BC6\u7B26");
2766
2776
  return {
2767
- emptyTurnGuard: flag2(value.emptyTurnGuard, "\u7A7A\u8F6E\u4FDD\u62A4\u5F00\u5173"),
2768
- useDesktopCredential: flag2(value.useDesktopCredential, "\u684C\u9762\u767B\u5F55\u6001\u5F00\u5173"),
2777
+ emptyTurnGuard: flag(value.emptyTurnGuard, "\u7A7A\u8F6E\u4FDD\u62A4\u5F00\u5173"),
2778
+ useDesktopCredential: flag(value.useDesktopCredential, "\u684C\u9762\u767B\u5F55\u6001\u5F00\u5173"),
2769
2779
  baseURL: text(value.baseURL, "\u63A8\u7406\u5730\u5740", MAX_BASE_URL),
2770
2780
  apiKeyEnv,
2771
2781
  ...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
@@ -2787,7 +2797,7 @@ function parseStatus(value) {
2787
2797
  }
2788
2798
  return {
2789
2799
  revision: text(value.revision, "\u914D\u7F6E\u7248\u672C", MAX_REVISION),
2790
- apiKeyConfigured: flag2(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
2800
+ apiKeyConfigured: flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
2791
2801
  ...value.sessionSource === void 0 ? {} : { sessionSource: member(value.sessionSource, SESSION_SOURCES, "\u767B\u5F55\u6001\u6765\u6E90") },
2792
2802
  quota: parseQuotaSnapshot(value.quota),
2793
2803
  login: parseLoginState(value.login),