dsh-multi-router 0.6.1 → 0.6.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/CHANGELOG.md +12 -0
- package/README.md +7 -1
- package/cordis.patch.yml +2 -2
- package/lib/accounts.js +2 -2
- package/lib/api-service.js +3 -3
- package/lib/{chunk-VZPXRK7Q.js → chunk-BVH4K6WH.js} +2 -2
- package/lib/{chunk-625KMEYS.js → chunk-GQEKAQXE.js} +3 -3
- package/lib/{chunk-DZ4ZUAYH.js → chunk-JJE6NRHN.js} +2 -2
- package/lib/{chunk-NGVWVIBM.js → chunk-PNFQDYBK.js} +42 -8
- package/lib/chunk-PNFQDYBK.js.map +7 -0
- package/lib/{chunk-2LH6TD2U.js → chunk-R3UQQMSV.js} +3 -3
- package/lib/{chunk-BSAI3SW5.js → chunk-XAND4QBY.js} +3 -3
- package/lib/{chunk-ZQZSXCVR.js → chunk-YJRNFOHM.js} +34 -11
- package/lib/chunk-YJRNFOHM.js.map +7 -0
- package/lib/cli.js +4 -4
- package/lib/client.js +63 -1
- package/lib/client.js.map +2 -2
- package/lib/clients.js +3 -3
- package/lib/{host-v0.6.1.js → host-v0.6.3.js} +7 -7
- package/lib/host.js +7 -7
- package/lib/index.js +7 -7
- package/lib/manager.js +6 -6
- package/lib/router.js +2 -2
- package/lib/shim.js +3 -3
- package/package.json +1 -1
- package/lib/chunk-NGVWVIBM.js.map +0 -7
- package/lib/chunk-ZQZSXCVR.js.map +0 -7
- /package/lib/{chunk-VZPXRK7Q.js.map → chunk-BVH4K6WH.js.map} +0 -0
- /package/lib/{chunk-625KMEYS.js.map → chunk-GQEKAQXE.js.map} +0 -0
- /package/lib/{chunk-DZ4ZUAYH.js.map → chunk-JJE6NRHN.js.map} +0 -0
- /package/lib/{chunk-2LH6TD2U.js.map → chunk-R3UQQMSV.js.map} +0 -0
- /package/lib/{chunk-BSAI3SW5.js.map → chunk-XAND4QBY.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。版本号从 `0.1` 起以功能迭代为主,接口在 `1.0` 前可能变化。
|
|
4
4
|
|
|
5
|
+
## 0.6.3
|
|
6
|
+
|
|
7
|
+
- 普通预配置及自定义路由的编辑弹窗新增「默认思考深度」,支持平台默认及渠道声明的关闭 / 深度档位;按当前目标、指定账号和上下文容量核对选项,仅读取本机模型缓存,不发送供应商探测请求。
|
|
8
|
+
- 保存校验所选档位;会话手动选择及 API `reasoning_effort` 优先于路由默认,仅向支持所选档位的账号切换。暂缺目录时保留已有默认值,不静默降档。
|
|
9
|
+
- 路由默认思考深度随配置导入导出迁移,覆盖保存、重载、跨设备迁移及真实 DSH 请求的回归验证。
|
|
10
|
+
|
|
11
|
+
## 0.6.2
|
|
12
|
+
|
|
13
|
+
- 修复旧用户升级后缺少新预制路由:启用或热加载时自动补齐 Qwen3.8-Max、Qwen3.8-Flash 与 Hy4 Preview,更新后直接出现在路由列表与模型选择器,无需手动补齐或重启。
|
|
14
|
+
- 记录已处理的预配置;重复启用不重复写入,用户改名、隐藏、改规则及旧预设的删除选择保留。新增预设处理后再次删除,不会在下一次启动恢复。
|
|
15
|
+
- 预配置处理记录随配置迁移;合并保留两端记录。升级写入使用现有文件锁与原子保存,损坏配置不自动重置。
|
|
16
|
+
|
|
5
17
|
## 0.6.1
|
|
6
18
|
|
|
7
19
|
- 保留三家模型的默认 / 最大上下文和可选档位,原始模型、预制路由及动态免费模型默认最大,不再统一限制 200K;旧隐式默认自动迁移,显式自定义预算保留。
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
一个插件内置 WorkBuddy、Trae、Qoder 的认证、模型发现和聊天传输,提供三家的多账号池及集中路由。运行不依赖原来三个 DSH 插件;三家代码随安装包一起打包。基于 MIT 上游,固定版本见 `upstream-lock.json`,许可见 `THIRD_PARTY_NOTICES.md`。
|
|
8
8
|
|
|
9
|
-
版本:0.6.
|
|
9
|
+
版本:0.6.3。适配 DSH Desktop / Web 0.2.0-rc.2,Node.js ^22.19.0 或 >=24。
|
|
10
10
|
|
|
11
11
|
## 在 DSH 里管理
|
|
12
12
|
|
|
@@ -331,6 +331,8 @@ Free 自动免费路由排在首位,以下普通预配置按表中渠道顺序
|
|
|
331
331
|
|
|
332
332
|
路由内部 ID 是 DSH 查找路由所需的标识,由插件维护;用户在面板只配置路由名称。目标模型 ID 决定实际调用哪个模型。上表为预配置的稳定内部标识,新建路由自动生成独立标识。GLM-5.2 已移出预配置,原始渠道模型不受影响。
|
|
333
333
|
|
|
334
|
+
从 v0.6.2 起,升级后的首次启用或热加载自动补齐新引入的预配置,无需重启或手动点击。首次迁移补齐 Qwen3.8-Max / Flash 与 Hy4 Preview,已有同 ID 路由的名称、显隐和规则保持原样,旧预设中已移除的路由不会恢复。已处理的预设会记录在配置中,此后主动删除也不会在启动时恢复;需要恢复时可在「添加预配置」手动添加。记录随配置导入导出迁移。
|
|
335
|
+
|
|
334
336
|
## Free 动态免费模型(0.3.6)
|
|
335
337
|
|
|
336
338
|
预配置内置 free 管理组,名称「Free · 动态免费模型」,排在预配置与路由管理列表首位。按确切的渠道与模型 ID 自动创建各模型的免费路由,DSH 模型列表分别展示「Free · 模型名 · 渠道」,排在普通预配置前。同一渠道同一模型的多个免费账号归为一个路由,不按展示名称模糊合并版本,也不把不同模型混为一个池。原 free 内部标识仅为旧会话保留,默认不在选择器展示。
|
|
@@ -345,6 +347,10 @@ Free 不使用临期积分或 Token / 积分额度策略,避免将「消耗赠
|
|
|
345
347
|
|
|
346
348
|
## 统一路由推理模式
|
|
347
349
|
|
|
350
|
+
「路由规则 → 编辑路由 → 默认思考深度」可为普通预配置与自定义路由设置平台默认、关闭思考或具体档位。选项根据当前目标、指定账号及上下文容量,从本机目录实时核对;保存立即生效,DSH 会话的手动选择及 API 的 `reasoning_effort` 优先。没有声明可调档位时只使用平台默认,已有档位暂不可用时保留设置并显示提示,不自动降档。默认值随配置导入导出保留。
|
|
351
|
+
|
|
352
|
+

|
|
353
|
+
|
|
348
354
|
所有预配置与自定义路由保留各目标明确声明的全部档位,包括支持的 Off、Minimal、Low、Medium、High、XHigh、Max。不同渠道存在差异时使用并集,并按会话所选档位筛选实际账号 / 模型候选,不静默降级,也不因某个目标未声明档位而删掉其他目标的能力。WorkBuddy 国内 onlyReasoning 的模型仍遵守上游禁止 Off 的约束。平台默认与显式 Off 通过每次请求独立的本机 shim 头区分,头不发送到三家上游;实际请求仍使用各渠道本来的字段映射。
|
|
349
355
|
|
|
350
356
|
## 开发与验证
|
package/cordis.patch.yml
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
- insert:
|
|
2
|
-
- id: llm-multi-router-v2-0.6.
|
|
3
|
-
name: ./lib/host-v0.6.
|
|
2
|
+
- id: llm-multi-router-v2-0.6.3
|
|
3
|
+
name: ./lib/host-v0.6.3.js
|
package/lib/accounts.js
CHANGED
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
localAccountKey,
|
|
5
5
|
normalizeLocalAccountKey,
|
|
6
6
|
readPortableCredential
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-BVH4K6WH.js";
|
|
8
8
|
import "./chunk-OK2T2UAZ.js";
|
|
9
9
|
import "./chunk-TEZ2FMEO.js";
|
|
10
10
|
import "./chunk-S5KMFAQM.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-PNFQDYBK.js";
|
|
12
12
|
export {
|
|
13
13
|
discoverLocalAccounts,
|
|
14
14
|
importAccount,
|
package/lib/api-service.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ApiService
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-GQEKAQXE.js";
|
|
4
4
|
import "./chunk-4V52V5GO.js";
|
|
5
5
|
import "./chunk-DNQPZMPF.js";
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-JJE6NRHN.js";
|
|
7
|
+
import "./chunk-PNFQDYBK.js";
|
|
8
8
|
export {
|
|
9
9
|
ApiService
|
|
10
10
|
};
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
PROVIDERS,
|
|
14
14
|
writePrivateJson
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-PNFQDYBK.js";
|
|
16
16
|
|
|
17
17
|
// src/accounts.mjs
|
|
18
18
|
import { readFile } from "node:fs/promises";
|
|
@@ -178,4 +178,4 @@ export {
|
|
|
178
178
|
readPortableCredential,
|
|
179
179
|
importAccount
|
|
180
180
|
};
|
|
181
|
-
//# sourceMappingURL=chunk-
|
|
181
|
+
//# sourceMappingURL=chunk-BVH4K6WH.js.map
|
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
RouteError,
|
|
9
9
|
abortable
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-JJE6NRHN.js";
|
|
11
11
|
import {
|
|
12
12
|
REASONING_EFFORTS,
|
|
13
13
|
beijingDay,
|
|
14
14
|
writePrivateJson
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-PNFQDYBK.js";
|
|
16
16
|
|
|
17
17
|
// src/api-service.mjs
|
|
18
18
|
import { createServer } from "node:http";
|
|
@@ -329,4 +329,4 @@ async function collectCompletion(frames, model) {
|
|
|
329
329
|
export {
|
|
330
330
|
ApiService
|
|
331
331
|
};
|
|
332
|
-
//# sourceMappingURL=chunk-
|
|
332
|
+
//# sourceMappingURL=chunk-GQEKAQXE.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
isFreeModel,
|
|
3
3
|
reasoningModes,
|
|
4
4
|
writePrivateJson
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-PNFQDYBK.js";
|
|
6
6
|
|
|
7
7
|
// src/telemetry.mjs
|
|
8
8
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -567,4 +567,4 @@ export {
|
|
|
567
567
|
matchModel,
|
|
568
568
|
Router
|
|
569
569
|
};
|
|
570
|
-
//# sourceMappingURL=chunk-
|
|
570
|
+
//# sourceMappingURL=chunk-JJE6NRHN.js.map
|
|
@@ -88,6 +88,35 @@ var DEFAULT_ROUTES = {
|
|
|
88
88
|
},
|
|
89
89
|
...ROUTE_PRESETS
|
|
90
90
|
};
|
|
91
|
+
var LEGACY_ROUTE_PRESETS = [
|
|
92
|
+
"free",
|
|
93
|
+
"deepseek-v4.1-flash",
|
|
94
|
+
"deepseek-v4-pro",
|
|
95
|
+
"glm-5.3",
|
|
96
|
+
"glm-5.3-flash",
|
|
97
|
+
"kimi-k3",
|
|
98
|
+
"kimi-k2.8-preview",
|
|
99
|
+
"minimax-m2.7"
|
|
100
|
+
];
|
|
101
|
+
function upgradeRoutePresets(raw) {
|
|
102
|
+
const ids = Object.keys(ROUTE_PRESETS);
|
|
103
|
+
if (ids.every((id) => raw.seenRoutePresets?.includes(id))) return raw;
|
|
104
|
+
const routes = raw.routes ?? DEFAULT_ROUTES;
|
|
105
|
+
const seen = /* @__PURE__ */ new Set([
|
|
106
|
+
...LEGACY_ROUTE_PRESETS,
|
|
107
|
+
...raw.seenRoutePresets ?? [],
|
|
108
|
+
...Object.keys(routes).filter((id) => Object.hasOwn(ROUTE_PRESETS, id))
|
|
109
|
+
]);
|
|
110
|
+
const additions = ids.filter((id) => !seen.has(id));
|
|
111
|
+
return {
|
|
112
|
+
...raw,
|
|
113
|
+
...additions.length ? { routes: {
|
|
114
|
+
...routes,
|
|
115
|
+
...Object.fromEntries(additions.map((id) => [id, structuredClone(ROUTE_PRESETS[id])]))
|
|
116
|
+
} } : {},
|
|
117
|
+
seenRoutePresets: [.../* @__PURE__ */ new Set([...seen, ...ids])]
|
|
118
|
+
};
|
|
119
|
+
}
|
|
91
120
|
var object = (x) => x !== null && typeof x === "object" && !Array.isArray(x);
|
|
92
121
|
var nonempty = (x) => typeof x === "string" && x.trim().length > 0;
|
|
93
122
|
var positive = (x) => Number.isSafeInteger(x) && x > 0;
|
|
@@ -130,6 +159,7 @@ function validateConfig(raw, file = resolve("router.json")) {
|
|
|
130
159
|
if (route.maxTokens > route.contextWindow) throw new Error(`Route ${alias}: maxTokens exceeds contextWindow`);
|
|
131
160
|
if (route.supportsImages !== void 0 && typeof route.supportsImages !== "boolean") throw new Error(`Invalid supportsImages for ${alias}`);
|
|
132
161
|
if (route.visible !== void 0 && typeof route.visible !== "boolean") throw new Error(`Invalid visibility for ${alias}`);
|
|
162
|
+
if (route.reasoningEffort != null && !REASONING_EFFORTS.includes(route.reasoningEffort)) throw new Error(`Invalid reasoningEffort for ${alias}`);
|
|
133
163
|
if (route.name !== void 0 && (!nonempty(route.name) || route.name.length > 200)) throw new Error(`Invalid route name for ${alias}`);
|
|
134
164
|
if (route.freeOnly !== void 0 && typeof route.freeOnly !== "boolean") throw new Error(`Invalid freeOnly for ${alias}`);
|
|
135
165
|
if (route.freeModels !== void 0 && (!route.freeOnly || !object(route.freeModels) || Object.entries(route.freeModels).some(([id, p]) => !/^free_[a-f0-9]{24}$/.test(id) || !object(p) || Object.keys(p).some((k) => !["visible", "reasoningEffort", "contextWindow"].includes(k)) || p.visible !== void 0 && typeof p.visible !== "boolean" || p.contextWindow !== void 0 && p.contextWindow !== null && !positive(p.contextWindow) || p.reasoningEffort !== void 0 && p.reasoningEffort !== null && !REASONING_EFFORTS.includes(p.reasoningEffort)))) throw new Error("\u514D\u8D39\u6A21\u578B\u5C55\u793A\u6216\u63A8\u7406\u7B49\u7EA7\u8BBE\u7F6E\u65E0\u6548");
|
|
@@ -165,6 +195,7 @@ function validateConfig(raw, file = resolve("router.json")) {
|
|
|
165
195
|
if (raw.retryServerErrors !== void 0 && typeof raw.retryServerErrors !== "boolean") throw new Error("Invalid retryServerErrors");
|
|
166
196
|
if (raw.sidebarUsage !== void 0 && typeof raw.sidebarUsage !== "boolean") throw new Error("\u4FA7\u680F\u7528\u91CF\u5F00\u5173\u5FC5\u987B\u662F\u5E03\u5C14\u503C");
|
|
167
197
|
if (raw.ignoredLocalAccounts !== void 0 && (!Array.isArray(raw.ignoredLocalAccounts) || raw.ignoredLocalAccounts.some((k) => typeof k !== "string" || k.length > 1024))) throw new Error("Invalid ignoredLocalAccounts");
|
|
198
|
+
if (raw.seenRoutePresets !== void 0 && (!Array.isArray(raw.seenRoutePresets) || raw.seenRoutePresets.length > 500 || raw.seenRoutePresets.some((id) => typeof id !== "string" || !/^[a-zA-Z0-9_.-]{1,128}$/.test(id)))) throw new Error("Invalid seenRoutePresets");
|
|
168
199
|
if (raw.usageRetentionDays !== void 0 && (!positive(raw.usageRetentionDays) || raw.usageRetentionDays > 365)) throw new Error("Token \u660E\u7EC6\u4FDD\u7559\u5929\u6570\u5FC5\u987B\u4E3A 1\u2013365 \u7684\u6574\u6570");
|
|
169
200
|
const checkinSchedule = raw.checkinSchedule ?? { mode: "scheduled", time: "10:05" };
|
|
170
201
|
if (!object(checkinSchedule) || !["startup", "scheduled"].includes(checkinSchedule.mode) || !/^([01]\d|2[0-3]):[0-5]\d$/.test(checkinSchedule.time ?? "") || Object.keys(checkinSchedule).some((k) => !["mode", "time"].includes(k))) throw new Error("\u7B7E\u5230\u8BA1\u5212\u5FC5\u987B\u9009\u62E9\u542F\u52A8\u6216\u5B9A\u65F6\uFF0C\u5E76\u586B\u5199\u6709\u6548\u7684\u5317\u4EAC\u65F6\u95F4\uFF08HH:mm\uFF09");
|
|
@@ -183,24 +214,27 @@ function validateConfig(raw, file = resolve("router.json")) {
|
|
|
183
214
|
usageRetentionDays: raw.usageRetentionDays ?? 30
|
|
184
215
|
};
|
|
185
216
|
}
|
|
186
|
-
async function readConfig(file) {
|
|
187
|
-
return validateConfig(JSON.parse(await readFile(file, "utf8")), resolve(file));
|
|
188
|
-
}
|
|
189
217
|
async function ensureConfig(file) {
|
|
190
218
|
try {
|
|
191
|
-
|
|
219
|
+
const raw = JSON.parse(await readFile(file, "utf8")), config = validateConfig(raw, resolve(file));
|
|
220
|
+
if (upgradeRoutePresets(raw) === raw) return config;
|
|
192
221
|
} catch (error) {
|
|
193
222
|
if (error.code !== "ENOENT") throw error;
|
|
194
223
|
}
|
|
195
224
|
await mkdir(dirname(file), { recursive: true, mode: 448 });
|
|
196
225
|
return withFileLock(file, async () => {
|
|
226
|
+
let raw, created = false;
|
|
197
227
|
try {
|
|
198
|
-
|
|
228
|
+
raw = JSON.parse(await readFile(file, "utf8"));
|
|
199
229
|
} catch (error) {
|
|
200
230
|
if (error.code !== "ENOENT") throw error;
|
|
231
|
+
raw = { accounts: [], routes: ROUTE_PRESETS };
|
|
232
|
+
created = true;
|
|
201
233
|
}
|
|
202
|
-
|
|
203
|
-
|
|
234
|
+
validateConfig(raw, resolve(file));
|
|
235
|
+
const next = upgradeRoutePresets(raw), config = validateConfig(next, resolve(file));
|
|
236
|
+
if (created || next !== raw) await writePrivateJson(file, next);
|
|
237
|
+
return config;
|
|
204
238
|
}, { waitMs: 3e4 });
|
|
205
239
|
}
|
|
206
240
|
async function writePrivateJson(file, value) {
|
|
@@ -226,4 +260,4 @@ export {
|
|
|
226
260
|
ensureConfig,
|
|
227
261
|
writePrivateJson
|
|
228
262
|
};
|
|
229
|
-
//# sourceMappingURL=chunk-
|
|
263
|
+
//# sourceMappingURL=chunk-PNFQDYBK.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/reasoning.mjs", "../src/config.mjs"],
|
|
4
|
+
"sourcesContent": ["export const REASONING_EFFORTS = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];\n\n// Keep declared modes only. A fixed-thinking model without a declared set uses platform default.\nexport function reasoningModes(model, provider) {\n const r = model?.reasoning;\n if (!r || (r.supports !== true && !Array.isArray(r.supported))) return [];\n const declared = r.supportedEfforts ?? r.supported ?? [];\n const disable = r.canDisableThinking === true || declared.includes('off');\n const off = disable && !(provider === 'workbuddy' && r.onlyReasoning === true);\n return REASONING_EFFORTS.filter(e => e === 'off' ? off : declared.includes(e));\n}\n\nexport function routeReasoning(models) {\n const efforts = REASONING_EFFORTS.filter(e => models.some(({ model, provider }) => reasoningModes(model, provider).includes(e)));\n if (!efforts.length) return undefined;\n return { supports: true, supportedEfforts: efforts, canDisableThinking: efforts.includes('off'),\n defaultEffort: efforts.includes('high') ? 'high' : efforts[0] };\n}\n", "import { readFile, mkdir, rename, writeFile, chmod } from 'node:fs/promises';\nimport { dirname, resolve } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport { withFileLock } from '@deepseek-ai/dsh-atomic-write';\nimport { REASONING_EFFORTS } from './reasoning.mjs';\n\nexport const PROVIDERS = ['workbuddy', 'workbuddy-ai', 'trae', 'trae-global', 'qoder', 'qoder-global'];\nexport const PROVIDER_NAMES = { workbuddy: 'WorkBuddy', 'workbuddy-ai': 'WorkBuddy AI', trae: 'Trae CN',\n 'trae-global': 'Trae Global', qoder: 'Qoder CN', 'qoder-global': 'Qoder Global' };\nexport const FLASH_PRESET = {\n name: 'DeepSeek V4.1 Flash \u00B7 \u81EA\u52A8\u8DEF\u7531', contextMode: 'maximum', contextWindow: 200000, maxTokens: 32000, preferExpiringCredits: true, expiringWithinDays: 7,\n targets: ['workbuddy', 'trae', 'qoder'].map(provider => ({ provider, models: provider.startsWith('qoder')\n ? ['dfmodel'] : ['deepseek-v4.1-flash', 'DeepSeek-V4.1-Flash', 'DeepSeek-V4.1-Flash-Official'] })),\n};\n// IDs differ between providers; keep precise model/version bindings, never fuzzy-match variants.\nconst sharedPreset = (name, workbuddy, trae, qoder) => ({\n name: `${name} \u00B7 \u81EA\u52A8\u8DEF\u7531`, contextMode: 'maximum', contextWindow: 200000, maxTokens: 32000, preferExpiringCredits: true, expiringWithinDays: 7,\n targets: [['workbuddy', workbuddy], ['trae', trae], ['qoder', qoder]]\n .filter(([, models]) => models).map(([provider, models]) => ({ provider, models: Array.isArray(models) ? models : [models] })),\n});\nexport const ROUTE_PRESETS = {\n free: { name: 'Free \u00B7 \u52A8\u6001\u514D\u8D39\u6A21\u578B', freeOnly: true, visible: true, contextMode: 'maximum', contextWindow: 200000, maxTokens: 32000,\n strategy: 'failover', preferExpiringCredits: false, targets: PROVIDERS.map(provider => ({ provider })) },\n 'deepseek-v4.1-flash': FLASH_PRESET,\n 'deepseek-v4-pro': sharedPreset('DeepSeek V4 Pro', 'deepseek-v4-pro', ['DeepSeek-V4-Pro-Official', 'DeepSeek-V4-Pro'], 'dmodel'),\n 'glm-5.3': sharedPreset('GLM-5.3', 'glm-5.3', 'glm-5.3', 'gmodel'),\n 'glm-5.3-flash': sharedPreset('GLM-5.3-Flash', 'glm-5.3-flash', 'glm-5.3-flash', 'gfmodel'),\n 'kimi-k3': sharedPreset('Kimi-K3', 'kimi-k3-1', 'kimi-k3', 'kmodel_latest'),\n 'kimi-k2.8-preview': sharedPreset('Kimi-K2.8-Preview', 'kimi-k2.8-preview', 'kimi-k2.8-preview', 'kmodel'),\n 'minimax-m2.7': sharedPreset('MiniMax-M2.7', 'minimax-m2.7', 'minimax-m2.7', 'mmodel'),\n // WorkBuddy does not advertise these models. Only bind verified Trae/Qoder IDs.\n 'qwen3.8-max': sharedPreset('Qwen3.8-Max', null, 'qwen3.8-max', 'qmodel_38max'),\n 'qwen3.8-flash': sharedPreset('Qwen3.8-Flash', null, 'qwen3.8-flash', 'qfmodel'),\n 'hy4-preview': sharedPreset('Hy4 Preview', 'hy4-preview', null, null),\n};\nexport const DEFAULT_ROUTES = {\n free: ROUTE_PRESETS.free,\n 'ds4.1f': {\n name: 'DeepSeek V4.1 Flash \u00B7 Auto', contextMode: 'maximum', contextWindow: 200000, maxTokens: 32000, preferExpiringCredits: true, expiringWithinDays: 7,\n targets: PROVIDERS.map(provider => ({ provider })),\n },\n ...ROUTE_PRESETS,\n};\n// Before preset history existed, these were already shipped. Missing old IDs\n// represent user removals; only subsequently introduced presets are auto-added.\nconst LEGACY_ROUTE_PRESETS = ['free', 'deepseek-v4.1-flash', 'deepseek-v4-pro', 'glm-5.3',\n 'glm-5.3-flash', 'kimi-k3', 'kimi-k2.8-preview', 'minimax-m2.7'];\nexport function upgradeRoutePresets(raw) {\n const ids = Object.keys(ROUTE_PRESETS);\n if (ids.every(id => raw.seenRoutePresets?.includes(id))) return raw;\n const routes = raw.routes ?? DEFAULT_ROUTES;\n const seen = new Set([...LEGACY_ROUTE_PRESETS, ...(raw.seenRoutePresets ?? []),\n ...Object.keys(routes).filter(id => Object.hasOwn(ROUTE_PRESETS, id))]);\n const additions = ids.filter(id => !seen.has(id));\n return { ...raw, ...(additions.length ? { routes: { ...routes,\n ...Object.fromEntries(additions.map(id => [id, structuredClone(ROUTE_PRESETS[id])])) } } : {}),\n seenRoutePresets: [...new Set([...seen, ...ids])] };\n}\nconst object = x => x !== null && typeof x === 'object' && !Array.isArray(x);\nconst nonempty = x => typeof x === 'string' && x.trim().length > 0;\nconst positive = x => Number.isSafeInteger(x) && x > 0;\nexport const beijingDay = at => new Date(at).toLocaleDateString('en-CA', { timeZone: 'Asia/Shanghai' });\nexport function isFreeModel(model, now = Date.now()) {\n if (model.billing?.rateUnknown === true) return false;\n // A badge or a zero adapter cost is not an account-scoped zero billing rate.\n const rate = model.creditMultiplier ?? (/^x?(\\d+(?:\\.\\d+)?)(?:\\s+credits?)?$/i.exec(model.billing?.credits?.trim() ?? '')?.[1]);\n if (rate === undefined || !Number.isFinite(Number(rate)) || Number(rate) !== 0) return false;\n if (model.promotions?.length && !model.promotions.some(p => now >= p.start && now < p.end)) return false;\n return true;\n}\nexport function validateConfig(raw, file = resolve('router.json')) {\n if (!object(raw) || !Array.isArray(raw.accounts)) throw new Error('Config must contain an accounts array');\n const ids = new Set();\n const accounts = raw.accounts.map(account => {\n if (!object(account) || !/^[a-zA-Z0-9_-]{1,64}$/.test(account.id ?? '') || ids.has(account.id)) throw new Error('Account ids must be unique, 1\u201364 letters, digits, _ or -');\n ids.add(account.id);\n if (!PROVIDERS.includes(account.provider) || !nonempty(account.credentialFile)) throw new Error(`Invalid provider or credentialFile for ${account.id}`);\n if (account.enabled !== undefined && typeof account.enabled !== 'boolean') throw new Error(`Invalid enabled flag for ${account.id}`);\n if (account.autoCheckin !== undefined && (typeof account.autoCheckin !== 'boolean' || (account.autoCheckin && !['workbuddy', 'trae', 'qoder', 'qoder-global'].includes(account.provider)))) throw new Error(`Invalid autoCheckin for ${account.id}`);\n if (account.name !== undefined && (!nonempty(account.name) || account.name.length > 100)) throw new Error(`Invalid account name for ${account.id}`);\n if (account.identityFile !== undefined && !nonempty(account.identityFile)) throw new Error(`Invalid identityFile for ${account.id}`);\n return { ...account, credentialFile: resolve(dirname(file), account.credentialFile),\n ...(account.identityFile ? { identityFile: resolve(dirname(file), account.identityFile) } : {}) };\n });\n if (!object(raw.routes ?? DEFAULT_ROUTES)) throw new Error('Routes must be an object');\n const routes = Object.fromEntries(Object.entries(raw.routes ?? DEFAULT_ROUTES).map(([id, route]) => [id, { ...route,\n contextMode: route?.contextMode ?? (route?.contextWindow === 200000 ? 'maximum' : 'custom'),\n preferExpiringCredits: route?.preferExpiringCredits ?? !route?.freeOnly, expiringWithinDays: route?.expiringWithinDays ?? 7 }]));\n for (const [alias, route] of Object.entries(routes)) {\n if (!/^[a-zA-Z0-9_.-]{1,128}$/.test(alias) || !object(route) || !Array.isArray(route.targets) || !route.targets.length) throw new Error(`Invalid route ${alias}`);\n for (const key of ['contextWindow', 'maxTokens']) if (!positive(route[key])) throw new Error(`Route ${alias} needs a positive ${key}`);\n if (!['maximum', 'custom'].includes(route.contextMode)) throw new Error(`Invalid contextMode in ${alias}`);\n if (route.maxTokens > route.contextWindow) throw new Error(`Route ${alias}: maxTokens exceeds contextWindow`);\n if (route.supportsImages !== undefined && typeof route.supportsImages !== 'boolean') throw new Error(`Invalid supportsImages for ${alias}`);\n if (route.visible !== undefined && typeof route.visible !== 'boolean') throw new Error(`Invalid visibility for ${alias}`);\n if (route.reasoningEffort != null && !REASONING_EFFORTS.includes(route.reasoningEffort)) throw new Error(`Invalid reasoningEffort for ${alias}`);\n if (route.name !== undefined && (!nonempty(route.name) || route.name.length > 200)) throw new Error(`Invalid route name for ${alias}`);\n if (route.freeOnly !== undefined && typeof route.freeOnly !== 'boolean') throw new Error(`Invalid freeOnly for ${alias}`);\n if (route.freeModels !== undefined && (!route.freeOnly || !object(route.freeModels) || Object.entries(route.freeModels).some(([id, p]) =>\n !/^free_[a-f0-9]{24}$/.test(id) || !object(p) || Object.keys(p).some(k => !['visible', 'reasoningEffort', 'contextWindow'].includes(k))\n || (p.visible !== undefined && typeof p.visible !== 'boolean')\n || (p.contextWindow !== undefined && p.contextWindow !== null && !positive(p.contextWindow))\n || (p.reasoningEffort !== undefined && p.reasoningEffort !== null && !REASONING_EFFORTS.includes(p.reasoningEffort))))) throw new Error('\u514D\u8D39\u6A21\u578B\u5C55\u793A\u6216\u63A8\u7406\u7B49\u7EA7\u8BBE\u7F6E\u65E0\u6548');\n if (route.freeOnly && ((route.strategy && route.strategy !== 'failover') || route.preferExpiringCredits)) throw new Error('Free \u8DEF\u7531\u4EC5\u4F7F\u7528\u514D\u8D39\u6A21\u578B\u6545\u969C\u5207\u6362\uFF0C\u4E0D\u4F7F\u7528\u79EF\u5206\u6216\u989D\u5EA6\u8F6E\u6362');\n if (route.preferExpiringCredits !== undefined && typeof route.preferExpiringCredits !== 'boolean') throw new Error(`Invalid expiring credits flag in ${alias}`);\n if (route.expiringWithinDays !== undefined && (!positive(route.expiringWithinDays) || route.expiringWithinDays > 365)) throw new Error(`Invalid expiry horizon in ${alias}`);\n if (route.strategy !== undefined && !['failover', 'weighted', 'tokens', 'credits'].includes(route.strategy)) throw new Error(`Invalid strategy in ${alias}`);\n for (const target of route.targets) {\n if (!object(target)) throw new Error(`Invalid target in ${alias}`);\n if (target.weight !== undefined && (!positive(target.weight) || target.weight > 1000)) throw new Error(`Invalid target weight in ${alias}`);\n if (target.tokenBudget !== undefined && !positive(target.tokenBudget)) throw new Error(`Invalid token budget in ${alias}`);\n if (target.creditBudget !== undefined && (typeof target.creditBudget !== 'number' || !Number.isFinite(target.creditBudget) || target.creditBudget <= 0)) throw new Error(`Invalid credit budget in ${alias}`);\n if (route.strategy === 'tokens' && !positive(target.tokenBudget)) throw new Error(`Route ${alias} needs token budgets`);\n if (route.strategy === 'credits' && !(target.creditBudget > 0)) throw new Error(`Route ${alias} needs credit budgets`);\n if (!object(target) || !PROVIDERS.includes(target.provider) || (target.model !== undefined && !nonempty(target.model))) throw new Error(`Invalid target in ${alias}`);\n if (target.models !== undefined && (!Array.isArray(target.models) || !target.models.length || target.models.length > 20 || !target.models.every(nonempty))) throw new Error(`Invalid target models in ${alias}`);\n if (target.model !== undefined && target.models !== undefined) throw new Error(`Choose model or models in ${alias}`);\n if (target.account !== undefined && !accounts.some(a => a.id === target.account && a.provider === target.provider)) throw new Error(`Unknown target account in ${alias}`);\n if (!target.model && !target.models && alias !== 'ds4.1f' && !route.freeOnly) throw new Error(`Route ${alias} requires explicit target model ids`);\n }\n }\n const models = raw.models ?? {};\n if (!object(models)) throw new Error('Models must be an object');\n for (const [provider, preferences] of Object.entries(models)) {\n if (!PROVIDERS.includes(provider) || !object(preferences)) throw new Error('Invalid model provider');\n for (const [id, preference] of Object.entries(preferences)) {\n if (!nonempty(id) || id.length > 256 || !object(preference)\n || (preference.name !== undefined && (!nonempty(preference.name) || preference.name.length > 200))\n || (preference.visible !== undefined && typeof preference.visible !== 'boolean')\n || (preference.contextWindow !== undefined && preference.contextWindow !== null && !positive(preference.contextWindow))\n || (preference.supportsImages !== undefined && typeof preference.supportsImages !== 'boolean')\n || (preference.reasoningEffort !== undefined && preference.reasoningEffort !== null && !REASONING_EFFORTS.includes(preference.reasoningEffort))) throw new Error('Invalid model preference');\n }\n }\n const modelVisibility = raw.modelVisibility ?? {};\n if (!object(modelVisibility) || Object.entries(modelVisibility).some(([provider, visible]) => !PROVIDERS.includes(provider) || typeof visible !== 'boolean')) throw new Error('Invalid modelVisibility');\n for (const key of ['cooldownMs', 'requestTimeoutMs', 'catalogTtlMs']) if (raw[key] !== undefined && !positive(raw[key])) throw new Error(`Invalid ${key}`);\n if (raw.retryServerErrors !== undefined && typeof raw.retryServerErrors !== 'boolean') throw new Error('Invalid retryServerErrors');\n if (raw.sidebarUsage !== undefined && typeof raw.sidebarUsage !== 'boolean') throw new Error('\u4FA7\u680F\u7528\u91CF\u5F00\u5173\u5FC5\u987B\u662F\u5E03\u5C14\u503C');\n if (raw.ignoredLocalAccounts !== undefined && (!Array.isArray(raw.ignoredLocalAccounts) || raw.ignoredLocalAccounts.some(k => typeof k !== 'string' || k.length > 1024))) throw new Error('Invalid ignoredLocalAccounts');\n if (raw.seenRoutePresets !== undefined && (!Array.isArray(raw.seenRoutePresets) || raw.seenRoutePresets.length > 500\n || raw.seenRoutePresets.some(id => typeof id !== 'string' || !/^[a-zA-Z0-9_.-]{1,128}$/.test(id)))) throw new Error('Invalid seenRoutePresets');\n if (raw.usageRetentionDays !== undefined && (!positive(raw.usageRetentionDays) || raw.usageRetentionDays > 365)) throw new Error('Token \u660E\u7EC6\u4FDD\u7559\u5929\u6570\u5FC5\u987B\u4E3A 1\u2013365 \u7684\u6574\u6570');\n const checkinSchedule = raw.checkinSchedule ?? { mode: 'scheduled', time: '10:05' };\n if (!object(checkinSchedule) || !['startup', 'scheduled'].includes(checkinSchedule.mode)\n || !/^([01]\\d|2[0-3]):[0-5]\\d$/.test(checkinSchedule.time ?? '')\n || Object.keys(checkinSchedule).some(k => !['mode', 'time'].includes(k))) throw new Error('\u7B7E\u5230\u8BA1\u5212\u5FC5\u987B\u9009\u62E9\u542F\u52A8\u6216\u5B9A\u65F6\uFF0C\u5E76\u586B\u5199\u6709\u6548\u7684\u5317\u4EAC\u65F6\u95F4\uFF08HH:mm\uFF09');\n return { ...raw, accounts, routes, models, modelVisibility, cooldownMs: raw.cooldownMs ?? 60000,\n checkinSchedule: { ...checkinSchedule }, sidebarUsage: raw.sidebarUsage ?? true,\n requestTimeoutMs: raw.requestTimeoutMs ?? 300000, catalogTtlMs: raw.catalogTtlMs ?? 300000,\n retryServerErrors: raw.retryServerErrors ?? false, usageRetentionDays: raw.usageRetentionDays ?? 30 };\n}\nexport async function readConfig(file) {\n return validateConfig(JSON.parse(await readFile(file, 'utf8')), resolve(file));\n}\nexport async function ensureConfig(file) {\n try {\n const raw = JSON.parse(await readFile(file, 'utf8')), config = validateConfig(raw, resolve(file));\n if (upgradeRoutePresets(raw) === raw) return config;\n } catch (error) { if (error.code !== 'ENOENT') throw error; }\n await mkdir(dirname(file), { recursive: true, mode: 0o700 });\n return withFileLock(file, async () => {\n let raw, created = false;\n try { raw = JSON.parse(await readFile(file, 'utf8')); } catch (error) {\n if (error.code !== 'ENOENT') throw error;\n raw = { accounts: [], routes: ROUTE_PRESETS }; created = true;\n }\n validateConfig(raw, resolve(file));\n const next = upgradeRoutePresets(raw), config = validateConfig(next, resolve(file));\n if (created || next !== raw) await writePrivateJson(file, next);\n return config;\n }, { waitMs: 30000 });\n}\nexport async function writePrivateJson(file, value) {\n await mkdir(dirname(file), { recursive: true, mode: 0o700 });\n const temp = `${file}.${randomUUID()}.tmp`;\n await writeFile(temp, `${JSON.stringify(value, null, 2)}\\n`, { mode: 0o600, flag: 'wx' });\n await rename(temp, file);\n await chmod(file, 0o600);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -22,11 +22,11 @@ import {
|
|
|
22
22
|
RouteError,
|
|
23
23
|
abortable,
|
|
24
24
|
qoderContextModel
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-JJE6NRHN.js";
|
|
26
26
|
import {
|
|
27
27
|
beijingDay,
|
|
28
28
|
writePrivateJson
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-PNFQDYBK.js";
|
|
30
30
|
|
|
31
31
|
// src/clients.mjs
|
|
32
32
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
@@ -5418,4 +5418,4 @@ export {
|
|
|
5418
5418
|
refreshWorkBuddyCheckinCredential,
|
|
5419
5419
|
createWorkBuddyCheckin
|
|
5420
5420
|
};
|
|
5421
|
-
//# sourceMappingURL=chunk-
|
|
5421
|
+
//# sourceMappingURL=chunk-R3UQQMSV.js.map
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-DNQPZMPF.js";
|
|
5
5
|
import {
|
|
6
6
|
RouteError
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-JJE6NRHN.js";
|
|
8
8
|
import {
|
|
9
9
|
REASONING_EFFORTS
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PNFQDYBK.js";
|
|
11
11
|
|
|
12
12
|
// src/shim.mjs
|
|
13
13
|
import { createServer } from "node:http";
|
|
@@ -117,4 +117,4 @@ function createShim(router, { modelPrefix = "" } = {}) {
|
|
|
117
117
|
export {
|
|
118
118
|
createShim
|
|
119
119
|
};
|
|
120
|
-
//# sourceMappingURL=chunk-
|
|
120
|
+
//# sourceMappingURL=chunk-XAND4QBY.js.map
|
|
@@ -6,20 +6,20 @@ import {
|
|
|
6
6
|
refreshWorkBuddyCheckinCredential,
|
|
7
7
|
supportsCheckin,
|
|
8
8
|
workbuddyToken
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-R3UQQMSV.js";
|
|
10
10
|
import {
|
|
11
11
|
discoverLocalAccounts,
|
|
12
12
|
importAccount,
|
|
13
13
|
localAccountKey,
|
|
14
14
|
normalizeLocalAccountKey,
|
|
15
15
|
readPortableCredential
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-BVH4K6WH.js";
|
|
17
17
|
import {
|
|
18
18
|
modelWithCurrentPromotion
|
|
19
19
|
} from "./chunk-TEZ2FMEO.js";
|
|
20
20
|
import {
|
|
21
21
|
ApiService
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-GQEKAQXE.js";
|
|
23
23
|
import {
|
|
24
24
|
hostIsLoopback
|
|
25
25
|
} from "./chunk-DNQPZMPF.js";
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
contextInfo,
|
|
29
29
|
matchModel,
|
|
30
30
|
resolveContext
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-JJE6NRHN.js";
|
|
32
32
|
import {
|
|
33
33
|
PROVIDERS,
|
|
34
34
|
PROVIDER_NAMES,
|
|
@@ -38,13 +38,13 @@ import {
|
|
|
38
38
|
routeReasoning,
|
|
39
39
|
validateConfig,
|
|
40
40
|
writePrivateJson
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-PNFQDYBK.js";
|
|
42
42
|
|
|
43
43
|
// src/manager.mjs
|
|
44
44
|
import { createHash, randomBytes as randomBytes3, timingSafeEqual } from "node:crypto";
|
|
45
45
|
|
|
46
46
|
// package.json
|
|
47
|
-
var version = "0.6.
|
|
47
|
+
var version = "0.6.3";
|
|
48
48
|
|
|
49
49
|
// src/manager.mjs
|
|
50
50
|
import { readFile as readFile4, mkdir as mkdir2, mkdtemp as mkdtemp2, rm as rm3 } from "node:fs/promises";
|
|
@@ -106,14 +106,14 @@ var derive = promisify(scrypt);
|
|
|
106
106
|
var FORMAT = "dsh-multi-router";
|
|
107
107
|
var MAX_BYTES = 512 * 1024;
|
|
108
108
|
var pick = (value, keys) => Object.fromEntries(keys.filter((k) => Object.hasOwn(value ?? {}, k)).map((k) => [k, value[k]]));
|
|
109
|
-
var options = ["cooldownMs", "requestTimeoutMs", "catalogTtlMs", "retryServerErrors", "modelVisibility", "usageRetentionDays", "checkinSchedule", "sidebarUsage"];
|
|
109
|
+
var options = ["cooldownMs", "requestTimeoutMs", "catalogTtlMs", "retryServerErrors", "modelVisibility", "usageRetentionDays", "checkinSchedule", "sidebarUsage", "seenRoutePresets"];
|
|
110
110
|
function settings(config) {
|
|
111
111
|
return {
|
|
112
112
|
...pick(config, options),
|
|
113
113
|
models: Object.fromEntries(Object.entries(config.models ?? {}).map(([p, rows]) => [p, Object.fromEntries(Object.entries(rows).map(([id, pref]) => [id, pick(pref, ["name", "visible", "contextWindow", "supportsImages", "reasoningEffort"])]))])),
|
|
114
114
|
accounts: config.accounts.map((a) => pick(a, ["id", "provider", "name", "enabled", "autoCheckin"])),
|
|
115
115
|
routes: Object.fromEntries(Object.entries(config.routes).map(([id, r]) => [id, {
|
|
116
|
-
...pick(r, ["name", "visible", "strategy", "contextMode", "contextWindow", "maxTokens", "preferExpiringCredits", "expiringWithinDays", "freeOnly", "freeModels"]),
|
|
116
|
+
...pick(r, ["name", "visible", "strategy", "contextMode", "contextWindow", "maxTokens", "reasoningEffort", "preferExpiringCredits", "expiringWithinDays", "freeOnly", "freeModels"]),
|
|
117
117
|
targets: r.targets.map((t) => pick(t, ["provider", "account", "model", "models", "weight", "tokenBudget", "creditBudget"]))
|
|
118
118
|
}]))
|
|
119
119
|
};
|
|
@@ -231,6 +231,7 @@ async function prepareMigration(manager, raw, portable, mode) {
|
|
|
231
231
|
const next = mode === "replace" ? { ...portable.config, accounts: imported } : {
|
|
232
232
|
...raw,
|
|
233
233
|
...pick(portable.config, options),
|
|
234
|
+
...raw.seenRoutePresets || portable.config.seenRoutePresets ? { seenRoutePresets: [.../* @__PURE__ */ new Set([...raw.seenRoutePresets ?? [], ...portable.config.seenRoutePresets ?? []])] } : {},
|
|
234
235
|
accounts: [...raw.accounts.map((a) => imported.find((b) => b.id === a.id) ?? a), ...imported.filter((a) => !raw.accounts.some((b) => b.id === a.id))],
|
|
235
236
|
routes: { ...raw.routes, ...portable.config.routes },
|
|
236
237
|
models: Object.fromEntries([.../* @__PURE__ */ new Set([...Object.keys(raw.models ?? {}), ...Object.keys(portable.config.models)])].map((p) => [p, { ...raw.models?.[p], ...portable.config.models[p] }]))
|
|
@@ -1375,8 +1376,8 @@ var Manager = class {
|
|
|
1375
1376
|
modelVisible(provider, id) {
|
|
1376
1377
|
return this.config.models[provider]?.[id]?.visible ?? this.config.modelVisibility[provider] ?? false;
|
|
1377
1378
|
}
|
|
1378
|
-
routeModels() {
|
|
1379
|
-
return Object.entries(
|
|
1379
|
+
routeModels(routes = this.config.routes) {
|
|
1380
|
+
return Object.entries(routes).sort(([, a], [, b]) => Number(!!b.freeOnly) - Number(!!a.freeOnly)).map(([id, row]) => {
|
|
1380
1381
|
const effectiveTargets = row.freeOnly ? this.freeRoutes(id, row).flatMap((r) => r.targets) : row.targets;
|
|
1381
1382
|
const sources = effectiveTargets.flatMap((target) => this.config.accounts.filter((a) => a.enabled !== false && a.provider === target.provider && (!target.account || target.account === a.id)).flatMap((a) => {
|
|
1382
1383
|
const catalog = this.catalogs.get(a.id)?.models ?? [];
|
|
@@ -1488,6 +1489,17 @@ var Manager = class {
|
|
|
1488
1489
|
}
|
|
1489
1490
|
async action(input) {
|
|
1490
1491
|
if (!input || typeof input !== "object" || Array.isArray(input)) bad("\u8BF7\u6C42\u683C\u5F0F\u65E0\u6548");
|
|
1492
|
+
if (input.action === "route.preview") {
|
|
1493
|
+
if (input.route?.freeOnly) bad("\u514D\u8D39\u6A21\u578B\u8BF7\u9010\u9879\u8BBE\u7F6E\u63A8\u7406\u7B49\u7EA7");
|
|
1494
|
+
let config;
|
|
1495
|
+
try {
|
|
1496
|
+
config = validateConfig({ ...this.raw, routes: { [input.id || "preview"]: input.route } }, this.file);
|
|
1497
|
+
} catch {
|
|
1498
|
+
bad("\u8BF7\u5148\u9009\u62E9\u6709\u6548\u7684\u76EE\u6807\u6A21\u578B\u4E0E\u4E0A\u4E0B\u6587\u5BB9\u91CF");
|
|
1499
|
+
}
|
|
1500
|
+
const { reasoning, contextKnown } = this.routeModels(config.routes)[0];
|
|
1501
|
+
return { routePreview: { reasoning, contextKnown } };
|
|
1502
|
+
}
|
|
1491
1503
|
if (input.action === "model.test") {
|
|
1492
1504
|
const model = this.providerModels(input.provider).find((m) => m.id === input.id);
|
|
1493
1505
|
if (!model) bad("\u8BF7\u5148\u5237\u65B0\u5E76\u9009\u62E9\u5DF2\u53D1\u73B0\u7684\u6A21\u578B");
|
|
@@ -1888,6 +1900,7 @@ var Manager = class {
|
|
|
1888
1900
|
if (["tokens", "credits"].includes(strategy)) await this.telemetry.advance(input.id, this.router.candidates(input.id), JSON.stringify({ strategy, targets: route.targets }));
|
|
1889
1901
|
} else if (input.action === "route.remove") {
|
|
1890
1902
|
if (!Object.hasOwn(raw.routes, input.id)) bad("\u8DEF\u7531\u4E0D\u5B58\u5728");
|
|
1903
|
+
if (Object.hasOwn(ROUTE_PRESETS, input.id)) raw.seenRoutePresets = [.../* @__PURE__ */ new Set([...raw.seenRoutePresets ?? [], input.id])];
|
|
1891
1904
|
delete raw.routes[input.id];
|
|
1892
1905
|
} else if (input.action === "preset.add") {
|
|
1893
1906
|
const id = input.id ?? "deepseek-v4.1-flash";
|
|
@@ -1909,6 +1922,16 @@ var Manager = class {
|
|
|
1909
1922
|
} catch (error) {
|
|
1910
1923
|
bad(error.message);
|
|
1911
1924
|
}
|
|
1925
|
+
if (input.action === "route.save" && input.route.reasoningEffort != null) {
|
|
1926
|
+
const previous = this.config.routes[input.previousId], route = config.routes[input.id];
|
|
1927
|
+
const bindings = (r) => JSON.stringify(r.targets.map((t) => ({
|
|
1928
|
+
provider: t.provider,
|
|
1929
|
+
account: t.account,
|
|
1930
|
+
models: t.models ?? (t.model ? [t.model] : [])
|
|
1931
|
+
})));
|
|
1932
|
+
const unchanged = previous?.reasoningEffort === route.reasoningEffort && bindings(previous) === bindings(route) && previous.contextMode === route.contextMode && (route.contextMode === "maximum" || previous.contextWindow === route.contextWindow);
|
|
1933
|
+
if (!unchanged && !this.routeModels({ [input.id]: route })[0].reasoning?.supportedEfforts.includes(route.reasoningEffort)) bad("\u76EE\u6807\u6A21\u578B\u5728\u5F53\u524D\u4E0A\u4E0B\u6587\u5BB9\u91CF\u4E0B\u4E0D\u652F\u6301\u6240\u9009\u601D\u8003\u6DF1\u5EA6\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9");
|
|
1934
|
+
}
|
|
1912
1935
|
await writePrivateJson(this.file, raw);
|
|
1913
1936
|
staging = void 0;
|
|
1914
1937
|
this.raw = raw;
|
|
@@ -2025,4 +2048,4 @@ export {
|
|
|
2025
2048
|
Manager,
|
|
2026
2049
|
managementHandler
|
|
2027
2050
|
};
|
|
2028
|
-
//# sourceMappingURL=chunk-
|
|
2051
|
+
//# sourceMappingURL=chunk-YJRNFOHM.js.map
|