mslxdff 0.1.232 → 0.1.234

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.
Files changed (114) hide show
  1. package/bin/mslxdff.js +3 -3
  2. package/docs/cli_help_mini.md +148 -0
  3. package/package.json +1 -1
  4. package/src/auto.js +264 -254
  5. package/src/bench/cline-bench.js +42 -42
  6. package/src/bench/probe.js +70 -70
  7. package/src/bench/report.js +162 -162
  8. package/src/bench/runner.js +77 -77
  9. package/src/bench/via-probe.js +124 -124
  10. package/src/bench/via-routes.js +87 -87
  11. package/src/bench/workbuddy-bench.js +54 -54
  12. package/src/chat/engine.js +160 -160
  13. package/src/chat/gateway.js +163 -163
  14. package/src/chat/orchestrator.js +234 -234
  15. package/src/chat/prompt.js +70 -70
  16. package/src/chat/repl.js +88 -88
  17. package/src/chat/terminal.js +135 -135
  18. package/src/chat/tools.js +306 -306
  19. package/src/chat-pipeline/index.js +155 -145
  20. package/src/chat-pipeline/policy.js +84 -84
  21. package/src/cli/commands/group.js +266 -266
  22. package/src/cli/commands/model/picks.js +50 -50
  23. package/src/cli/commands/provider/bench-via.js +247 -247
  24. package/src/cli/commands/provider/bench.js +141 -141
  25. package/src/cli/commands/provider/index.js +139 -139
  26. package/src/cli/commands/provider/models.js +149 -149
  27. package/src/cli/commands/provider/qwenwork-login.js +119 -119
  28. package/src/cli/commands/provider/raccoon-quota.js +156 -156
  29. package/src/cli/commands/sync.js +310 -310
  30. package/src/cli/status.js +279 -279
  31. package/src/daemon.js +246 -246
  32. package/src/model-capabilities/enrich.js +86 -86
  33. package/src/model-capabilities/index.js +183 -183
  34. package/src/model-capabilities/parse.js +70 -70
  35. package/src/model-trace.js +10 -2
  36. package/src/models.js +293 -226
  37. package/src/peers.js +345 -345
  38. package/src/providers/AGENTS.md +49 -0
  39. package/src/providers/agentrouter.js +238 -238
  40. package/src/providers/base.js +164 -164
  41. package/src/providers/cline/auth.js +228 -228
  42. package/src/providers/cline/chat.js +307 -307
  43. package/src/providers/cline.js +2 -2
  44. package/src/providers/codearts/chat.js +207 -207
  45. package/src/providers/dispatcher.js +147 -147
  46. package/src/providers/globalqwenwork/cosy.js +123 -123
  47. package/src/providers/globalqwenwork/crypto.js +218 -218
  48. package/src/providers/globalqwenwork/http.js +20 -20
  49. package/src/providers/globalqwenwork/rsa.js +54 -54
  50. package/src/providers/globalqwenwork/sse.js +268 -268
  51. package/src/providers/globalqwenwork/stream.js +130 -130
  52. package/src/providers/globalqwenwork/upstream.js +122 -122
  53. package/src/providers/keyring.js +60 -60
  54. package/src/providers/qoder/account-store.js +18 -0
  55. package/src/providers/qoder/chat.js +292 -203
  56. package/src/providers/qoder/checkin.js +25 -12
  57. package/src/providers/qoder/index.js +311 -249
  58. package/src/providers/qoder/models.js +64 -2
  59. package/src/providers/qoder/oauth.js +42 -1
  60. package/src/providers/qoder/payload.js +116 -80
  61. package/src/providers/qoder/request.js +7 -2
  62. package/src/providers/qoder/session.js +26 -10
  63. package/src/providers/qoder/sse.js +233 -145
  64. package/src/providers/qoder/sticky.js +5 -2
  65. package/src/providers/qoder/wire-messages.js +242 -0
  66. package/src/providers/qwenwork/account-store.js +133 -133
  67. package/src/providers/qwenwork/constants.js +67 -67
  68. package/src/providers/qwenwork/cosy.js +120 -120
  69. package/src/providers/qwenwork/crypto.js +218 -218
  70. package/src/providers/qwenwork/http.js +20 -20
  71. package/src/providers/qwenwork/index.js +337 -337
  72. package/src/providers/qwenwork/payload.js +144 -144
  73. package/src/providers/qwenwork/rsa.js +54 -54
  74. package/src/providers/qwenwork/sse.js +268 -268
  75. package/src/providers/qwenwork/stream.js +130 -130
  76. package/src/providers/qwenwork/upstream.js +120 -120
  77. package/src/providers/qwenwork.js +1 -1
  78. package/src/providers/raccoon/chat.js +1 -1
  79. package/src/providers/raccoon/const.js +219 -202
  80. package/src/providers/raccoon/credits.js +285 -285
  81. package/src/providers/raccoon/index.js +51 -6
  82. package/src/providers/raccoon/models.js +68 -17
  83. package/src/providers/raccoon/sticky.js +46 -0
  84. package/src/providers/registry.js +89 -89
  85. package/src/providers/workbuddy/chat.js +298 -298
  86. package/src/providers/workbuddy/reshape.js +152 -152
  87. package/src/providers/workbuddy.js +2 -2
  88. package/src/reasoning.js +32 -32
  89. package/src/routes/AGENTS.md +37 -0
  90. package/src/routes/chat/broadband-handler.js +80 -80
  91. package/src/routes/chat/gateway.js +46 -46
  92. package/src/routes/chat/relay-pipeline.js +282 -282
  93. package/src/routes/chat/via-route-handler.js +156 -156
  94. package/src/routes/hedge.js +260 -260
  95. package/src/routes/models-route.js +167 -167
  96. package/src/routes/peers.js +373 -373
  97. package/src/routes/stream.js +364 -347
  98. package/src/runtime/bootstrap.js +75 -75
  99. package/src/runtime/keep-warm.js +135 -135
  100. package/src/runtime/provider-gate.js +75 -75
  101. package/src/runtime/providers-setup.js +187 -187
  102. package/src/runtime/raccoon-checkin.js +175 -175
  103. package/src/server.js +85 -85
  104. package/src/state/schemas/allowlist.js +92 -92
  105. package/src/sync-opencode.js +280 -280
  106. package/src/transport/index.js +244 -244
  107. package/src/transport/pool.js +56 -56
  108. package/src/transport/retry.js +24 -24
  109. package/src/transport/sse.js +93 -93
  110. package/src/upstream-probe/display.js +52 -52
  111. package/src/upstream-probe/probe.js +49 -49
  112. package/src/upstream-probe/rotate.js +110 -110
  113. package/src/upstream-probe/start.js +45 -45
  114. package/src/upstream.js +355 -355
@@ -1,70 +1,70 @@
1
- // models.dev 能力目录 → mslxdff 能力形状的纯函数解析层(无 IO,测试接缝 S1)
2
- // 源数据形态(实测 models.opencode.ai/api.json 2026-09-11):
3
- // reasoning_options: [{type:"effort",values:["low","medium","high","max"]} | {type:"toggle"} | {type:"budget_tokens",min}]
4
- // modalities.input 含 "image" 即可读图;limit.context/output;cost.input/output 为 $/M tokens
5
- export function normalizeModelCaps(_id, m) {
6
- const opts = Array.isArray(m?.reasoning_options) ? m.reasoning_options : [];
7
- const effort = opts.find((o) => o?.type === "effort");
8
- const toggle = opts.some((o) => o?.type === "toggle");
9
- const budget = opts.find((o) => o?.type === "budget_tokens");
10
- const input = Array.isArray(m?.modalities?.input) ? m.modalities.input : [];
11
- return {
12
- reasoning: Boolean(m?.reasoning),
13
- effortType: effort ? "effort" : toggle ? "toggle" : budget ? "budget_tokens" : null,
14
- effortValues: effort && Array.isArray(effort.values) ? effort.values.map(String) : null,
15
- imageInput: input.includes("image"),
16
- toolCall: Boolean(m?.tool_call),
17
- context: Number(m?.limit?.context) || null,
18
- maxOutput: Number(m?.limit?.output) || null,
19
- costIn: Number(m?.cost?.input) || null,
20
- costOut: Number(m?.cost?.output) || null,
21
- // opencode Model 形状补充字段(-setto opencode 条目注入用)
22
- attachment: Boolean(m?.attachment),
23
- temperature: Boolean(m?.temperature),
24
- releaseDate: typeof m?.release_date === "string" && m.release_date ? m.release_date : null,
25
- inputModalities: input.length ? input : ["text"],
26
- outputModalities: Array.isArray(m?.modalities?.output) && m.modalities.output.length ? m.modalities.output : ["text"],
27
- // 模型级 SDK 覆盖(models.dev provider.npm):@ai-sdk/openai → responses 端点;null = 继承 provider 默认
28
- npm: typeof m?.provider?.npm === "string" && m.provider.npm ? m.provider.npm : null,
29
- };
30
- }
31
-
32
- // provider.models 对象({ [modelId]: rawModel })→ { [modelId]: caps }
33
- export function normalizeProviderModels(modelsObj) {
34
- const out = {};
35
- if (!modelsObj || typeof modelsObj !== "object") return out;
36
- for (const [id, m] of Object.entries(modelsObj)) {
37
- if (!m || typeof m !== "object") continue;
38
- out[id] = normalizeModelCaps(id, m);
39
- }
40
- return out;
41
- }
42
-
43
- // workbuddy 上游原生字段(/v3/config 产品文档,first-party 最准)→ 统一 caps 形状
44
- // 实测字段(2026-09-11,29 模型全覆盖):maxInputTokens/maxOutputTokens/supportsImages/
45
- // supportsReasoning/reasoning{effort,summary}/supportsToolCall/disabledMultimodal/credits/tags/name/vendor
46
- // reasoning 是"当前档位"非档位列表 → effortType=effort 但 effortValues=null、defaultEffort 记默认档
47
- export function normalizeWorkbuddyCaps(_id, m) {
48
- const imageOk = Boolean(m?.supportsImages) && !m?.disabledMultimodal;
49
- const reasoning = Boolean(m?.supportsReasoning);
50
- const effort = reasoning && m?.reasoning && typeof m.reasoning === "object" ? String(m.reasoning.effort || "").trim() : "";
51
- return {
52
- reasoning,
53
- effortType: reasoning ? "effort" : null,
54
- // 上游只给当前档位不给档位列表;实测 hy3 reasoning_effort low/high 均生效(思考块 99 vs 210),
55
- // 网关层按 OpenAI 兼容标准给通用三档(上游不识别时忽略,无害)
56
- effortValues: reasoning ? ["low", "medium", "high"] : null,
57
- defaultEffort: effort || null,
58
- imageInput: imageOk,
59
- toolCall: Boolean(m?.supportsToolCall),
60
- context: Number(m?.maxInputTokens) || null,
61
- maxOutput: Number(m?.maxOutputTokens) || null,
62
- costIn: null,
63
- costOut: null,
64
- attachment: false,
65
- temperature: m?.temperature != null,
66
- releaseDate: null,
67
- inputModalities: imageOk ? ["text", "image"] : ["text"],
68
- outputModalities: ["text"],
69
- };
70
- }
1
+ // models.dev 能力目录 → mslxdff 能力形状的纯函数解析层(无 IO,测试接缝 S1)
2
+ // 源数据形态(实测 models.opencode.ai/api.json 2026-09-11):
3
+ // reasoning_options: [{type:"effort",values:["low","medium","high","max"]} | {type:"toggle"} | {type:"budget_tokens",min}]
4
+ // modalities.input 含 "image" 即可读图;limit.context/output;cost.input/output 为 $/M tokens
5
+ export function normalizeModelCaps(_id, m) {
6
+ const opts = Array.isArray(m?.reasoning_options) ? m.reasoning_options : [];
7
+ const effort = opts.find((o) => o?.type === "effort");
8
+ const toggle = opts.some((o) => o?.type === "toggle");
9
+ const budget = opts.find((o) => o?.type === "budget_tokens");
10
+ const input = Array.isArray(m?.modalities?.input) ? m.modalities.input : [];
11
+ return {
12
+ reasoning: Boolean(m?.reasoning),
13
+ effortType: effort ? "effort" : toggle ? "toggle" : budget ? "budget_tokens" : null,
14
+ effortValues: effort && Array.isArray(effort.values) ? effort.values.map(String) : null,
15
+ imageInput: input.includes("image"),
16
+ toolCall: Boolean(m?.tool_call),
17
+ context: Number(m?.limit?.context) || null,
18
+ maxOutput: Number(m?.limit?.output) || null,
19
+ costIn: Number(m?.cost?.input) || null,
20
+ costOut: Number(m?.cost?.output) || null,
21
+ // opencode Model 形状补充字段(-setto opencode 条目注入用)
22
+ attachment: Boolean(m?.attachment),
23
+ temperature: Boolean(m?.temperature),
24
+ releaseDate: typeof m?.release_date === "string" && m.release_date ? m.release_date : null,
25
+ inputModalities: input.length ? input : ["text"],
26
+ outputModalities: Array.isArray(m?.modalities?.output) && m.modalities.output.length ? m.modalities.output : ["text"],
27
+ // 模型级 SDK 覆盖(models.dev provider.npm):@ai-sdk/openai → responses 端点;null = 继承 provider 默认
28
+ npm: typeof m?.provider?.npm === "string" && m.provider.npm ? m.provider.npm : null,
29
+ };
30
+ }
31
+
32
+ // provider.models 对象({ [modelId]: rawModel })→ { [modelId]: caps }
33
+ export function normalizeProviderModels(modelsObj) {
34
+ const out = {};
35
+ if (!modelsObj || typeof modelsObj !== "object") return out;
36
+ for (const [id, m] of Object.entries(modelsObj)) {
37
+ if (!m || typeof m !== "object") continue;
38
+ out[id] = normalizeModelCaps(id, m);
39
+ }
40
+ return out;
41
+ }
42
+
43
+ // workbuddy 上游原生字段(/v3/config 产品文档,first-party 最准)→ 统一 caps 形状
44
+ // 实测字段(2026-09-11,29 模型全覆盖):maxInputTokens/maxOutputTokens/supportsImages/
45
+ // supportsReasoning/reasoning{effort,summary}/supportsToolCall/disabledMultimodal/credits/tags/name/vendor
46
+ // reasoning 是"当前档位"非档位列表 → effortType=effort 但 effortValues=null、defaultEffort 记默认档
47
+ export function normalizeWorkbuddyCaps(_id, m) {
48
+ const imageOk = Boolean(m?.supportsImages) && !m?.disabledMultimodal;
49
+ const reasoning = Boolean(m?.supportsReasoning);
50
+ const effort = reasoning && m?.reasoning && typeof m.reasoning === "object" ? String(m.reasoning.effort || "").trim() : "";
51
+ return {
52
+ reasoning,
53
+ effortType: reasoning ? "effort" : null,
54
+ // 上游只给当前档位不给档位列表;实测 hy3 reasoning_effort low/high 均生效(思考块 99 vs 210),
55
+ // 网关层按 OpenAI 兼容标准给通用三档(上游不识别时忽略,无害)
56
+ effortValues: reasoning ? ["low", "medium", "high"] : null,
57
+ defaultEffort: effort || null,
58
+ imageInput: imageOk,
59
+ toolCall: Boolean(m?.supportsToolCall),
60
+ context: Number(m?.maxInputTokens) || null,
61
+ maxOutput: Number(m?.maxOutputTokens) || null,
62
+ costIn: null,
63
+ costOut: null,
64
+ attachment: false,
65
+ temperature: m?.temperature != null,
66
+ releaseDate: null,
67
+ inputModalities: imageOk ? ["text", "image"] : ["text"],
68
+ outputModalities: ["text"],
69
+ };
70
+ }
@@ -84,6 +84,8 @@ const DECISION_FIELDS = [
84
84
  "latencyMs", "ttfMs", "hedged", "hops", "hasShare", "elapsedMs", "threshold",
85
85
  "stallHits", "maxGapMs", "interrupted", "providers", "via",
86
86
  "retry", "step", "max", "delayMs", "upstream", "account", "pick", "cooled", "queued", "nudged", "retries", "waitedMs", "raiseFrom", "raiseTo",
87
+ // qoder 判决定点日志(2026-10-22):login/额度/排队判决各走各的路径,没有这三项,403 盲飞无从分辨
88
+ "login", "nocapacity", "retryAfter",
87
89
  "heldOpen", "terminalForm", "requestWaitedMs", "budgetMs", "budgetOut",
88
90
  // 终局判决(ADR-0058):取证时第一眼要看的三件——判的哪种、命中哪条判据、是否因此没问组员
89
91
  "kind", "marker", "peersSkipped",
@@ -103,8 +105,10 @@ function decisionKv(data = {}) {
103
105
  return out.join(" ");
104
106
  }
105
107
 
106
- // provider 回显头 → 日志字段(谁上的 / 打哪个站 / 为什么选它 / 是否被冷却 / 是否被判排队):
108
+ // provider 回显头 → 日志字段(谁上的 / 打哪个站 / 为什么选它 / 是否被冷却 / 是否被判排队 / 判决命中哪种):
107
109
  // 单一来源,防各处重复写法漂移;取不到时返回空对象(其它供应商零变化)。
110
+ // login/nocapacity/retryAfter(2026-10-22 补):qoder 判决链曾全程盲飞——403 直出日志里只有状态码,
111
+ // 看不出内部是 login 误伤、queue 漏检还是根本没命中,三轮排查全靠猜(用户实证批评:没多打日志)。
108
112
  export function upstreamEcho(res) {
109
113
  const h = res?.headers;
110
114
  if (typeof h?.get !== "function") return {};
@@ -115,6 +119,10 @@ export function upstreamEcho(res) {
115
119
  pick: pick("x-mslxdff-qoder-account"),
116
120
  cooled: pick("x-mslxdff-qoder-cooldown"),
117
121
  queued: pick("x-mslxdff-qoder-queued"),
122
+ login: pick("x-mslxdff-qoder-login"),
123
+ nocapacity: pick("x-mslxdff-qoder-nocapacity"),
124
+ verdict: pick("x-mslxdff-qoder-verdict"),
125
+ qoderRetry: pick("x-mslxdff-qoder-retry-after"),
118
126
  };
119
127
  }
120
128
 
@@ -128,7 +136,7 @@ export function formatModelTrace({ type, reqId, model, data = {}, request = null
128
136
  else if (type === "alias") detail = `rawModel=${data.rawModel || "-"} requested=${data.requested || model || "-"}`;
129
137
  else if (type === "exhausted-local" || type === "exhausted-all") detail = `last=${data.lastModel || model || "-"} status=${data.lastStatus ?? "-"} order=${(data.order || []).join(" | ")}`;
130
138
  else if (type === "upstream-try") detail = `target=${data.model || model || "-"} attempt=${data.attempt ?? "-"} payload=${kv(data.payload || {})}`;
131
- else if (type === "upstream-done" || type === "upstream-error") detail = `upstream status=${data.status ?? "-"} timing=${data.timing?.totalMs ?? "-"}ms${data.upstream ? ` via=${data.upstream}` : ""}${data.account ? ` account=${data.account}` : ""}${data.pick ? ` pick=${data.pick}` : ""}${data.cooled ? ` cooled=${data.cooled}` : ""}${data.queued ? ` queued=1` : ""} ${safeText(data.message || data.error || "")}`;
139
+ else if (type === "upstream-done" || type === "upstream-error") detail = `upstream status=${data.status ?? "-"} timing=${data.timing?.totalMs ?? "-"}ms${data.upstream ? ` via=${data.upstream}` : ""}${data.account ? ` account=${data.account}` : ""}${data.pick ? ` pick=${data.pick}` : ""}${data.cooled ? ` cooled=${data.cooled}` : ""}${data.queued ? ` queued=1` : ""}${data.login ? ` login=1` : ""}${data.nocapacity ? ` nocapacity=1` : ""}${data.verdict ? ` verdict=${data.verdict}` : ""}${data.qoderRetry ? ` retry=${data.qoderRetry}s` : ""} ${safeText(data.message || data.error || "")}`;
132
140
  else if (type === "empty-turn-retry") detail = `空转重试:retry ${data.retry ?? "-"}/${data.max ?? "-"}${data.step != null ? ` step=${data.step}` : ""} delay=${data.delayMs ?? "-"}ms${data.waitedMs ? ` waited=${data.waitedMs}ms` : ""}${data.requestWaitedMs != null ? ` 请求级累计=${data.requestWaitedMs}ms/预算${data.budgetMs ?? "-"}ms` : ""}${data.raiseTo ? ` max_tokens ${data.raiseFrom}→${data.raiseTo}` : ""}${data.upstream ? ` after=${data.upstream}` : ""}${data.account ? ` account=${data.account}` : ""}${data.pick ? ` pick=${data.pick}` : ""}${data.nudged ? ` nudged=1` : ""} reason=empty turn${data.reason ? ` :: ${safeText(data.reason, 120)}` : ""}`;
133
141
  else if (type === "empty-turn-recovered") detail = `空转重试成功:第 ${data.retries ?? "-"}/${data.max ?? "-"} 次重拉拿到真实输出,本轮共白等 ${data.waitedMs ?? "-"}ms${data.upstream ? ` via=${data.upstream}` : ""}${data.account ? ` account=${data.account}` : ""}${data.pick ? ` pick=${data.pick}` : ""}`;
134
142
  else if (type === "empty-turn-exhausted") detail = `空转重试已用尽:重试 ${data.retries ?? 0}/${data.max ?? "-"} 次仍零输出(累计等待 ${data.waitedMs ?? 0}ms${data.budgetOut ? `,请求级等待预算 ${data.budgetMs ?? "-"}ms 用尽` : ""}),交回换候选${data.heldOpen ? "(响应仍开着,换过去的正文还能送达)" : "(响应已封口,重拉只为省额度)"}${data.upstream ? ` after=${data.upstream}` : ""}${data.account ? ` account=${data.account}` : ""}${data.pick ? ` pick=${data.pick}` : ""}${data.reason ? ` :: ${safeText(data.reason, 120)}` : ""}`;