dsh-opendesign-corouter 0.1.1 → 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/config.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import Schema from '@deepseek-ai/schemastery';
2
+ import { type ApiProtocol } from './protocol-options.js';
3
+ import { type ModelSettingsMap } from './model-settings.js';
2
4
  export declare const SETTINGS_NS = "llm-opendesign-corouter";
3
5
  export declare const PLAN_PROVIDER = "opendesign-corouter-plan";
4
6
  export declare const PAID_PROVIDER = "opendesign-corouter-paid";
@@ -6,15 +8,21 @@ export declare const DEFAULT_BASE_URL = "https://amr-link.open-design.ai/v1";
6
8
  export declare const Config: Schema<Schemastery.ObjectS<NoInfer<{
7
9
  apiKeyEnv: Schema<string, string, "volatile-defined">;
8
10
  baseURL: Schema<string, string, "volatile-defined">;
11
+ apiProtocol: Schema<"chat-completions" | "responses" | "messages", "chat-completions" | "responses" | "messages", "volatile-defined">;
12
+ modelSettings: Schema<NoInfer<import("@deepseek-ai/cosmokit").Dict<unknown, string>>, NoInfer<ModelSettingsMap>, "volatile-defined">;
9
13
  useDesktopCredential: Schema<boolean, boolean, "volatile-defined">;
10
14
  emptyTurnGuard: Schema<boolean, boolean, "volatile-defined">;
15
+ quotaRefreshSeconds: Schema<number, number, "volatile-defined">;
11
16
  requestTimeoutMs: Schema<number, number, "volatile-defined">;
12
17
  streamIdleTimeoutMs: Schema<number, number, "volatile-defined">;
13
18
  }>>, Schemastery.ObjectT<NoInfer<{
14
19
  apiKeyEnv: Schema<string, string, "volatile-defined">;
15
20
  baseURL: Schema<string, string, "volatile-defined">;
21
+ apiProtocol: Schema<"chat-completions" | "responses" | "messages", "chat-completions" | "responses" | "messages", "volatile-defined">;
22
+ modelSettings: Schema<NoInfer<import("@deepseek-ai/cosmokit").Dict<unknown, string>>, NoInfer<ModelSettingsMap>, "volatile-defined">;
16
23
  useDesktopCredential: Schema<boolean, boolean, "volatile-defined">;
17
24
  emptyTurnGuard: Schema<boolean, boolean, "volatile-defined">;
25
+ quotaRefreshSeconds: Schema<number, number, "volatile-defined">;
18
26
  requestTimeoutMs: Schema<number, number, "volatile-defined">;
19
27
  streamIdleTimeoutMs: Schema<number, number, "volatile-defined">;
20
28
  }>>, "plain">;
@@ -26,6 +34,9 @@ export interface RuntimeConfig {
26
34
  emptyTurnGuard: boolean;
27
35
  requestTimeoutMs: number;
28
36
  streamIdleTimeoutMs: number;
37
+ apiProtocol?: ApiProtocol;
38
+ modelSettings?: ModelSettingsMap;
39
+ quotaRefreshSeconds?: number;
29
40
  }
30
41
  export declare function assertBaseURL(raw: string): string;
31
42
  export declare function readConfig(config: LiveConfig): RuntimeConfig;
@@ -7,6 +7,53 @@ function record(value) {
7
7
  return value !== null && typeof value === "object" && !Array.isArray(value);
8
8
  }
9
9
 
10
+ // src/protocol-options.ts
11
+ var API_PROTOCOL_IDS = ["chat-completions", "responses", "messages"];
12
+
13
+ // src/model-settings.ts
14
+ function parseModelSettingsMap(value) {
15
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
16
+ const keys = Object.keys(value);
17
+ if (keys.length > 512) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u6700\u591A\u5141\u8BB8 512 \u4E2A\u6A21\u578B");
18
+ const fields = /* @__PURE__ */ new Set(["enabled", "temperature", "topP", "maxTokens", "contextWindow", "reasoningEffort"]);
19
+ const efforts = ["none", "minimal", "low", "medium", "high", "xhigh", "ultra", "max"];
20
+ const out = {};
21
+ for (const id of keys) {
22
+ if (["__proto__", "constructor", "prototype"].includes(id)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u4E0D\u5141\u8BB8\u4FDD\u7559\u5B57\u6BB5\u540D");
23
+ 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 . _ : / -");
24
+ const entry = value[id];
25
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry)) throw new Error("\u6BCF\u4E2A\u6A21\u578B\u7684\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
26
+ const settings = entry;
27
+ for (const field of Object.keys(settings)) {
28
+ if (!fields.has(field)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u542B\u6709\u4E0D\u652F\u6301\u7684\u5B57\u6BB5");
29
+ }
30
+ const parsed = {};
31
+ if (settings.enabled !== void 0) {
32
+ if (typeof settings.enabled !== "boolean") throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 enabled \u5FC5\u987B\u662F\u5E03\u5C14\u503C");
33
+ parsed.enabled = settings.enabled;
34
+ }
35
+ for (const [field, max] of [["temperature", 2], ["topP", 1]]) {
36
+ const item = settings[field];
37
+ if (item === void 0) continue;
38
+ 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`);
39
+ parsed[field] = item;
40
+ }
41
+ for (const [field, max] of [["maxTokens", 1e7], ["contextWindow", 1e8]]) {
42
+ const item = settings[field];
43
+ if (item === void 0) continue;
44
+ 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`);
45
+ parsed[field] = item;
46
+ }
47
+ if (settings.reasoningEffort !== void 0) {
48
+ 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");
49
+ parsed.reasoningEffort = settings.reasoningEffort;
50
+ }
51
+ 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");
52
+ out[id] = parsed;
53
+ }
54
+ return out;
55
+ }
56
+
10
57
  // src/remote.ts
11
58
  var MAX_REVISION = 256;
12
59
  var MAX_JOB_ID = 128;
@@ -20,7 +67,7 @@ var MAX_WINDOWS = 64;
20
67
  var MAX_API_KEY = 16384;
21
68
  var HTTP_ASCII = /^[\x21-\x7e]+$/u;
22
69
  var ENV_REF = /^[A-Za-z_][A-Za-z0-9_]*$/u;
23
- var MODEL_ID = /^[A-Za-z0-9._:-]{1,128}$/u;
70
+ var MODEL_ID = /^[A-Za-z0-9._:/-]{1,128}$/u;
24
71
  var LOGIN_PHASES = ["idle", "launching", "waiting", "verifying", "success", "cancelled", "error"];
25
72
  var QUOTA_STATES = ["ok", "partial", "need-login", "error"];
26
73
  var SESSION_SOURCES = ["desktop", "login", "environment"];
@@ -46,6 +93,15 @@ function amount(value, label, negative = false) {
46
93
  if (typeof value !== "number" || !Number.isFinite(value) || !negative && value < 0) throw new Error(`${label} \u5FC5\u987B\u662F${negative ? "" : "\u975E\u8D1F"}\u6709\u9650\u6570\u5B57`);
47
94
  return value;
48
95
  }
96
+ function positiveInteger(value, label, max) {
97
+ const result = count(value, label);
98
+ if (result === 0 || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
99
+ return result;
100
+ }
101
+ function parseEfforts(value) {
102
+ if (!Array.isArray(value) || value.length > 16) throw new Error("\u6A21\u578B\u601D\u8003\u6863\u4F4D\u683C\u5F0F\u65E0\u6548");
103
+ return value.map((item) => text(item, "\u601D\u8003\u6863\u4F4D", 32));
104
+ }
49
105
  function member(value, allowed, label) {
50
106
  const hit = allowed.find((candidate) => candidate === value);
51
107
  if (hit === void 0) throw new Error(`${label} \u4E0D\u5728\u5141\u8BB8\u7684\u53D6\u503C\u5185`);
@@ -63,7 +119,9 @@ function parseQuotaWindow(value) {
63
119
  limit,
64
120
  ...value.remaining === void 0 ? {} : { remaining: amount(value.remaining, "\u5269\u4F59\u989D\u5EA6") },
65
121
  percent: Math.min(100, Math.max(0, amount(value.percent, "\u5DF2\u7528\u767E\u5206\u6BD4"))),
66
- ...value.resetsAt === void 0 ? {} : { resetsAt: isoTime(value.resetsAt, "\u989D\u5EA6\u91CD\u7F6E\u65F6\u95F4") }
122
+ ...value.resetsAt === void 0 ? {} : { resetsAt: isoTime(value.resetsAt, "\u989D\u5EA6\u91CD\u7F6E\u65F6\u95F4") },
123
+ ...value.windowStart === void 0 ? {} : { windowStart: isoTime(value.windowStart, "\u989D\u5EA6\u7A97\u53E3\u5F00\u59CB\u65F6\u95F4") },
124
+ ...value.resetMode === void 0 ? {} : { resetMode: text(value.resetMode, "\u989D\u5EA6\u5237\u65B0\u65B9\u5F0F", 128) }
67
125
  };
68
126
  }
69
127
  function parseQuotaSnapshot(value) {
@@ -76,6 +134,12 @@ function parseQuotaSnapshot(value) {
76
134
  state: member(value.state, QUOTA_STATES, "\u989D\u5EA6\u72B6\u6001"),
77
135
  ...value.source === void 0 ? {} : { source: member(value.source, SESSION_SOURCES, "\u989D\u5EA6\u6765\u6E90") },
78
136
  updatedAt: isoTime(value.updatedAt, "\u989D\u5EA6\u66F4\u65B0\u65F6\u95F4"),
137
+ ...value.subscriptionPeriodStart === void 0 ? {} : { subscriptionPeriodStart: isoTime(value.subscriptionPeriodStart, "\u8BA2\u9605\u5468\u671F\u5F00\u59CB\u65F6\u95F4") },
138
+ ...value.subscriptionPeriodEnd === void 0 ? {} : { subscriptionPeriodEnd: isoTime(value.subscriptionPeriodEnd, "\u8BA2\u9605\u5468\u671F\u7ED3\u675F\u65F6\u95F4") },
139
+ ...value.nextRefreshAt === void 0 ? {} : { nextRefreshAt: isoTime(value.nextRefreshAt, "\u4E0B\u6B21\u81EA\u52A8\u5237\u65B0\u65F6\u95F4") },
140
+ ...value.stale === void 0 ? {} : { stale: flag(value.stale, "\u5386\u53F2\u989D\u5EA6\u8BFB\u6570") },
141
+ ...value.refreshFailures === void 0 ? {} : { refreshFailures: count(value.refreshFailures, "\u8FDE\u7EED\u5237\u65B0\u5931\u8D25\u6B21\u6570") },
142
+ ...value.autoRefreshPaused === void 0 ? {} : { autoRefreshPaused: flag(value.autoRefreshPaused, "\u81EA\u52A8\u5237\u65B0\u6682\u505C\u72B6\u6001") },
79
143
  ...value.tier === void 0 ? {} : { tier: text(value.tier, "\u5957\u9910\u540D", MAX_TIER) },
80
144
  ...value.eligible === void 0 ? {} : { eligible: flag(value.eligible, "\u5957\u9910\u8D44\u683C") },
81
145
  windows: windows.map(parseQuotaWindow),
@@ -106,7 +170,11 @@ function parseStatusModel(value) {
106
170
  return {
107
171
  id,
108
172
  name: text(value.name, "\u6A21\u578B\u540D", 128),
109
- group: member(value.group, MODEL_GROUPS, "\u6A21\u578B\u5206\u7EC4")
173
+ group: member(value.group, MODEL_GROUPS, "\u6A21\u578B\u5206\u7EC4"),
174
+ ...value.enabled === void 0 ? {} : { enabled: flag(value.enabled, "\u6A21\u578B\u542F\u7528\u72B6\u6001") },
175
+ ...value.contextWindow === void 0 ? {} : { contextWindow: positiveInteger(value.contextWindow, "\u4E0A\u4E0B\u6587\u9884\u7B97", 1e8) },
176
+ ...value.maxOutputTokens === void 0 ? {} : { maxOutputTokens: positiveInteger(value.maxOutputTokens, "\u6700\u5927\u8F93\u51FA", 1e7) },
177
+ ...value.reasoningEfforts === void 0 ? {} : { reasoningEfforts: parseEfforts(value.reasoningEfforts) }
110
178
  };
111
179
  }
112
180
  function parseStatusConfig(value) {
@@ -117,7 +185,12 @@ function parseStatusConfig(value) {
117
185
  emptyTurnGuard: flag(value.emptyTurnGuard, "\u7A7A\u8F6E\u4FDD\u62A4\u5F00\u5173"),
118
186
  useDesktopCredential: flag(value.useDesktopCredential, "\u684C\u9762\u767B\u5F55\u6001\u5F00\u5173"),
119
187
  baseURL: text(value.baseURL, "\u63A8\u7406\u5730\u5740", MAX_BASE_URL),
120
- apiKeyEnv
188
+ apiKeyEnv,
189
+ ...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
190
+ ...value.modelSettings === void 0 ? {} : { modelSettings: parseModelSettingsMap(value.modelSettings) },
191
+ ...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5) },
192
+ ...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5) },
193
+ ...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600) }
121
194
  };
122
195
  }
123
196
  function parseStatus(value) {
@@ -138,7 +211,10 @@ function parseStatus(value) {
138
211
  login: parseLoginState(value.login),
139
212
  config: parseStatusConfig(value.config),
140
213
  guardedTurns: count(value.guardedTurns, "\u5DF2\u62E6\u622A\u7A7A\u8F6E\u6570"),
141
- models: parsed
214
+ models: parsed,
215
+ ...value.modelsSource === void 0 ? {} : { modelsSource: member(value.modelsSource, ["builtin", "openai"], "\u6A21\u578B\u76EE\u5F55\u6765\u6E90") },
216
+ ...value.modelsUpdatedAt === void 0 ? {} : { modelsUpdatedAt: isoTime(value.modelsUpdatedAt, "\u6A21\u578B\u66F4\u65B0\u65F6\u95F4") },
217
+ ...value.modelsError === void 0 ? {} : { modelsError: text(value.modelsError, "\u6A21\u578B\u66F4\u65B0\u63D0\u793A", MAX_MESSAGE) }
142
218
  };
143
219
  }
144
220
  function parseStartLoginRequest(value) {
@@ -167,7 +243,9 @@ var CancelLoginRequestCodec = { mode: "strict", typeSymbol: "dsh-opendesign-coro
167
243
  var SaveApiKeyRequestCodec = { mode: "strict", typeSymbol: "dsh-opendesign-corouter#SaveApiKeyRequest", create: () => z.unknown().transform((value) => parseSaveApiKeyRequest(value)) };
168
244
  var TYPERT_REMOTE = createTypertRemoteInfo({ package: "dsh-opendesign-corouter", methods: {
169
245
  "openDesignCoRouter/status": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [], result: StatusCodec },
246
+ "openDesignCoRouter/refreshModels": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [], result: StatusCodec },
170
247
  "openDesignCoRouter/refreshQuota": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [], result: QuotaSnapshotCodec },
248
+ "openDesignCoRouter/refreshQuotaNow": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [], result: QuotaSnapshotCodec },
171
249
  "openDesignCoRouter/startLogin": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [{ name: "input", source: "json", codec: StartLoginRequestCodec, strictCodec: StartLoginRequestCodec }], result: LoginStateCodec },
172
250
  "openDesignCoRouter/loginStatus": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [], result: LoginStateCodec },
173
251
  "openDesignCoRouter/cancelLogin": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [{ name: "input", source: "json", codec: CancelLoginRequestCodec, strictCodec: CancelLoginRequestCodec }], result: LoginStateCodec },
@@ -2,7 +2,9 @@ import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol';
2
2
  import type { Status, QuotaSnapshot, LoginState, StartLoginRequest, CancelLoginRequest, SaveApiKeyRequest } from '../remote.js';
3
3
  export type CoRouterRemote = {
4
4
  status: () => Promise<RemoteResult<Status>>;
5
+ refreshModels: () => Promise<RemoteResult<Status>>;
5
6
  refreshQuota: () => Promise<RemoteResult<QuotaSnapshot>>;
7
+ refreshQuotaNow: () => Promise<RemoteResult<QuotaSnapshot>>;
6
8
  startLogin: (input: StartLoginRequest) => Promise<RemoteResult<LoginState>>;
7
9
  loginStatus: () => Promise<RemoteResult<LoginState>>;
8
10
  cancelLogin: (input: CancelLoginRequest) => Promise<RemoteResult<LoginState>>;
@@ -7,6 +7,53 @@ function record(value) {
7
7
  return value !== null && typeof value === "object" && !Array.isArray(value);
8
8
  }
9
9
 
10
+ // src/protocol-options.ts
11
+ var API_PROTOCOL_IDS = ["chat-completions", "responses", "messages"];
12
+
13
+ // src/model-settings.ts
14
+ function parseModelSettingsMap(value) {
15
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
16
+ const keys = Object.keys(value);
17
+ if (keys.length > 512) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u6700\u591A\u5141\u8BB8 512 \u4E2A\u6A21\u578B");
18
+ const fields = /* @__PURE__ */ new Set(["enabled", "temperature", "topP", "maxTokens", "contextWindow", "reasoningEffort"]);
19
+ const efforts = ["none", "minimal", "low", "medium", "high", "xhigh", "ultra", "max"];
20
+ const out = {};
21
+ for (const id of keys) {
22
+ if (["__proto__", "constructor", "prototype"].includes(id)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u4E0D\u5141\u8BB8\u4FDD\u7559\u5B57\u6BB5\u540D");
23
+ 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 . _ : / -");
24
+ const entry = value[id];
25
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry)) throw new Error("\u6BCF\u4E2A\u6A21\u578B\u7684\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
26
+ const settings = entry;
27
+ for (const field of Object.keys(settings)) {
28
+ if (!fields.has(field)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u542B\u6709\u4E0D\u652F\u6301\u7684\u5B57\u6BB5");
29
+ }
30
+ const parsed = {};
31
+ if (settings.enabled !== void 0) {
32
+ if (typeof settings.enabled !== "boolean") throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 enabled \u5FC5\u987B\u662F\u5E03\u5C14\u503C");
33
+ parsed.enabled = settings.enabled;
34
+ }
35
+ for (const [field, max] of [["temperature", 2], ["topP", 1]]) {
36
+ const item = settings[field];
37
+ if (item === void 0) continue;
38
+ 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`);
39
+ parsed[field] = item;
40
+ }
41
+ for (const [field, max] of [["maxTokens", 1e7], ["contextWindow", 1e8]]) {
42
+ const item = settings[field];
43
+ if (item === void 0) continue;
44
+ 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`);
45
+ parsed[field] = item;
46
+ }
47
+ if (settings.reasoningEffort !== void 0) {
48
+ 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");
49
+ parsed.reasoningEffort = settings.reasoningEffort;
50
+ }
51
+ 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");
52
+ out[id] = parsed;
53
+ }
54
+ return out;
55
+ }
56
+
10
57
  // src/remote.ts
11
58
  var MAX_REVISION = 256;
12
59
  var MAX_JOB_ID = 128;
@@ -20,7 +67,7 @@ var MAX_WINDOWS = 64;
20
67
  var MAX_API_KEY = 16384;
21
68
  var HTTP_ASCII = /^[\x21-\x7e]+$/u;
22
69
  var ENV_REF = /^[A-Za-z_][A-Za-z0-9_]*$/u;
23
- var MODEL_ID = /^[A-Za-z0-9._:-]{1,128}$/u;
70
+ var MODEL_ID = /^[A-Za-z0-9._:/-]{1,128}$/u;
24
71
  var LOGIN_PHASES = ["idle", "launching", "waiting", "verifying", "success", "cancelled", "error"];
25
72
  var QUOTA_STATES = ["ok", "partial", "need-login", "error"];
26
73
  var SESSION_SOURCES = ["desktop", "login", "environment"];
@@ -46,6 +93,15 @@ function amount(value, label, negative = false) {
46
93
  if (typeof value !== "number" || !Number.isFinite(value) || !negative && value < 0) throw new Error(`${label} \u5FC5\u987B\u662F${negative ? "" : "\u975E\u8D1F"}\u6709\u9650\u6570\u5B57`);
47
94
  return value;
48
95
  }
96
+ function positiveInteger(value, label, max) {
97
+ const result = count(value, label);
98
+ if (result === 0 || result > max) throw new Error(`${label} \u8D85\u51FA\u8303\u56F4`);
99
+ return result;
100
+ }
101
+ function parseEfforts(value) {
102
+ if (!Array.isArray(value) || value.length > 16) throw new Error("\u6A21\u578B\u601D\u8003\u6863\u4F4D\u683C\u5F0F\u65E0\u6548");
103
+ return value.map((item) => text(item, "\u601D\u8003\u6863\u4F4D", 32));
104
+ }
49
105
  function member(value, allowed, label) {
50
106
  const hit = allowed.find((candidate) => candidate === value);
51
107
  if (hit === void 0) throw new Error(`${label} \u4E0D\u5728\u5141\u8BB8\u7684\u53D6\u503C\u5185`);
@@ -63,7 +119,9 @@ function parseQuotaWindow(value) {
63
119
  limit,
64
120
  ...value.remaining === void 0 ? {} : { remaining: amount(value.remaining, "\u5269\u4F59\u989D\u5EA6") },
65
121
  percent: Math.min(100, Math.max(0, amount(value.percent, "\u5DF2\u7528\u767E\u5206\u6BD4"))),
66
- ...value.resetsAt === void 0 ? {} : { resetsAt: isoTime(value.resetsAt, "\u989D\u5EA6\u91CD\u7F6E\u65F6\u95F4") }
122
+ ...value.resetsAt === void 0 ? {} : { resetsAt: isoTime(value.resetsAt, "\u989D\u5EA6\u91CD\u7F6E\u65F6\u95F4") },
123
+ ...value.windowStart === void 0 ? {} : { windowStart: isoTime(value.windowStart, "\u989D\u5EA6\u7A97\u53E3\u5F00\u59CB\u65F6\u95F4") },
124
+ ...value.resetMode === void 0 ? {} : { resetMode: text(value.resetMode, "\u989D\u5EA6\u5237\u65B0\u65B9\u5F0F", 128) }
67
125
  };
68
126
  }
69
127
  function parseQuotaSnapshot(value) {
@@ -76,6 +134,12 @@ function parseQuotaSnapshot(value) {
76
134
  state: member(value.state, QUOTA_STATES, "\u989D\u5EA6\u72B6\u6001"),
77
135
  ...value.source === void 0 ? {} : { source: member(value.source, SESSION_SOURCES, "\u989D\u5EA6\u6765\u6E90") },
78
136
  updatedAt: isoTime(value.updatedAt, "\u989D\u5EA6\u66F4\u65B0\u65F6\u95F4"),
137
+ ...value.subscriptionPeriodStart === void 0 ? {} : { subscriptionPeriodStart: isoTime(value.subscriptionPeriodStart, "\u8BA2\u9605\u5468\u671F\u5F00\u59CB\u65F6\u95F4") },
138
+ ...value.subscriptionPeriodEnd === void 0 ? {} : { subscriptionPeriodEnd: isoTime(value.subscriptionPeriodEnd, "\u8BA2\u9605\u5468\u671F\u7ED3\u675F\u65F6\u95F4") },
139
+ ...value.nextRefreshAt === void 0 ? {} : { nextRefreshAt: isoTime(value.nextRefreshAt, "\u4E0B\u6B21\u81EA\u52A8\u5237\u65B0\u65F6\u95F4") },
140
+ ...value.stale === void 0 ? {} : { stale: flag(value.stale, "\u5386\u53F2\u989D\u5EA6\u8BFB\u6570") },
141
+ ...value.refreshFailures === void 0 ? {} : { refreshFailures: count(value.refreshFailures, "\u8FDE\u7EED\u5237\u65B0\u5931\u8D25\u6B21\u6570") },
142
+ ...value.autoRefreshPaused === void 0 ? {} : { autoRefreshPaused: flag(value.autoRefreshPaused, "\u81EA\u52A8\u5237\u65B0\u6682\u505C\u72B6\u6001") },
79
143
  ...value.tier === void 0 ? {} : { tier: text(value.tier, "\u5957\u9910\u540D", MAX_TIER) },
80
144
  ...value.eligible === void 0 ? {} : { eligible: flag(value.eligible, "\u5957\u9910\u8D44\u683C") },
81
145
  windows: windows.map(parseQuotaWindow),
@@ -106,7 +170,11 @@ function parseStatusModel(value) {
106
170
  return {
107
171
  id,
108
172
  name: text(value.name, "\u6A21\u578B\u540D", 128),
109
- group: member(value.group, MODEL_GROUPS, "\u6A21\u578B\u5206\u7EC4")
173
+ group: member(value.group, MODEL_GROUPS, "\u6A21\u578B\u5206\u7EC4"),
174
+ ...value.enabled === void 0 ? {} : { enabled: flag(value.enabled, "\u6A21\u578B\u542F\u7528\u72B6\u6001") },
175
+ ...value.contextWindow === void 0 ? {} : { contextWindow: positiveInteger(value.contextWindow, "\u4E0A\u4E0B\u6587\u9884\u7B97", 1e8) },
176
+ ...value.maxOutputTokens === void 0 ? {} : { maxOutputTokens: positiveInteger(value.maxOutputTokens, "\u6700\u5927\u8F93\u51FA", 1e7) },
177
+ ...value.reasoningEfforts === void 0 ? {} : { reasoningEfforts: parseEfforts(value.reasoningEfforts) }
110
178
  };
111
179
  }
112
180
  function parseStatusConfig(value) {
@@ -117,7 +185,12 @@ function parseStatusConfig(value) {
117
185
  emptyTurnGuard: flag(value.emptyTurnGuard, "\u7A7A\u8F6E\u4FDD\u62A4\u5F00\u5173"),
118
186
  useDesktopCredential: flag(value.useDesktopCredential, "\u684C\u9762\u767B\u5F55\u6001\u5F00\u5173"),
119
187
  baseURL: text(value.baseURL, "\u63A8\u7406\u5730\u5740", MAX_BASE_URL),
120
- apiKeyEnv
188
+ apiKeyEnv,
189
+ ...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
190
+ ...value.modelSettings === void 0 ? {} : { modelSettings: parseModelSettingsMap(value.modelSettings) },
191
+ ...value.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: positiveInteger(value.requestTimeoutMs, "\u8BF7\u6C42\u8D85\u65F6", 36e5) },
192
+ ...value.streamIdleTimeoutMs === void 0 ? {} : { streamIdleTimeoutMs: positiveInteger(value.streamIdleTimeoutMs, "\u6D41\u7A7A\u95F2\u8D85\u65F6", 18e5) },
193
+ ...value.quotaRefreshSeconds === void 0 ? {} : { quotaRefreshSeconds: positiveInteger(value.quotaRefreshSeconds, "\u81EA\u52A8\u5237\u65B0\u95F4\u9694", 3600) }
121
194
  };
122
195
  }
123
196
  function parseStatus(value) {
@@ -138,7 +211,10 @@ function parseStatus(value) {
138
211
  login: parseLoginState(value.login),
139
212
  config: parseStatusConfig(value.config),
140
213
  guardedTurns: count(value.guardedTurns, "\u5DF2\u62E6\u622A\u7A7A\u8F6E\u6570"),
141
- models: parsed
214
+ models: parsed,
215
+ ...value.modelsSource === void 0 ? {} : { modelsSource: member(value.modelsSource, ["builtin", "openai"], "\u6A21\u578B\u76EE\u5F55\u6765\u6E90") },
216
+ ...value.modelsUpdatedAt === void 0 ? {} : { modelsUpdatedAt: isoTime(value.modelsUpdatedAt, "\u6A21\u578B\u66F4\u65B0\u65F6\u95F4") },
217
+ ...value.modelsError === void 0 ? {} : { modelsError: text(value.modelsError, "\u6A21\u578B\u66F4\u65B0\u63D0\u793A", MAX_MESSAGE) }
142
218
  };
143
219
  }
144
220
  function parseStartLoginRequest(value) {
@@ -167,7 +243,9 @@ var CancelLoginRequestCodec = { mode: "strict", typeSymbol: "dsh-opendesign-coro
167
243
  var SaveApiKeyRequestCodec = { mode: "strict", typeSymbol: "dsh-opendesign-corouter#SaveApiKeyRequest", create: () => z.unknown().transform((value) => parseSaveApiKeyRequest(value)) };
168
244
  var TYPERT_REMOTE = createTypertRemoteInfo({ package: "dsh-opendesign-corouter", methods: {
169
245
  "openDesignCoRouter/status": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [], result: StatusCodec },
246
+ "openDesignCoRouter/refreshModels": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [], result: StatusCodec },
170
247
  "openDesignCoRouter/refreshQuota": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [], result: QuotaSnapshotCodec },
248
+ "openDesignCoRouter/refreshQuotaNow": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [], result: QuotaSnapshotCodec },
171
249
  "openDesignCoRouter/startLogin": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [{ name: "input", source: "json", codec: StartLoginRequestCodec, strictCodec: StartLoginRequestCodec }], result: LoginStateCodec },
172
250
  "openDesignCoRouter/loginStatus": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [], result: LoginStateCodec },
173
251
  "openDesignCoRouter/cancelLogin": { service: "openDesignCoRouter", invocation: { kind: "direct" }, parameters: [{ name: "input", source: "json", codec: CancelLoginRequestCodec, strictCodec: CancelLoginRequestCodec }], result: LoginStateCodec },
package/lib/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import type { Context } from '@deepseek-ai/cordis';
2
2
  import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
3
+ import { fetchModelCatalog } from './model-discovery.js';
4
+ import type { CatalogModel } from './catalog.js';
3
5
  import { readConfig, type LiveConfig } from './config.js';
4
6
  import { resolveSession } from './auth.js';
5
7
  import { readQuota, type QuotaSnapshot } from './quota.js';
@@ -14,6 +16,8 @@ export interface HostDependencies {
14
16
  resolveSession: typeof resolveSession;
15
17
  readQuota: typeof readQuota;
16
18
  readDesktopQuota: typeof readDesktopQuota;
19
+ fetchModels?: typeof fetchModelCatalog;
20
+ modelsChanged?: () => void;
17
21
  }
18
22
  export declare class OpenDesignCoRouterService extends TypertRemoteService {
19
23
  readonly dependencies: HostDependencies;
@@ -25,10 +29,19 @@ export declare class OpenDesignCoRouterService extends TypertRemoteService {
25
29
  private _quota;
26
30
  private _quotaAt;
27
31
  private _quotaConfig;
32
+ private _quotaIdentity;
28
33
  private _quotaEpoch;
29
34
  private _quotaPending;
30
35
  private _quotaController;
31
36
  guardedTurns: number;
37
+ private _models;
38
+ private _modelsUpdatedAt;
39
+ private _modelsError;
40
+ private _modelsFingerprint;
41
+ private _modelsEpoch;
42
+ private _modelsPending;
43
+ private _modelsController;
44
+ modelCatalog(): readonly CatalogModel[];
32
45
  constructor(ctx: Context, config: () => ReturnType<typeof readConfig>, dependencies?: HostDependencies);
33
46
  private _credentials;
34
47
  resolveApiKey(ref: string): Promise<string | undefined>;
@@ -37,7 +50,10 @@ export declare class OpenDesignCoRouterService extends TypertRemoteService {
37
50
  private _expect;
38
51
  private _invalidateQuota;
39
52
  status(): Promise<Status>;
53
+ refreshModels(): Promise<Status>;
40
54
  refreshQuota(): Promise<QuotaSnapshot>;
55
+ refreshQuotaNow(): Promise<QuotaSnapshot>;
56
+ private _refreshQuota;
41
57
  private _readQuota;
42
58
  startLogin(input: StartLoginRequest): Promise<LoginState>;
43
59
  loginStatus(): LoginState;