dsh-opendesign-corouter 0.1.6 → 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.
@@ -122,9 +122,9 @@ function amount(value, label, negative = false) {
122
122
  if (typeof value !== "number" || !Number.isFinite(value) || !negative && value < 0) throw new Error(`${label} \u5FC5\u987B\u662F${negative ? "" : "\u975E\u8D1F"}\u6709\u9650\u6570\u5B57`);
123
123
  return value;
124
124
  }
125
- function positiveInteger(value, label, max) {
125
+ function positiveInteger(value, label, max, min = 1) {
126
126
  const result = count(value, label);
127
- if (result === 0 || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
127
+ if (result < min || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
128
128
  return result;
129
129
  }
130
130
  function parseEfforts(value) {
@@ -227,9 +227,9 @@ function parseStatusConfig(value) {
227
227
  apiKeyEnv,
228
228
  ...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
229
229
  ...value.modelSettings === void 0 ? {} : { modelSettings: parseModelSettingsMap(value.modelSettings) },
230
- ...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5) },
231
- ...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5) },
232
- ...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600) }
230
+ ...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5, 1e3) },
231
+ ...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5, 1e3) },
232
+ ...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600, 5) }
233
233
  };
234
234
  }
235
235
  function parseStatus(value) {
@@ -242,9 +242,13 @@ function parseStatus(value) {
242
242
  if (ids.has(model.id)) throw new Error(`\u6A21\u578B\u5217\u8868\u91CD\u590D\u4E86 id "${model.id}"`);
243
243
  ids.add(model.id);
244
244
  }
245
+ const apiKeyConfigured = flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA");
246
+ const apiKeySource = value.apiKeySource === void 0 ? void 0 : member(value.apiKeySource, ["reference", "stored", "device"], "\u63A8\u7406\u51ED\u636E\u6765\u6E90");
247
+ if (!apiKeyConfigured && apiKeySource !== void 0) throw new Error("\u672A\u914D\u7F6E\u51ED\u636E\u65F6\u4E0D\u80FD\u6307\u5B9A\u63A8\u7406\u51ED\u636E\u6765\u6E90");
245
248
  return {
246
249
  revision: text(value.revision, "\u914D\u7F6E\u7248\u672C", MAX_REVISION),
247
- apiKeyConfigured: flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
250
+ apiKeyConfigured,
251
+ ...apiKeySource === void 0 ? {} : { apiKeySource },
248
252
  ...value.sessionSource === void 0 ? {} : { sessionSource: member(value.sessionSource, SESSION_SOURCES, "\u767B\u5F55\u6001\u6765\u6E90") },
249
253
  quota: parseQuotaSnapshot(value.quota),
250
254
  login: parseLoginState(value.login),
package/lib/index.js CHANGED
@@ -302,7 +302,7 @@ var DEFAULT_BASE_URL = "https://amr-link.open-design.ai/v1";
302
302
  var Config = Schema.object({
303
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(),
304
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(),
305
- 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(),
306
306
  modelSettings: Schema.transform(Schema.dict(Schema.any()), parseModelSettingsMap).default({}).description("\u9010\u6A21\u578B\u542F\u7528\u72B6\u6001\u548C\u8BF7\u6C42\u53C2\u6570").volatile(),
307
307
  useDesktopCredential: Schema.boolean().default(true).description("\u4F18\u5148\u8BFB\u53D6 OpenDesign \u684C\u9762\u7AEF\u767B\u5F55\u6001\u67E5\u8BE2\u989D\u5EA6").volatile(),
308
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(),
@@ -2200,7 +2200,7 @@ import { randomUUID } from "node:crypto";
2200
2200
 
2201
2201
  // src/device-auth.ts
2202
2202
  var DEVICE_AUTH_ENDPOINT = "https://amr-api.open-design.ai/api/v1/cli/device-authorizations";
2203
- var DEVICE_AUTH_PLUGIN_VERSION = "0.1.6";
2203
+ var DEVICE_AUTH_PLUGIN_VERSION = "0.1.7";
2204
2204
  var DEVICE_REQUEST_TIMEOUT_MS = 2e4;
2205
2205
  var DEVICE_RESPONSE_MAX_BYTES = 65536;
2206
2206
  var DEVICE_POLL_MIN_MS = 1e3;
@@ -3171,9 +3171,9 @@ function amount(value, label, negative = false) {
3171
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`);
3172
3172
  return value;
3173
3173
  }
3174
- function positiveInteger(value, label, max) {
3174
+ function positiveInteger(value, label, max, min = 1) {
3175
3175
  const result = count(value, label);
3176
- 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`);
3177
3177
  return result;
3178
3178
  }
3179
3179
  function parseEfforts(value) {
@@ -3276,9 +3276,9 @@ function parseStatusConfig(value) {
3276
3276
  apiKeyEnv,
3277
3277
  ...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
3278
3278
  ...value.modelSettings === void 0 ? {} : { modelSettings: parseModelSettingsMap(value.modelSettings) },
3279
- ...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5) },
3280
- ...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5) },
3281
- ...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) }
3282
3282
  };
3283
3283
  }
3284
3284
  function parseStatus(value) {
@@ -3291,9 +3291,13 @@ function parseStatus(value) {
3291
3291
  if (ids.has(model.id)) throw new Error(`\u6A21\u578B\u5217\u8868\u91CD\u590D\u4E86 id "${model.id}"`);
3292
3292
  ids.add(model.id);
3293
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");
3294
3297
  return {
3295
3298
  revision: text(value.revision, "\u914D\u7F6E\u7248\u672C", MAX_REVISION),
3296
- apiKeyConfigured: flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
3299
+ apiKeyConfigured,
3300
+ ...apiKeySource === void 0 ? {} : { apiKeySource },
3297
3301
  ...value.sessionSource === void 0 ? {} : { sessionSource: member(value.sessionSource, SESSION_SOURCES, "\u767B\u5F55\u6001\u6765\u6E90") },
3298
3302
  quota: parseQuotaSnapshot(value.quota),
3299
3303
  login: parseLoginState(value.login),
@@ -3332,7 +3336,8 @@ var inject = ["llm"];
3332
3336
  var API_KEY = credentialKey(name, "api-key");
3333
3337
  var SESSION = credentialKey(name, "console");
3334
3338
  var hash = (value) => createHash("sha256").update(JSON.stringify(value) ?? "").digest("hex");
3335
- 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" });
3336
3341
  function grantOf(value) {
3337
3342
  if (value?.kind !== "grant" || !record(value.payload)) return;
3338
3343
  if (value.payload.kind === "device") return deviceGrant(value.payload);
@@ -3351,7 +3356,7 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3351
3356
  __publicField(this, "_lifetime", new AbortController());
3352
3357
  __publicField(this, "_revision", randomUUID2());
3353
3358
  __publicField(this, "_fingerprint", "");
3354
- __publicField(this, "_quota", needLogin());
3359
+ __publicField(this, "_quota", unreadQuota());
3355
3360
  __publicField(this, "_quotaAt", 0);
3356
3361
  __publicField(this, "_quotaConfig", "");
3357
3362
  __publicField(this, "_quotaIdentity");
@@ -3417,15 +3422,15 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3417
3422
  async _key(ref, baseURL, apiRecord, sessionRecord) {
3418
3423
  const credentials = this.ctx.get("credentials");
3419
3424
  const ambient = credentials ? (await credentials.resolve(credentialRef(ref)))?.value : launchEnvironmentOf(this.ctx).get(ref)?.value;
3420
- if (ambient?.trim()) return ambient;
3421
- 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" };
3422
3427
  const grant = grantOf(sessionRecord);
3423
- 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;
3424
3429
  }
3425
3430
  async resolveApiKey(ref, baseURL = this._config().baseURL) {
3426
3431
  const credentials = this.ctx.get("credentials");
3427
3432
  const [apiRecord, sessionRecord] = await Promise.all([credentials?.readRecord(API_KEY), credentials?.readRecord(SESSION)]);
3428
- return this._key(ref, baseURL, apiRecord, sessionRecord);
3433
+ return (await this._key(ref, baseURL, apiRecord, sessionRecord))?.key;
3429
3434
  }
3430
3435
  _invalidateModels() {
3431
3436
  const changed = this._modelsUpdatedAt !== void 0;
@@ -3445,8 +3450,9 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3445
3450
  async _state() {
3446
3451
  const credentials = this.ctx.get("credentials"), config = this._config();
3447
3452
  const [apiRecord, sessionRecord] = await Promise.all([credentials?.readRecord(API_KEY), credentials?.readRecord(SESSION)]);
3448
- const key = await this._key(config.apiKeyEnv, config.baseURL, apiRecord, sessionRecord);
3449
- 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 };
3450
3456
  const modelsFingerprint = hash({ key, baseURL: config.baseURL });
3451
3457
  if (modelsFingerprint !== this._modelsFingerprint) {
3452
3458
  this._modelsFingerprint = modelsFingerprint;
@@ -3468,7 +3474,7 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3468
3474
  _invalidateQuota() {
3469
3475
  this._quotaAt = 0;
3470
3476
  this._quotaEpoch++;
3471
- this._quota = needLogin();
3477
+ this._quota = unreadQuota();
3472
3478
  this._quotaIdentity = void 0;
3473
3479
  this._quotaController?.abort();
3474
3480
  this._quotaPending = void 0;
@@ -3483,6 +3489,7 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3483
3489
  return parseStatus({
3484
3490
  revision: this._revision,
3485
3491
  apiKeyConfigured: Boolean(state.key?.trim()),
3492
+ ...state.keySource ? { apiKeySource: state.keySource } : {},
3486
3493
  ...this._quota.source ? { sessionSource: this._quota.source } : {},
3487
3494
  quota: this._quota,
3488
3495
  login: this._login.status(),
@@ -3507,7 +3514,7 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3507
3514
  if (this._modelsPending) return this._modelsPending;
3508
3515
  const key = state.key;
3509
3516
  if (!key?.trim()) {
3510
- 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";
3511
3518
  return this.status();
3512
3519
  }
3513
3520
  const epoch = this._modelsEpoch;
@@ -3519,10 +3526,18 @@ var OpenDesignCoRouterService = class extends (_a = TypertRemoteService, _status
3519
3526
  const models = await (this.dependencies.fetchModels ?? fetchModelCatalog)(state.config.baseURL, key, signal);
3520
3527
  await this._state();
3521
3528
  if (signal.aborted || epoch !== this._modelsEpoch) return this.status();
3529
+ const previousModels = this._models;
3530
+ const previousUpdatedAt = this._modelsUpdatedAt;
3522
3531
  this._models = models;
3523
3532
  this._modelsUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
3524
3533
  this._modelsError = void 0;
3525
- 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
+ }
3526
3541
  } catch (error) {
3527
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";
3528
3543
  }