mslxdff 0.1.199 → 0.1.203
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/README.md +3 -3
- package/bin/mslxdff.js +1 -1
- package/package.json +38 -38
- package/plugins/README.md +14 -14
- package/plugins/prefer-model.mjs.example +14 -14
- package/src/anthropic/count-tokens.js +61 -61
- package/src/anthropic/request-body.js +126 -126
- package/src/anthropic/shared.js +18 -18
- package/src/anthropic/sse-aggregate.js +56 -56
- package/src/anthropic/translate.js +287 -287
- package/src/anthropic/web-search.js +361 -361
- package/src/api-kind.js +31 -31
- package/src/autostart.js +288 -288
- package/src/bench/probe.js +1 -1
- package/src/bench/runner.js +1 -1
- package/src/bench/via-probe.js +1 -1
- package/src/bench/via.js +144 -144
- package/src/bench/workbuddy-bench.js +1 -1
- package/src/chat/config.js +11 -11
- package/src/chat/cooling.js +81 -81
- package/src/chat/direct.js +58 -58
- package/src/chat/index.js +6 -6
- package/src/chat/spinner.js +38 -38
- package/src/chat/sse.js +69 -69
- package/src/chat/stats.js +247 -247
- package/src/chat/store.js +48 -48
- package/src/chat/tool-handlers.js +67 -67
- package/src/chat/tools.js +1 -1
- package/src/chat/upstream.js +59 -59
- package/src/chat-pipeline/auto-race.js +158 -158
- package/src/chat-pipeline/empty-turn.js +147 -147
- package/src/chat-pipeline/engine.js +17 -17
- package/src/chat-pipeline/serial-trial.js +283 -283
- package/src/chat-pipeline/terminal-verdict.js +147 -147
- package/src/chooser.js +54 -54
- package/src/claude-desktop/apply.js +101 -101
- package/src/claude-desktop/context1m.js +38 -38
- package/src/claude-desktop/doctor.js +146 -146
- package/src/claude-desktop/slots.js +152 -152
- package/src/cli/bootstrap.js +1 -1
- package/src/cli/commands/claude-desktop.js +284 -284
- package/src/cli/commands/daemon.js +231 -231
- package/src/cli/commands/model/list-live.js +22 -22
- package/src/cli/commands/model/list-providers.js +76 -76
- package/src/cli/commands/model/list-render.js +77 -77
- package/src/cli/commands/model/list-sort.js +52 -52
- package/src/cli/commands/model/list-tty.js +76 -76
- package/src/cli/commands/model/list.js +166 -166
- package/src/cli/commands/model/live-models.js +24 -24
- package/src/cli/commands/model/stats.js +43 -43
- package/src/cli/commands/model/status.js +47 -47
- package/src/cli/commands/model.js +51 -51
- package/src/cli/commands/provider/add.js +108 -108
- package/src/cli/commands/provider/allowlist.js +99 -99
- package/src/cli/commands/provider/cline-free.js +99 -99
- package/src/cli/commands/provider/cline-login.js +218 -218
- package/src/cli/commands/provider/cline-quota.js +65 -65
- package/src/cli/commands/provider/codearts-login.js +45 -45
- package/src/cli/commands/provider/config.js +119 -119
- package/src/cli/commands/provider/globalqwenwork-login.js +126 -126
- package/src/cli/commands/provider/keys-guard.js +50 -50
- package/src/cli/commands/provider/keys.js +161 -161
- package/src/cli/commands/provider/qoder-checkin.js +81 -81
- package/src/cli/commands/provider/qoder-login.js +102 -102
- package/src/cli/commands/provider/raccoon-login.js +180 -180
- package/src/cli/commands/provider/raccoon-password.js +162 -162
- package/src/cli/commands/provider/raccoon-quota.js +109 -109
- package/src/cli/commands/provider/traework-checkin.js +144 -144
- package/src/cli/commands/provider/traework-login.js +164 -164
- package/src/cli/commands/provider/workbuddy-login.js +153 -153
- package/src/cli/commands/provider/zcode-login.js +77 -77
- package/src/cli/commands/provider/zcode-quota.js +55 -55
- package/src/cli/commands/provider.js +1 -1
- package/src/cli/commands/stats.js +149 -149
- package/src/cli/commands/system.js +261 -261
- package/src/cli/commands/timezone.js +47 -47
- package/src/cli/commands/use-group.js +60 -60
- package/src/cli/commands/workbuddy.js +189 -189
- package/src/cli/format.js +141 -141
- package/src/cli/group-helpers.js +70 -70
- package/src/cli/help.js +80 -80
- package/src/cli/index.js +70 -70
- package/src/cli/interactive.js +121 -121
- package/src/cli/join-core.js +99 -99
- package/src/cli/join-wizard.js +175 -175
- package/src/cli/policy.js +136 -136
- package/src/cli/provider-row.js +126 -126
- package/src/cli/util.js +24 -24
- package/src/compat.js +53 -53
- package/src/events.js +38 -38
- package/src/free-lane.js +131 -131
- package/src/free-watcher.js +63 -63
- package/src/groups.js +262 -262
- package/src/logs.js +195 -195
- package/src/metrics.js +62 -62
- package/src/model-capabilities/context-lookup.js +65 -65
- package/src/model-capabilities/merge.js +142 -142
- package/src/model-trace.js +187 -187
- package/src/models.js +1 -1
- package/src/opencode-identity.js +72 -72
- package/src/peers.js +254 -251
- package/src/plugins.js +107 -107
- package/src/providers/base.js +164 -164
- package/src/providers/classify.js +22 -22
- package/src/providers/cline/allowlist-sync.js +93 -93
- package/src/providers/cline/free-catalog.js +71 -71
- package/src/providers/cline/headers.js +37 -37
- package/src/providers/cline/index.js +130 -130
- package/src/providers/cline/models.js +150 -150
- package/src/providers/cline/usage.js +274 -274
- package/src/providers/codearts/auth-pool.js +148 -148
- package/src/providers/codearts/concurrency.js +34 -34
- package/src/providers/codearts/const.js +65 -65
- package/src/providers/codearts/dpop.js +95 -95
- package/src/providers/codearts/index.js +175 -175
- package/src/providers/codearts/login.js +214 -214
- package/src/providers/codearts/models.js +182 -182
- package/src/providers/codearts/sign.js +96 -96
- package/src/providers/codearts/sse.js +204 -204
- package/src/providers/codearts/stream.js +209 -209
- package/src/providers/codearts/sts.js +124 -124
- package/src/providers/codearts.js +1 -1
- package/src/providers/dispatcher.js +146 -146
- package/src/providers/generic.js +156 -156
- package/src/providers/globalqwenwork/account-store.js +141 -141
- package/src/providers/globalqwenwork/constants.js +73 -73
- package/src/providers/globalqwenwork/crypto.js +2 -2
- package/src/providers/globalqwenwork/http.js +2 -2
- package/src/providers/globalqwenwork/index.js +331 -331
- package/src/providers/globalqwenwork/payload.js +147 -147
- package/src/providers/globalqwenwork/rsa.js +2 -2
- package/src/providers/globalqwenwork/sse.js +2 -2
- package/src/providers/globalqwenwork/stream.js +2 -2
- package/src/providers/globalqwenwork.js +1 -1
- package/src/providers/globalworkbuddy/account-store.js +198 -198
- package/src/providers/globalworkbuddy/auth.js +97 -97
- package/src/providers/globalworkbuddy/catalog.js +138 -138
- package/src/providers/globalworkbuddy/constants.js +73 -73
- package/src/providers/globalworkbuddy/device-auth.js +120 -120
- package/src/providers/globalworkbuddy/errors.js +98 -98
- package/src/providers/globalworkbuddy/headers.js +89 -89
- package/src/providers/globalworkbuddy/models.js +96 -96
- package/src/providers/globalworkbuddy/payload.js +80 -80
- package/src/providers/index.js +5 -5
- package/src/providers/model-id.js +172 -172
- package/src/providers/opencode.js +19 -19
- package/src/providers/openrouter.js +31 -31
- package/src/providers/qoder/account-store.js +106 -106
- package/src/providers/qoder/aggregate.js +60 -60
- package/src/providers/qoder/baseprompt.json +591 -591
- package/src/providers/qoder/checkin.js +160 -160
- package/src/providers/qoder/constants.js +44 -44
- package/src/providers/qoder/encode.js +41 -41
- package/src/providers/qoder/fingerprint.js +38 -38
- package/src/providers/qoder/models.js +77 -77
- package/src/providers/qoder/oauth.js +84 -84
- package/src/providers/qoder/payload.js +162 -162
- package/src/providers/qoder/request.js +27 -27
- package/src/providers/qoder/session.js +134 -134
- package/src/providers/qoder/sticky.js +38 -38
- package/src/providers/qoder/stream.js +116 -116
- package/src/providers/qoder.js +1 -1
- package/src/providers/raccoon/account-store.js +216 -216
- package/src/providers/raccoon/auth.js +67 -67
- package/src/providers/raccoon/chat.js +228 -228
- package/src/providers/raccoon/const.js +180 -165
- package/src/providers/raccoon/credits.js +185 -175
- package/src/providers/raccoon/crypto.js +43 -0
- package/src/providers/raccoon/envelope.js +31 -31
- package/src/providers/raccoon/headers.js +45 -45
- package/src/providers/raccoon/index.js +216 -216
- package/src/providers/raccoon/login.js +279 -279
- package/src/providers/raccoon/models.js +160 -160
- package/src/providers/raccoon/password-login.js +102 -87
- package/src/providers/raccoon/qr-codewords.js +115 -115
- package/src/providers/raccoon/qr.js +236 -236
- package/src/providers/raccoon/sse.js +135 -135
- package/src/providers/responses-channel.js +120 -120
- package/src/providers/share-keys.js +53 -53
- package/src/providers/traework/account-store.js +234 -234
- package/src/providers/traework/chat.js +217 -217
- package/src/providers/traework/checkin.js +77 -77
- package/src/providers/traework/constants.js +41 -41
- package/src/providers/traework/errors.js +52 -52
- package/src/providers/traework/headers.js +79 -79
- package/src/providers/traework/index.js +132 -132
- package/src/providers/traework/market-identity.js +116 -116
- package/src/providers/traework/models.js +98 -98
- package/src/providers/traework/payload.js +86 -86
- package/src/providers/traework/sse.js +184 -184
- package/src/providers/traework/token.js +52 -52
- package/src/providers/traework.js +2 -2
- package/src/providers/workbuddy/account-store.js +186 -186
- package/src/providers/workbuddy/auth.js +158 -158
- package/src/providers/workbuddy/balance.js +86 -86
- package/src/providers/workbuddy/cat-travel.js +125 -125
- package/src/providers/workbuddy/checkin.js +75 -75
- package/src/providers/workbuddy/desktop-info.js +78 -78
- package/src/providers/workbuddy/growth-api.js +67 -67
- package/src/providers/workbuddy/growth-plans.js +63 -63
- package/src/providers/workbuddy/growth.js +181 -181
- package/src/providers/workbuddy/index.js +217 -217
- package/src/providers/workbuddy/models.js +126 -126
- package/src/providers/workbuddy/payload.js +141 -141
- package/src/providers/workbuddy/rotation-log.js +83 -83
- package/src/providers/workbuddy/sanitize-tools.js +61 -61
- package/src/providers/workbuddy/sdk-chat.js +26 -26
- package/src/providers/workbuddy-balance.js +78 -78
- package/src/providers/zcode/account-store.js +129 -129
- package/src/providers/zcode/auth.js +28 -28
- package/src/providers/zcode/chat.js +179 -179
- package/src/providers/zcode/const.js +54 -54
- package/src/providers/zcode/context-shape.js +162 -162
- package/src/providers/zcode/headers.js +93 -93
- package/src/providers/zcode/index.js +124 -124
- package/src/providers/zcode/models.js +65 -65
- package/src/providers/zcode/oauth.js +120 -120
- package/src/providers/zcode/quota.js +176 -176
- package/src/providers/zcode/sse.js +196 -196
- package/src/readline-compat.js +25 -25
- package/src/responses/translate.js +311 -311
- package/src/routes/chat/broadband-handler.js +72 -72
- package/src/routes/chat/empty-turn-report.js +31 -31
- package/src/routes/chat/exhausted-handler.js +87 -87
- package/src/routes/chat/hedge-handler.js +130 -130
- package/src/routes/chat/index.js +1 -1
- package/src/routes/chat/local-handler.js +63 -63
- package/src/routes/chat/peer-handler.js +81 -81
- package/src/routes/chat.js +3 -3
- package/src/routes/fallback.js +88 -88
- package/src/routes/groups-relay.js +214 -214
- package/src/routes/groups.js +122 -122
- package/src/routes/helpers.js +83 -83
- package/src/routes/index.js +147 -147
- package/src/routes/messages-route.js +365 -365
- package/src/routes/peers.js +23 -1
- package/src/routes/relay-queue.js +181 -181
- package/src/routes/relay.js +60 -60
- package/src/routes/responses-route.js +213 -213
- package/src/routes/stream-body.js +84 -84
- package/src/routes/stream-hold.js +337 -337
- package/src/routes/stream-scan.js +366 -366
- package/src/routes.js +3 -3
- package/src/runtime/auto-update.js +113 -113
- package/src/runtime/bootstrap.js +8 -0
- package/src/runtime/broadband-stream.js +79 -79
- package/src/runtime/broadband.js +103 -103
- package/src/runtime/group-sync.js +81 -81
- package/src/runtime/keep-warm.js +120 -0
- package/src/runtime/lifecycle-forensics.js +116 -116
- package/src/runtime/lifecycle-log.js +87 -87
- package/src/runtime/log-stamp.js +73 -73
- package/src/runtime/proc-info.js +137 -137
- package/src/runtime/qoder-checkin.js +93 -93
- package/src/runtime/raccoon-checkin.js +126 -126
- package/src/runtime/server-lifecycle.js +189 -189
- package/src/runtime/traework-checkin.js +118 -118
- package/src/runtime/workbuddy-checkin.js +120 -120
- package/src/runtime/workbuddy-growth.js +133 -133
- package/src/server.js +7 -0
- package/src/state/facade.js +58 -58
- package/src/state/memory.js +162 -162
- package/src/state/merge.js +25 -25
- package/src/state/migrations/cline-unify.js +94 -94
- package/src/state/migrations.js +33 -33
- package/src/state/persist.js +42 -42
- package/src/state/provider-config.js +142 -142
- package/src/state/schemas/group.js +31 -31
- package/src/state/schemas/model.js +94 -94
- package/src/state/schemas/peer.js +31 -31
- package/src/state/schemas/port.js +10 -10
- package/src/state/schemas/provider.js +202 -202
- package/src/state/schemas/timezone.js +70 -70
- package/src/state/schemas/token.js +48 -48
- package/src/state/schemas/use-group.js +102 -102
- package/src/state/store.js +176 -176
- package/src/state.js +1 -1
- package/src/sync-claude-desktop.js +234 -234
- package/src/sync-claude.js +152 -152
- package/src/sync-codex.js +116 -116
- package/src/sync-workbuddy.js +158 -158
- package/src/talk-full-redact.js +129 -129
- package/src/talk-full.js +131 -131
- package/src/talk-log.js +257 -257
- package/src/text-tokens.js +52 -52
- package/src/thinking-effort.js +67 -67
- package/src/time.js +106 -106
- package/src/timeline.js +26 -26
- package/src/transport/index.js +1 -1
- package/src/upstream-engine/index.js +74 -72
- package/src/upstream-engine/mode.js +15 -15
- package/src/upstream-engine/sdk/attempt.js +221 -221
- package/src/upstream-engine/sdk/chat.js +28 -28
- package/src/upstream-engine/sdk/convert.js +192 -192
- package/src/upstream-engine/sdk/diagnose.js +62 -62
- package/src/upstream-engine/sdk/dispatch.js +55 -55
- package/src/upstream-engine/sdk/responses.js +176 -176
- package/src/upstream-engine/sdk/sse.js +166 -166
- package/src/upstream-responses.js +305 -305
- package/src/upstream.js +53 -1
- package/src/usage/record.js +106 -106
- package/src/usage/report.js +195 -195
- package/src/v6pool/claim.js +157 -157
- package/src/v6pool/config.js +65 -65
- package/src/v6pool/detect.js +130 -130
- package/src/v6pool/index.js +152 -152
- package/src/v6pool/prefix.js +140 -140
- package/src/v6pool/probe.js +40 -40
- package/src/v6pool/report.js +104 -104
- package/src/v6pool/rotate.js +263 -239
- package/src/warp-pool/config.js +74 -74
- package/src/warp-pool/health.js +106 -106
- package/src/warp-pool/identity.js +141 -141
- package/src/warp-pool/index.js +358 -358
- package/src/warp-pool/keys.js +29 -29
- package/src/warp-pool/nodes.js +95 -95
- package/src/warp-pool/ports.js +160 -160
- package/src/warp-pool/register.js +113 -113
- package/src/warp-pool/report.js +232 -232
- package/src/warp-pool/revive.js +168 -168
- package/src/warp-pool/rotate.js +214 -214
- package/src/warp-pool/strategy.js +43 -43
- package/src/warp-pool/verdict.js +69 -69
- package/src/warp-pool/wireproxy.js +162 -162
- package/docs/cli_help_mini.md +0 -146
- package/src/providers/AGENTS.md +0 -49
- package/src/routes/AGENTS.md +0 -37
|
@@ -1,173 +1,173 @@
|
|
|
1
|
-
// 模型 ID 前缀解析:`<provider>/<rawId>`。默认供应商(opencode)保持裸 id(向后兼容),
|
|
2
|
-
// 其它供应商必须带前缀,请求按前缀路由到对应上游通道。
|
|
3
|
-
//
|
|
4
|
-
// WorkBuddy 别名系统:
|
|
5
|
-
// WorkBuddy 不支持模型 ID 中的 /,写入 models.json 时替换为 -
|
|
6
|
-
// mslxdff 在收到请求时通过固定映射表还原为 / 格式
|
|
7
|
-
// 映射表持久化在 ~/.config/mslxdff/model-aliases.json
|
|
8
|
-
|
|
9
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
10
|
-
import { dirname, join } from "node:path";
|
|
11
|
-
import os from "node:os";
|
|
12
|
-
|
|
13
|
-
export const DEFAULT_PROVIDER = "opencode";
|
|
14
|
-
|
|
15
|
-
const ALIASES = { oc: "opencode", opencode: "opencode", clinebot: "cline", "cline-bot": "cline" };
|
|
16
|
-
|
|
17
|
-
// WorkBuddy 别名映射(alias → canonical):cline-z-ai-glm-5.3-flash → cline/z-ai/glm-5.3-flash
|
|
18
|
-
const _modelAliases = new Map();
|
|
19
|
-
|
|
20
|
-
function aliasFile() {
|
|
21
|
-
const env = process.env.MSLXDFF_ALIASES_FILE;
|
|
22
|
-
if (typeof env === "string" && env.trim()) return env.trim();
|
|
23
|
-
return join(os.homedir(), ".config", "mslxdff", "model-aliases.json");
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function loadModelAliases(file) {
|
|
27
|
-
const fp = file || aliasFile();
|
|
28
|
-
try {
|
|
29
|
-
const raw = JSON.parse(readFileSync(fp, "utf8"));
|
|
30
|
-
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
31
|
-
for (const [k, v] of Object.entries(raw)) {
|
|
32
|
-
if (typeof v === "string" && v) _modelAliases.set(String(k), v);
|
|
33
|
-
}
|
|
34
|
-
_aliasLoaded = true;
|
|
35
|
-
}
|
|
36
|
-
} catch {}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function registerModelAlias(alias, canonical) {
|
|
40
|
-
const a = String(alias || "").trim();
|
|
41
|
-
const c = String(canonical || "").trim();
|
|
42
|
-
if (!a || !c || a === c) return;
|
|
43
|
-
_modelAliases.set(a, c);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function persistModelAliases(file) {
|
|
47
|
-
const fp = file || aliasFile();
|
|
48
|
-
try {
|
|
49
|
-
mkdirSync(dirname(fp), { recursive: true });
|
|
50
|
-
const obj = Object.fromEntries(_modelAliases);
|
|
51
|
-
writeFileSync(fp, JSON.stringify(obj, null, 2), "utf8");
|
|
52
|
-
} catch {}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/** 别名文件路径(单一真相,供只读消费方复用,别再各自拼一遍)。 */
|
|
56
|
-
export function modelAliasFile() {
|
|
57
|
-
return aliasFile();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** 当前已装载的 alias 快照(只读;不触发重读,判"会不会被覆盖"用)。 */
|
|
61
|
-
export function snapshotModelAliases() {
|
|
62
|
-
return Object.fromEntries(_modelAliases);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
let _aliasLoaded = false;
|
|
66
|
-
export function getModelAlias(id) {
|
|
67
|
-
const key = String(id || "").trim();
|
|
68
|
-
let hit = _modelAliases.get(key);
|
|
69
|
-
if (hit) return hit;
|
|
70
|
-
// 未命中时尝试加载(支持 daemon 运行期间由 -setto 进程写入的新 alias)
|
|
71
|
-
try { loadModelAliases(); } catch {}
|
|
72
|
-
return _modelAliases.get(key) || null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// 反向查询:canonical id → alias(如 cline/z-ai/glm-5.3-flash → cline-z-ai-glm-5.3-flash)
|
|
76
|
-
export function getAliasForModel(canonicalId) {
|
|
77
|
-
const c = String(canonicalId || "").trim();
|
|
78
|
-
if (!_aliasLoaded) { try { loadModelAliases(); } catch {} }
|
|
79
|
-
for (const [alias, target] of _modelAliases) {
|
|
80
|
-
if (target === c) return alias;
|
|
81
|
-
}
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function normalizeProviderId(p) {
|
|
86
|
-
const id = String(p || "").trim();
|
|
87
|
-
return ALIASES[id] || id;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// 把(可能带前缀的)模型 id 拆成 { provider, raw, prefixed }
|
|
91
|
-
// - 无前缀(含默认供应商裸 id)→ provider = DEFAULT_PROVIDER
|
|
92
|
-
// - 前缀是已知供应商 → 对应路由;开头的 `oc/` 视为 opencode 别名
|
|
93
|
-
export function splitModelId(id, knownProviders = []) {
|
|
94
|
-
const s = String(id || "");
|
|
95
|
-
if (!s) return { provider: DEFAULT_PROVIDER, raw: s, prefixed: false };
|
|
96
|
-
const idx = s.indexOf("/");
|
|
97
|
-
if (idx > 0) {
|
|
98
|
-
const head = normalizeProviderId(s.slice(0, idx));
|
|
99
|
-
const known = new Set([DEFAULT_PROVIDER, ...knownProviders]);
|
|
100
|
-
if (known.has(head)) {
|
|
101
|
-
return { provider: head, raw: s.slice(idx + 1), prefixed: true };
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return { provider: DEFAULT_PROVIDER, raw: s, prefixed: false };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// 生成对外暴露的模型 id:默认供应商裸 id(向后兼容),其它供应商带前缀
|
|
108
|
-
export function joinModelId(provider, raw, { force = false } = {}) {
|
|
109
|
-
provider = normalizeProviderId(provider || "");
|
|
110
|
-
raw = String(raw || "");
|
|
111
|
-
if (provider === DEFAULT_PROVIDER && !force) return raw;
|
|
112
|
-
return `${provider}/${raw}`;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// 观测用全称:始终带前缀(opencode 也带),用于 modelStats / calls.log 聚合主键
|
|
116
|
-
export function toFullId(provider, raw) {
|
|
117
|
-
provider = normalizeProviderId(provider || "");
|
|
118
|
-
raw = String(raw || "").trim();
|
|
119
|
-
if (!raw) return "";
|
|
120
|
-
if (!provider || provider === DEFAULT_PROVIDER) return `${DEFAULT_PROVIDER}/${raw}`;
|
|
121
|
-
return `${provider}/${raw}`;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// 归一任意输入为全称:裸 id -> opencode/xxx,已带前缀保持不变(大小写保留,provider 归一)
|
|
125
|
-
// 优先查 WorkBuddy 别名表(固定映射),命中直接还原为 / 格式
|
|
126
|
-
export function normalizeFullId(id, knownProviders = []) {
|
|
127
|
-
const s = String(id || "").trim();
|
|
128
|
-
if (!s) return "";
|
|
129
|
-
// 1. 查别名表(cline-z-ai-glm-5.3-flash → cline/z-ai/glm-5.3-flash)
|
|
130
|
-
const aliased = getModelAlias(s);
|
|
131
|
-
if (aliased) return aliased;
|
|
132
|
-
// 2. 已含 /,走原有逻辑
|
|
133
|
-
const idx = s.indexOf("/");
|
|
134
|
-
if (idx > 0) {
|
|
135
|
-
const head = normalizeProviderId(s.slice(0, idx));
|
|
136
|
-
if (knownProviders.length) {
|
|
137
|
-
const known = new Set([DEFAULT_PROVIDER, ...knownProviders.map(normalizeProviderId)]);
|
|
138
|
-
if (known.has(head)) return `${head}/${s.slice(idx + 1)}`;
|
|
139
|
-
return `${DEFAULT_PROVIDER}/${s}`;
|
|
140
|
-
}
|
|
141
|
-
return `${head}/${s.slice(idx + 1)}`;
|
|
142
|
-
}
|
|
143
|
-
return `${DEFAULT_PROVIDER}/${s}`;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const BUILTIN_PROVIDERS = new Set([DEFAULT_PROVIDER, "openrouter"]);
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* 过滤 provider 已不存在的 picks 孤儿(纯函数,零 IO,可单测)。
|
|
150
|
-
* - 含 `/` 前缀:head(归一+小写)∉ 已知集合 → stale(如 amddev/*)。
|
|
151
|
-
* - Bare id:∉ 上游 liveIds ∪ allowlist 展开 → stale(如 laguna-s-2.1-free)。
|
|
152
|
-
* - provider 存在但未启用(如 deepseek 缺 baseUrl)→ 保留,不可用由 [error] 表达。
|
|
153
|
-
* - 未知一律保留(默认放行不误删显示);dash 别名经 resolveAlias 还原后判定;
|
|
154
|
-
* 上游 liveIds 为空时 bare 一律保留(无法判定则放行)。
|
|
155
|
-
* 数据不动,只决定进不进 `-models` 交互列表 — 见 .scratch/models-stale-picks/SPEC.md。
|
|
156
|
-
*/
|
|
157
|
-
export function filterStalePicks(pickedIds, { knownProviders = [], liveIds = [], allowedIds = [], resolveAlias = getModelAlias } = {}) {
|
|
158
|
-
const known = new Set([...BUILTIN_PROVIDERS, ...(knownProviders || []).map((p) => normalizeProviderId(p).toLowerCase())]);
|
|
159
|
-
const live = new Set((liveIds || []).map((id) => String(id).toLowerCase()));
|
|
160
|
-
const allowed = new Set((allowedIds || []).map((id) => String(id).toLowerCase()));
|
|
161
|
-
return (pickedIds || []).filter((pick) => {
|
|
162
|
-
const raw = String(pick || "").trim();
|
|
163
|
-
if (!raw) return false;
|
|
164
|
-
let id = raw;
|
|
165
|
-
try { id = resolveAlias(raw) || raw; } catch { id = raw; }
|
|
166
|
-
const slash = String(id).indexOf("/");
|
|
167
|
-
if (slash > 0) return known.has(normalizeProviderId(id.slice(0, slash)).toLowerCase());
|
|
168
|
-
// 上游列表为空(刷新与缓存双失败的极端情况)时无法判定 bare 生死 → 保留(默认放行)
|
|
169
|
-
if (live.size === 0) return true;
|
|
170
|
-
const low = String(id).toLowerCase();
|
|
171
|
-
return live.has(low) || allowed.has(low);
|
|
172
|
-
});
|
|
1
|
+
// 模型 ID 前缀解析:`<provider>/<rawId>`。默认供应商(opencode)保持裸 id(向后兼容),
|
|
2
|
+
// 其它供应商必须带前缀,请求按前缀路由到对应上游通道。
|
|
3
|
+
//
|
|
4
|
+
// WorkBuddy 别名系统:
|
|
5
|
+
// WorkBuddy 不支持模型 ID 中的 /,写入 models.json 时替换为 -
|
|
6
|
+
// mslxdff 在收到请求时通过固定映射表还原为 / 格式
|
|
7
|
+
// 映射表持久化在 ~/.config/mslxdff/model-aliases.json
|
|
8
|
+
|
|
9
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
10
|
+
import { dirname, join } from "node:path";
|
|
11
|
+
import os from "node:os";
|
|
12
|
+
|
|
13
|
+
export const DEFAULT_PROVIDER = "opencode";
|
|
14
|
+
|
|
15
|
+
const ALIASES = { oc: "opencode", opencode: "opencode", clinebot: "cline", "cline-bot": "cline" };
|
|
16
|
+
|
|
17
|
+
// WorkBuddy 别名映射(alias → canonical):cline-z-ai-glm-5.3-flash → cline/z-ai/glm-5.3-flash
|
|
18
|
+
const _modelAliases = new Map();
|
|
19
|
+
|
|
20
|
+
function aliasFile() {
|
|
21
|
+
const env = process.env.MSLXDFF_ALIASES_FILE;
|
|
22
|
+
if (typeof env === "string" && env.trim()) return env.trim();
|
|
23
|
+
return join(os.homedir(), ".config", "mslxdff", "model-aliases.json");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function loadModelAliases(file) {
|
|
27
|
+
const fp = file || aliasFile();
|
|
28
|
+
try {
|
|
29
|
+
const raw = JSON.parse(readFileSync(fp, "utf8"));
|
|
30
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
31
|
+
for (const [k, v] of Object.entries(raw)) {
|
|
32
|
+
if (typeof v === "string" && v) _modelAliases.set(String(k), v);
|
|
33
|
+
}
|
|
34
|
+
_aliasLoaded = true;
|
|
35
|
+
}
|
|
36
|
+
} catch {}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function registerModelAlias(alias, canonical) {
|
|
40
|
+
const a = String(alias || "").trim();
|
|
41
|
+
const c = String(canonical || "").trim();
|
|
42
|
+
if (!a || !c || a === c) return;
|
|
43
|
+
_modelAliases.set(a, c);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function persistModelAliases(file) {
|
|
47
|
+
const fp = file || aliasFile();
|
|
48
|
+
try {
|
|
49
|
+
mkdirSync(dirname(fp), { recursive: true });
|
|
50
|
+
const obj = Object.fromEntries(_modelAliases);
|
|
51
|
+
writeFileSync(fp, JSON.stringify(obj, null, 2), "utf8");
|
|
52
|
+
} catch {}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** 别名文件路径(单一真相,供只读消费方复用,别再各自拼一遍)。 */
|
|
56
|
+
export function modelAliasFile() {
|
|
57
|
+
return aliasFile();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** 当前已装载的 alias 快照(只读;不触发重读,判"会不会被覆盖"用)。 */
|
|
61
|
+
export function snapshotModelAliases() {
|
|
62
|
+
return Object.fromEntries(_modelAliases);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let _aliasLoaded = false;
|
|
66
|
+
export function getModelAlias(id) {
|
|
67
|
+
const key = String(id || "").trim();
|
|
68
|
+
let hit = _modelAliases.get(key);
|
|
69
|
+
if (hit) return hit;
|
|
70
|
+
// 未命中时尝试加载(支持 daemon 运行期间由 -setto 进程写入的新 alias)
|
|
71
|
+
try { loadModelAliases(); } catch {}
|
|
72
|
+
return _modelAliases.get(key) || null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 反向查询:canonical id → alias(如 cline/z-ai/glm-5.3-flash → cline-z-ai-glm-5.3-flash)
|
|
76
|
+
export function getAliasForModel(canonicalId) {
|
|
77
|
+
const c = String(canonicalId || "").trim();
|
|
78
|
+
if (!_aliasLoaded) { try { loadModelAliases(); } catch {} }
|
|
79
|
+
for (const [alias, target] of _modelAliases) {
|
|
80
|
+
if (target === c) return alias;
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function normalizeProviderId(p) {
|
|
86
|
+
const id = String(p || "").trim();
|
|
87
|
+
return ALIASES[id] || id;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 把(可能带前缀的)模型 id 拆成 { provider, raw, prefixed }
|
|
91
|
+
// - 无前缀(含默认供应商裸 id)→ provider = DEFAULT_PROVIDER
|
|
92
|
+
// - 前缀是已知供应商 → 对应路由;开头的 `oc/` 视为 opencode 别名
|
|
93
|
+
export function splitModelId(id, knownProviders = []) {
|
|
94
|
+
const s = String(id || "");
|
|
95
|
+
if (!s) return { provider: DEFAULT_PROVIDER, raw: s, prefixed: false };
|
|
96
|
+
const idx = s.indexOf("/");
|
|
97
|
+
if (idx > 0) {
|
|
98
|
+
const head = normalizeProviderId(s.slice(0, idx));
|
|
99
|
+
const known = new Set([DEFAULT_PROVIDER, ...knownProviders]);
|
|
100
|
+
if (known.has(head)) {
|
|
101
|
+
return { provider: head, raw: s.slice(idx + 1), prefixed: true };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return { provider: DEFAULT_PROVIDER, raw: s, prefixed: false };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 生成对外暴露的模型 id:默认供应商裸 id(向后兼容),其它供应商带前缀
|
|
108
|
+
export function joinModelId(provider, raw, { force = false } = {}) {
|
|
109
|
+
provider = normalizeProviderId(provider || "");
|
|
110
|
+
raw = String(raw || "");
|
|
111
|
+
if (provider === DEFAULT_PROVIDER && !force) return raw;
|
|
112
|
+
return `${provider}/${raw}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 观测用全称:始终带前缀(opencode 也带),用于 modelStats / calls.log 聚合主键
|
|
116
|
+
export function toFullId(provider, raw) {
|
|
117
|
+
provider = normalizeProviderId(provider || "");
|
|
118
|
+
raw = String(raw || "").trim();
|
|
119
|
+
if (!raw) return "";
|
|
120
|
+
if (!provider || provider === DEFAULT_PROVIDER) return `${DEFAULT_PROVIDER}/${raw}`;
|
|
121
|
+
return `${provider}/${raw}`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// 归一任意输入为全称:裸 id -> opencode/xxx,已带前缀保持不变(大小写保留,provider 归一)
|
|
125
|
+
// 优先查 WorkBuddy 别名表(固定映射),命中直接还原为 / 格式
|
|
126
|
+
export function normalizeFullId(id, knownProviders = []) {
|
|
127
|
+
const s = String(id || "").trim();
|
|
128
|
+
if (!s) return "";
|
|
129
|
+
// 1. 查别名表(cline-z-ai-glm-5.3-flash → cline/z-ai/glm-5.3-flash)
|
|
130
|
+
const aliased = getModelAlias(s);
|
|
131
|
+
if (aliased) return aliased;
|
|
132
|
+
// 2. 已含 /,走原有逻辑
|
|
133
|
+
const idx = s.indexOf("/");
|
|
134
|
+
if (idx > 0) {
|
|
135
|
+
const head = normalizeProviderId(s.slice(0, idx));
|
|
136
|
+
if (knownProviders.length) {
|
|
137
|
+
const known = new Set([DEFAULT_PROVIDER, ...knownProviders.map(normalizeProviderId)]);
|
|
138
|
+
if (known.has(head)) return `${head}/${s.slice(idx + 1)}`;
|
|
139
|
+
return `${DEFAULT_PROVIDER}/${s}`;
|
|
140
|
+
}
|
|
141
|
+
return `${head}/${s.slice(idx + 1)}`;
|
|
142
|
+
}
|
|
143
|
+
return `${DEFAULT_PROVIDER}/${s}`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const BUILTIN_PROVIDERS = new Set([DEFAULT_PROVIDER, "openrouter"]);
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 过滤 provider 已不存在的 picks 孤儿(纯函数,零 IO,可单测)。
|
|
150
|
+
* - 含 `/` 前缀:head(归一+小写)∉ 已知集合 → stale(如 amddev/*)。
|
|
151
|
+
* - Bare id:∉ 上游 liveIds ∪ allowlist 展开 → stale(如 laguna-s-2.1-free)。
|
|
152
|
+
* - provider 存在但未启用(如 deepseek 缺 baseUrl)→ 保留,不可用由 [error] 表达。
|
|
153
|
+
* - 未知一律保留(默认放行不误删显示);dash 别名经 resolveAlias 还原后判定;
|
|
154
|
+
* 上游 liveIds 为空时 bare 一律保留(无法判定则放行)。
|
|
155
|
+
* 数据不动,只决定进不进 `-models` 交互列表 — 见 .scratch/models-stale-picks/SPEC.md。
|
|
156
|
+
*/
|
|
157
|
+
export function filterStalePicks(pickedIds, { knownProviders = [], liveIds = [], allowedIds = [], resolveAlias = getModelAlias } = {}) {
|
|
158
|
+
const known = new Set([...BUILTIN_PROVIDERS, ...(knownProviders || []).map((p) => normalizeProviderId(p).toLowerCase())]);
|
|
159
|
+
const live = new Set((liveIds || []).map((id) => String(id).toLowerCase()));
|
|
160
|
+
const allowed = new Set((allowedIds || []).map((id) => String(id).toLowerCase()));
|
|
161
|
+
return (pickedIds || []).filter((pick) => {
|
|
162
|
+
const raw = String(pick || "").trim();
|
|
163
|
+
if (!raw) return false;
|
|
164
|
+
let id = raw;
|
|
165
|
+
try { id = resolveAlias(raw) || raw; } catch { id = raw; }
|
|
166
|
+
const slash = String(id).indexOf("/");
|
|
167
|
+
if (slash > 0) return known.has(normalizeProviderId(id.slice(0, slash)).toLowerCase());
|
|
168
|
+
// 上游列表为空(刷新与缓存双失败的极端情况)时无法判定 bare 生死 → 保留(默认放行)
|
|
169
|
+
if (live.size === 0) return true;
|
|
170
|
+
const low = String(id).toLowerCase();
|
|
171
|
+
return live.has(low) || allowed.has(low);
|
|
172
|
+
});
|
|
173
173
|
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { createUpstreamClient } from "../upstream.js";
|
|
2
|
-
import { joinModelId } from "./model-id.js";
|
|
3
|
-
|
|
4
|
-
// opencode Provider:复用现有 createUpstreamClient 的全部能力(头/重试/匿名免费通道/keep-alive 预热),
|
|
5
|
-
// 模型 id 保持裸 id(向后兼容)。
|
|
6
|
-
export function createOpenCodeProvider({ upstream, modelsService, baseUrl, authToken, hooks } = {}) {
|
|
7
|
-
const client = upstream ?? createUpstreamClient({ baseUrl, authToken, hooks });
|
|
8
|
-
return {
|
|
9
|
-
id: "opencode",
|
|
10
|
-
upstream: client,
|
|
11
|
-
chat: (body, opts) => client.chat(body, opts),
|
|
12
|
-
preheat: (args) => client.preheat(args),
|
|
13
|
-
close: () => client.close(),
|
|
14
|
-
async listModels() {
|
|
15
|
-
const data = await modelsService?.get?.();
|
|
16
|
-
const list = data?.data ?? [];
|
|
17
|
-
return list.map((m) => ({ ...m, id: joinModelId("opencode", m.id) }));
|
|
18
|
-
},
|
|
19
|
-
};
|
|
1
|
+
import { createUpstreamClient } from "../upstream.js";
|
|
2
|
+
import { joinModelId } from "./model-id.js";
|
|
3
|
+
|
|
4
|
+
// opencode Provider:复用现有 createUpstreamClient 的全部能力(头/重试/匿名免费通道/keep-alive 预热),
|
|
5
|
+
// 模型 id 保持裸 id(向后兼容)。
|
|
6
|
+
export function createOpenCodeProvider({ upstream, modelsService, baseUrl, authToken, hooks } = {}) {
|
|
7
|
+
const client = upstream ?? createUpstreamClient({ baseUrl, authToken, hooks });
|
|
8
|
+
return {
|
|
9
|
+
id: "opencode",
|
|
10
|
+
upstream: client,
|
|
11
|
+
chat: (body, opts) => client.chat(body, opts),
|
|
12
|
+
preheat: (args) => client.preheat(args),
|
|
13
|
+
close: () => client.close(),
|
|
14
|
+
async listModels() {
|
|
15
|
+
const data = await modelsService?.get?.();
|
|
16
|
+
const list = data?.data ?? [];
|
|
17
|
+
return list.map((m) => ({ ...m, id: joinModelId("opencode", m.id) }));
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
20
|
}
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import { createGenericProvider } from "./generic.js";
|
|
2
|
-
|
|
3
|
-
const DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
|
|
4
|
-
|
|
5
|
-
export function createOpenRouterProvider({
|
|
6
|
-
apiKeys,
|
|
7
|
-
apiKey,
|
|
8
|
-
baseUrl = process.env.MSLXDFF_OPENROUTER_BASE_URL || DEFAULT_BASE_URL,
|
|
9
|
-
fetchImpl,
|
|
10
|
-
headers,
|
|
11
|
-
noAgent = false,
|
|
12
|
-
...rest
|
|
13
|
-
} = {}) {
|
|
14
|
-
return createGenericProvider({
|
|
15
|
-
id: "openrouter",
|
|
16
|
-
baseUrl,
|
|
17
|
-
apiKeys,
|
|
18
|
-
apiKey,
|
|
19
|
-
modelsPath: "/models",
|
|
20
|
-
chatPath: "/chat/completions",
|
|
21
|
-
headers: {
|
|
22
|
-
"HTTP-Referer": process.env.MSLXDFF_OPENROUTER_REFERER || "https://github.com/mslxdff",
|
|
23
|
-
"X-Title": process.env.MSLXDFF_OPENROUTER_TITLE || "mslxdff",
|
|
24
|
-
...(headers || {}),
|
|
25
|
-
},
|
|
26
|
-
mapModel: (raw) => raw.filter((m) => Number(m.pricing?.prompt || 0) === 0 && Number(m.pricing?.completion || 0) === 0),
|
|
27
|
-
fetchImpl,
|
|
28
|
-
noAgent,
|
|
29
|
-
...rest,
|
|
30
|
-
});
|
|
31
|
-
}
|
|
1
|
+
import { createGenericProvider } from "./generic.js";
|
|
2
|
+
|
|
3
|
+
const DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
|
|
4
|
+
|
|
5
|
+
export function createOpenRouterProvider({
|
|
6
|
+
apiKeys,
|
|
7
|
+
apiKey,
|
|
8
|
+
baseUrl = process.env.MSLXDFF_OPENROUTER_BASE_URL || DEFAULT_BASE_URL,
|
|
9
|
+
fetchImpl,
|
|
10
|
+
headers,
|
|
11
|
+
noAgent = false,
|
|
12
|
+
...rest
|
|
13
|
+
} = {}) {
|
|
14
|
+
return createGenericProvider({
|
|
15
|
+
id: "openrouter",
|
|
16
|
+
baseUrl,
|
|
17
|
+
apiKeys,
|
|
18
|
+
apiKey,
|
|
19
|
+
modelsPath: "/models",
|
|
20
|
+
chatPath: "/chat/completions",
|
|
21
|
+
headers: {
|
|
22
|
+
"HTTP-Referer": process.env.MSLXDFF_OPENROUTER_REFERER || "https://github.com/mslxdff",
|
|
23
|
+
"X-Title": process.env.MSLXDFF_OPENROUTER_TITLE || "mslxdff",
|
|
24
|
+
...(headers || {}),
|
|
25
|
+
},
|
|
26
|
+
mapModel: (raw) => raw.filter((m) => Number(m.pricing?.prompt || 0) === 0 && Number(m.pricing?.completion || 0) === 0),
|
|
27
|
+
fetchImpl,
|
|
28
|
+
noAgent,
|
|
29
|
+
...rest,
|
|
30
|
+
});
|
|
31
|
+
}
|