mslxdff 0.1.203 → 0.1.207

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 (330) hide show
  1. package/README.md +3 -3
  2. package/bin/mslxdff.js +1 -1
  3. package/docs/cli_help_mini.md +146 -0
  4. package/package.json +38 -38
  5. package/plugins/README.md +14 -14
  6. package/plugins/prefer-model.mjs.example +14 -14
  7. package/src/anthropic/canonical-json.js +55 -0
  8. package/src/anthropic/count-tokens.js +61 -61
  9. package/src/anthropic/request-body.js +183 -126
  10. package/src/anthropic/request-shape.js +60 -0
  11. package/src/anthropic/session-id.js +58 -0
  12. package/src/anthropic/shared.js +18 -18
  13. package/src/anthropic/sse-aggregate.js +56 -56
  14. package/src/anthropic/tool-media.js +75 -0
  15. package/src/anthropic/translate.js +296 -287
  16. package/src/anthropic/web-search.js +361 -361
  17. package/src/api-kind.js +31 -31
  18. package/src/autostart.js +288 -288
  19. package/src/bench/probe.js +1 -1
  20. package/src/bench/runner.js +1 -1
  21. package/src/bench/via-probe.js +1 -1
  22. package/src/bench/via.js +144 -144
  23. package/src/bench/workbuddy-bench.js +1 -1
  24. package/src/chat/config.js +11 -11
  25. package/src/chat/cooling.js +81 -81
  26. package/src/chat/direct.js +58 -58
  27. package/src/chat/index.js +6 -6
  28. package/src/chat/spinner.js +38 -38
  29. package/src/chat/sse.js +69 -69
  30. package/src/chat/stats.js +247 -247
  31. package/src/chat/store.js +48 -48
  32. package/src/chat/tool-handlers.js +67 -67
  33. package/src/chat/tools.js +1 -1
  34. package/src/chat/upstream.js +59 -59
  35. package/src/chat-pipeline/auto-race.js +158 -158
  36. package/src/chat-pipeline/empty-turn.js +147 -147
  37. package/src/chat-pipeline/engine.js +17 -17
  38. package/src/chat-pipeline/index.js +8 -40
  39. package/src/chat-pipeline/serial-trial.js +279 -283
  40. package/src/chat-pipeline/terminal-verdict.js +132 -147
  41. package/src/chooser.js +54 -54
  42. package/src/claude-desktop/apply.js +101 -101
  43. package/src/claude-desktop/context1m.js +38 -38
  44. package/src/claude-desktop/doctor.js +146 -146
  45. package/src/claude-desktop/slots.js +152 -152
  46. package/src/cli/bootstrap.js +1 -1
  47. package/src/cli/commands/claude-desktop.js +284 -284
  48. package/src/cli/commands/daemon.js +231 -231
  49. package/src/cli/commands/model/list-live.js +22 -22
  50. package/src/cli/commands/model/list-providers.js +76 -76
  51. package/src/cli/commands/model/list-render.js +77 -77
  52. package/src/cli/commands/model/list-sort.js +52 -52
  53. package/src/cli/commands/model/list-tty.js +76 -76
  54. package/src/cli/commands/model/list.js +166 -166
  55. package/src/cli/commands/model/live-models.js +24 -24
  56. package/src/cli/commands/model/stats.js +43 -43
  57. package/src/cli/commands/model/status.js +47 -47
  58. package/src/cli/commands/model.js +51 -51
  59. package/src/cli/commands/provider/add.js +108 -108
  60. package/src/cli/commands/provider/allowlist.js +99 -99
  61. package/src/cli/commands/provider/cline-free.js +99 -99
  62. package/src/cli/commands/provider/cline-login.js +218 -218
  63. package/src/cli/commands/provider/cline-quota.js +65 -65
  64. package/src/cli/commands/provider/codearts-login.js +45 -45
  65. package/src/cli/commands/provider/config.js +119 -119
  66. package/src/cli/commands/provider/globalqwenwork-login.js +126 -126
  67. package/src/cli/commands/provider/keys-guard.js +50 -50
  68. package/src/cli/commands/provider/keys.js +161 -161
  69. package/src/cli/commands/provider/qoder-checkin.js +81 -81
  70. package/src/cli/commands/provider/qoder-login.js +102 -102
  71. package/src/cli/commands/provider/raccoon-login.js +180 -180
  72. package/src/cli/commands/provider/raccoon-password.js +162 -162
  73. package/src/cli/commands/provider/raccoon-quota.js +109 -109
  74. package/src/cli/commands/provider/traework-checkin.js +144 -144
  75. package/src/cli/commands/provider/traework-login.js +164 -164
  76. package/src/cli/commands/provider/workbuddy-login.js +153 -153
  77. package/src/cli/commands/provider/zcode-login.js +77 -77
  78. package/src/cli/commands/provider/zcode-quota.js +55 -55
  79. package/src/cli/commands/provider.js +1 -1
  80. package/src/cli/commands/stats.js +158 -149
  81. package/src/cli/commands/system.js +261 -261
  82. package/src/cli/commands/timezone.js +47 -47
  83. package/src/cli/commands/use-group.js +60 -60
  84. package/src/cli/commands/workbuddy.js +189 -189
  85. package/src/cli/format.js +141 -141
  86. package/src/cli/group-helpers.js +70 -70
  87. package/src/cli/help.js +80 -80
  88. package/src/cli/index.js +70 -70
  89. package/src/cli/interactive.js +121 -121
  90. package/src/cli/join-core.js +99 -99
  91. package/src/cli/join-wizard.js +175 -175
  92. package/src/cli/policy.js +136 -136
  93. package/src/cli/provider-row.js +126 -126
  94. package/src/cli/util.js +24 -24
  95. package/src/compat.js +53 -53
  96. package/src/events.js +38 -38
  97. package/src/free-lane.js +131 -131
  98. package/src/free-watcher.js +63 -63
  99. package/src/groups.js +262 -262
  100. package/src/logs.js +195 -195
  101. package/src/metrics.js +71 -62
  102. package/src/model-capabilities/context-lookup.js +65 -65
  103. package/src/model-capabilities/merge.js +142 -142
  104. package/src/model-trace.js +187 -187
  105. package/src/models.js +1 -1
  106. package/src/opencode-identity.js +72 -72
  107. package/src/peers.js +254 -254
  108. package/src/plugins.js +107 -107
  109. package/src/providers/AGENTS.md +49 -0
  110. package/src/providers/base.js +164 -164
  111. package/src/providers/classify.js +22 -22
  112. package/src/providers/cline/allowlist-sync.js +93 -93
  113. package/src/providers/cline/free-catalog.js +71 -71
  114. package/src/providers/cline/headers.js +37 -37
  115. package/src/providers/cline/index.js +130 -130
  116. package/src/providers/cline/models.js +150 -150
  117. package/src/providers/cline/usage.js +274 -274
  118. package/src/providers/codearts/auth-pool.js +148 -148
  119. package/src/providers/codearts/concurrency.js +34 -34
  120. package/src/providers/codearts/const.js +65 -65
  121. package/src/providers/codearts/dpop.js +95 -95
  122. package/src/providers/codearts/index.js +175 -175
  123. package/src/providers/codearts/login.js +214 -214
  124. package/src/providers/codearts/models.js +182 -182
  125. package/src/providers/codearts/sign.js +96 -96
  126. package/src/providers/codearts/sse.js +204 -204
  127. package/src/providers/codearts/stream.js +209 -209
  128. package/src/providers/codearts/sts.js +124 -124
  129. package/src/providers/codearts.js +1 -1
  130. package/src/providers/dispatcher.js +146 -146
  131. package/src/providers/generic.js +156 -156
  132. package/src/providers/globalqwenwork/account-store.js +141 -141
  133. package/src/providers/globalqwenwork/constants.js +73 -73
  134. package/src/providers/globalqwenwork/crypto.js +2 -2
  135. package/src/providers/globalqwenwork/http.js +2 -2
  136. package/src/providers/globalqwenwork/index.js +331 -331
  137. package/src/providers/globalqwenwork/payload.js +147 -147
  138. package/src/providers/globalqwenwork/rsa.js +2 -2
  139. package/src/providers/globalqwenwork/sse.js +2 -2
  140. package/src/providers/globalqwenwork/stream.js +2 -2
  141. package/src/providers/globalqwenwork.js +1 -1
  142. package/src/providers/globalworkbuddy/account-store.js +198 -198
  143. package/src/providers/globalworkbuddy/auth.js +97 -97
  144. package/src/providers/globalworkbuddy/catalog.js +138 -138
  145. package/src/providers/globalworkbuddy/constants.js +73 -73
  146. package/src/providers/globalworkbuddy/device-auth.js +120 -120
  147. package/src/providers/globalworkbuddy/errors.js +98 -98
  148. package/src/providers/globalworkbuddy/headers.js +89 -89
  149. package/src/providers/globalworkbuddy/models.js +96 -96
  150. package/src/providers/globalworkbuddy/payload.js +80 -80
  151. package/src/providers/index.js +5 -5
  152. package/src/providers/model-id.js +172 -172
  153. package/src/providers/opencode.js +19 -19
  154. package/src/providers/openrouter.js +31 -31
  155. package/src/providers/qoder/account-store.js +106 -106
  156. package/src/providers/qoder/aggregate.js +60 -60
  157. package/src/providers/qoder/baseprompt.json +591 -591
  158. package/src/providers/qoder/checkin.js +160 -160
  159. package/src/providers/qoder/constants.js +44 -44
  160. package/src/providers/qoder/encode.js +41 -41
  161. package/src/providers/qoder/fingerprint.js +38 -38
  162. package/src/providers/qoder/models.js +77 -77
  163. package/src/providers/qoder/oauth.js +84 -84
  164. package/src/providers/qoder/payload.js +162 -162
  165. package/src/providers/qoder/request.js +27 -27
  166. package/src/providers/qoder/session.js +134 -134
  167. package/src/providers/qoder/sticky.js +38 -38
  168. package/src/providers/qoder/stream.js +116 -116
  169. package/src/providers/qoder.js +1 -1
  170. package/src/providers/raccoon/account-store.js +216 -216
  171. package/src/providers/raccoon/auth.js +67 -67
  172. package/src/providers/raccoon/chat.js +228 -228
  173. package/src/providers/raccoon/const.js +180 -180
  174. package/src/providers/raccoon/credits.js +185 -185
  175. package/src/providers/raccoon/crypto.js +43 -43
  176. package/src/providers/raccoon/envelope.js +31 -31
  177. package/src/providers/raccoon/headers.js +45 -45
  178. package/src/providers/raccoon/index.js +216 -216
  179. package/src/providers/raccoon/login.js +279 -279
  180. package/src/providers/raccoon/models.js +160 -160
  181. package/src/providers/raccoon/password-login.js +102 -102
  182. package/src/providers/raccoon/qr-codewords.js +115 -115
  183. package/src/providers/raccoon/qr.js +236 -236
  184. package/src/providers/raccoon/sse.js +135 -135
  185. package/src/providers/responses-channel.js +120 -120
  186. package/src/providers/share-keys.js +53 -53
  187. package/src/providers/traework/account-store.js +234 -234
  188. package/src/providers/traework/chat.js +217 -217
  189. package/src/providers/traework/checkin.js +77 -77
  190. package/src/providers/traework/constants.js +41 -41
  191. package/src/providers/traework/errors.js +52 -52
  192. package/src/providers/traework/headers.js +79 -79
  193. package/src/providers/traework/index.js +132 -132
  194. package/src/providers/traework/market-identity.js +116 -116
  195. package/src/providers/traework/models.js +98 -98
  196. package/src/providers/traework/payload.js +86 -86
  197. package/src/providers/traework/sse.js +184 -184
  198. package/src/providers/traework/token.js +52 -52
  199. package/src/providers/traework.js +2 -2
  200. package/src/providers/workbuddy/account-store.js +186 -186
  201. package/src/providers/workbuddy/auth.js +158 -158
  202. package/src/providers/workbuddy/balance.js +86 -86
  203. package/src/providers/workbuddy/cat-travel.js +125 -125
  204. package/src/providers/workbuddy/checkin.js +75 -75
  205. package/src/providers/workbuddy/desktop-info.js +78 -78
  206. package/src/providers/workbuddy/growth-api.js +67 -67
  207. package/src/providers/workbuddy/growth-plans.js +63 -63
  208. package/src/providers/workbuddy/growth.js +181 -181
  209. package/src/providers/workbuddy/index.js +217 -217
  210. package/src/providers/workbuddy/models.js +126 -126
  211. package/src/providers/workbuddy/payload.js +141 -141
  212. package/src/providers/workbuddy/rotation-log.js +83 -83
  213. package/src/providers/workbuddy/sanitize-tools.js +61 -61
  214. package/src/providers/workbuddy/sdk-chat.js +26 -26
  215. package/src/providers/workbuddy-balance.js +78 -78
  216. package/src/providers/zcode/account-store.js +129 -129
  217. package/src/providers/zcode/auth.js +28 -28
  218. package/src/providers/zcode/chat.js +179 -179
  219. package/src/providers/zcode/const.js +54 -54
  220. package/src/providers/zcode/context-shape.js +162 -162
  221. package/src/providers/zcode/headers.js +93 -93
  222. package/src/providers/zcode/index.js +124 -124
  223. package/src/providers/zcode/models.js +65 -65
  224. package/src/providers/zcode/oauth.js +120 -120
  225. package/src/providers/zcode/quota.js +176 -176
  226. package/src/providers/zcode/sse.js +196 -196
  227. package/src/readline-compat.js +25 -25
  228. package/src/responses/translate.js +311 -311
  229. package/src/routes/AGENTS.md +37 -0
  230. package/src/routes/chat/broadband-handler.js +72 -72
  231. package/src/routes/chat/empty-turn-report.js +31 -31
  232. package/src/routes/chat/exhausted-handler.js +87 -87
  233. package/src/routes/chat/hedge-handler.js +130 -130
  234. package/src/routes/chat/index.js +1 -1
  235. package/src/routes/chat/local-handler.js +63 -63
  236. package/src/routes/chat/peer-handler.js +81 -81
  237. package/src/routes/chat.js +3 -3
  238. package/src/routes/fallback.js +88 -88
  239. package/src/routes/groups-relay.js +214 -214
  240. package/src/routes/groups.js +122 -122
  241. package/src/routes/helpers.js +93 -83
  242. package/src/routes/index.js +147 -147
  243. package/src/routes/messages-route.js +375 -365
  244. package/src/routes/peers.js +10 -2
  245. package/src/routes/relay-queue.js +181 -181
  246. package/src/routes/relay.js +60 -60
  247. package/src/routes/responses-route.js +213 -213
  248. package/src/routes/stream-body.js +84 -84
  249. package/src/routes/stream-hold.js +337 -337
  250. package/src/routes/stream-scan.js +366 -366
  251. package/src/routes.js +3 -3
  252. package/src/runtime/auto-update.js +113 -113
  253. package/src/runtime/broadband-stream.js +79 -79
  254. package/src/runtime/broadband.js +103 -103
  255. package/src/runtime/group-sync.js +81 -81
  256. package/src/runtime/keep-warm.js +120 -120
  257. package/src/runtime/lifecycle-forensics.js +116 -116
  258. package/src/runtime/lifecycle-log.js +87 -87
  259. package/src/runtime/log-stamp.js +73 -73
  260. package/src/runtime/proc-info.js +137 -137
  261. package/src/runtime/qoder-checkin.js +93 -93
  262. package/src/runtime/raccoon-checkin.js +126 -126
  263. package/src/runtime/server-lifecycle.js +189 -189
  264. package/src/runtime/traework-checkin.js +118 -118
  265. package/src/runtime/workbuddy-checkin.js +120 -120
  266. package/src/runtime/workbuddy-growth.js +133 -133
  267. package/src/state/facade.js +58 -58
  268. package/src/state/memory.js +162 -162
  269. package/src/state/merge.js +25 -25
  270. package/src/state/migrations/cline-unify.js +94 -94
  271. package/src/state/migrations.js +33 -33
  272. package/src/state/persist.js +42 -42
  273. package/src/state/provider-config.js +142 -142
  274. package/src/state/schemas/group.js +31 -31
  275. package/src/state/schemas/model.js +94 -94
  276. package/src/state/schemas/peer.js +31 -31
  277. package/src/state/schemas/port.js +10 -10
  278. package/src/state/schemas/provider.js +202 -202
  279. package/src/state/schemas/timezone.js +70 -70
  280. package/src/state/schemas/token.js +48 -48
  281. package/src/state/schemas/use-group.js +102 -102
  282. package/src/state/store.js +176 -176
  283. package/src/state.js +1 -1
  284. package/src/sync-claude-desktop.js +234 -234
  285. package/src/sync-claude.js +152 -152
  286. package/src/sync-codex.js +116 -116
  287. package/src/sync-workbuddy.js +158 -158
  288. package/src/talk-full-redact.js +129 -129
  289. package/src/talk-full.js +131 -131
  290. package/src/talk-log.js +257 -257
  291. package/src/text-tokens.js +52 -52
  292. package/src/thinking-effort.js +67 -67
  293. package/src/time.js +106 -106
  294. package/src/timeline.js +26 -26
  295. package/src/transport/index.js +1 -1
  296. package/src/upstream-engine/index.js +74 -74
  297. package/src/upstream-engine/mode.js +15 -15
  298. package/src/upstream-engine/sdk/attempt.js +221 -221
  299. package/src/upstream-engine/sdk/chat.js +28 -28
  300. package/src/upstream-engine/sdk/convert.js +192 -192
  301. package/src/upstream-engine/sdk/diagnose.js +62 -62
  302. package/src/upstream-engine/sdk/dispatch.js +55 -55
  303. package/src/upstream-engine/sdk/responses.js +176 -176
  304. package/src/upstream-engine/sdk/sse.js +166 -166
  305. package/src/upstream-responses.js +305 -305
  306. package/src/usage/cache-fields.js +58 -0
  307. package/src/usage/record.js +109 -106
  308. package/src/usage/report.js +209 -195
  309. package/src/v6pool/claim.js +157 -157
  310. package/src/v6pool/config.js +65 -65
  311. package/src/v6pool/detect.js +130 -130
  312. package/src/v6pool/index.js +152 -152
  313. package/src/v6pool/prefix.js +140 -140
  314. package/src/v6pool/probe.js +40 -40
  315. package/src/v6pool/report.js +104 -104
  316. package/src/v6pool/rotate.js +263 -263
  317. package/src/warp-pool/config.js +74 -74
  318. package/src/warp-pool/health.js +106 -106
  319. package/src/warp-pool/identity.js +141 -141
  320. package/src/warp-pool/index.js +358 -358
  321. package/src/warp-pool/keys.js +29 -29
  322. package/src/warp-pool/nodes.js +95 -95
  323. package/src/warp-pool/ports.js +160 -160
  324. package/src/warp-pool/register.js +113 -113
  325. package/src/warp-pool/report.js +232 -232
  326. package/src/warp-pool/revive.js +168 -168
  327. package/src/warp-pool/rotate.js +214 -214
  328. package/src/warp-pool/strategy.js +43 -43
  329. package/src/warp-pool/verdict.js +69 -69
  330. package/src/warp-pool/wireproxy.js +162 -162
@@ -1,130 +1,130 @@
1
- import { relay, SLOW_TOTAL_MS, STREAM_TIMEOUT_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS } from "../stream.js";
2
- import { buildFallbackInfo } from "../fallback.js";
3
- import { createRelayPipeline } from "./relay-pipeline.js";
4
- import { hedgedFirstChunkRace } from "../hedge.js";
5
-
6
- /** 薄适配:hedge 赛跑后按 winner 调 pipeline(复用 relay-pipeline 深模块) */
7
- export async function handleHedge({
8
- upRes,
9
- model,
10
- body,
11
- order,
12
- idx,
13
- lastErr,
14
- requested,
15
- useAuto,
16
- lockModel,
17
- auto,
18
- peers,
19
- handlerCtx,
20
- evt,
21
- logCall,
22
- logError,
23
- mark,
24
- perf0,
25
- attemptStartMs,
26
- stages,
27
- startedAt,
28
- plugins,
29
- res,
30
- hedgeDelayMs,
31
- deps = {},
32
- }) {
33
- const { createPipeline = createRelayPipeline, hedgedFirstChunkRace: race = hedgedFirstChunkRace } = deps;
34
- const d = hedgeDelayMs;
35
- try {
36
- const hedged = await race({ localUpRes: upRes, peers, handlerCtx, hedgeDelayMs: d, evt });
37
- if (hedged && hedged.winner) {
38
- if (hedged.winner === "local") {
39
- const bufferedUpRes = { ...upRes, body: hedged.bufferedBody, headers: upRes.headers, status: upRes.status, _t: upRes._t };
40
- const pipeline = createPipeline({
41
- relay,
42
- buildFallbackInfo,
43
- auto,
44
- plugins,
45
- evt,
46
- mark,
47
- logCall,
48
- logError,
49
- constants: { STREAM_TIMEOUT_MS, SLOW_TOTAL_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS },
50
- startedAt,
51
- stages,
52
- });
53
- const r = await pipeline.execute({
54
- res,
55
- upRes: bufferedUpRes,
56
- body,
57
- requested,
58
- actual: model,
59
- lastErr,
60
- via: "local",
61
- lockModel,
62
- useAuto,
63
- handlerCtx,
64
- mark,
65
- perf0,
66
- attemptStartMs,
67
- stages,
68
- startedAt,
69
- });
70
- // 保留 hedged 语义:若超时则透传 needs fallback
71
- if (!r.handled) return { handled: false, upRes: null, lastErr: r.lastErr };
72
- return { handled: true };
73
- }
74
- if (hedged.winner === "peer" && hedged.peerInfo) {
75
- const win = hedged.peerInfo;
76
- evt("peer-race-win", { reqId: handlerCtx.reqId, model, winPeer: win.peer.url, winTarget: win.target, latencyMs: win.latencyMs, hedged: true, ttfMs: hedged.ttfMs });
77
- await peers.recordResult(win.peer.url, { ok: true, latencyMs: win.latencyMs, model: win.target });
78
- const bufferedPeerRes = { ...win.res, body: hedged.bufferedBody, headers: win.res.headers, status: win.res.status, _t: win.res._t };
79
- const pipeline = createPipeline({
80
- relay,
81
- buildFallbackInfo,
82
- auto,
83
- plugins,
84
- evt,
85
- mark,
86
- logCall,
87
- logError: () => {},
88
- constants: { STREAM_TIMEOUT_MS, SLOW_TOTAL_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS },
89
- startedAt,
90
- stages,
91
- });
92
- const r = await pipeline.execute({
93
- res,
94
- upRes: bufferedPeerRes,
95
- body,
96
- requested,
97
- actual: win.target,
98
- lastErr,
99
- via: "peer",
100
- lockModel,
101
- useAuto,
102
- handlerCtx: { ...handlerCtx, model: win.target },
103
- mark: (n) => mark(n),
104
- perf0,
105
- attemptStartMs,
106
- stages,
107
- startedAt,
108
- });
109
- if (!r.handled) return { handled: false, upRes: null, lastErr: r.lastErr };
110
- return { handled: true };
111
- }
112
- }
113
- if (hedged && hedged.needsPeer) {
114
- return { handled: false, upRes: null, lastErr, needsPeer: true };
115
- }
116
- if (!hedged || !hedged.winner) {
117
- evt("hedge-both-fail", { reqId: handlerCtx.reqId, model });
118
- if (!hedged) {
119
- if (auto) await auto.recordError(model, { status: 502, slow: false, note: "hedge both fail" });
120
- const err = { model, upstream: null, status: 502, message: "hedge both failed" };
121
- return { handled: false, upRes: null, lastErr: err };
122
- }
123
- return { handled: false, upRes: null, lastErr };
124
- }
125
- return { handled: false, upRes: null, lastErr };
126
- } catch (hedgeErr) {
127
- evt("hedge-error", { reqId: handlerCtx.reqId, model, error: String(hedgeErr?.message || hedgeErr).slice(0, 300) });
128
- return { handled: false, upRes, lastErr };
129
- }
130
- }
1
+ import { relay, SLOW_TOTAL_MS, STREAM_TIMEOUT_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS } from "../stream.js";
2
+ import { buildFallbackInfo } from "../fallback.js";
3
+ import { createRelayPipeline } from "./relay-pipeline.js";
4
+ import { hedgedFirstChunkRace } from "../hedge.js";
5
+
6
+ /** 薄适配:hedge 赛跑后按 winner 调 pipeline(复用 relay-pipeline 深模块) */
7
+ export async function handleHedge({
8
+ upRes,
9
+ model,
10
+ body,
11
+ order,
12
+ idx,
13
+ lastErr,
14
+ requested,
15
+ useAuto,
16
+ lockModel,
17
+ auto,
18
+ peers,
19
+ handlerCtx,
20
+ evt,
21
+ logCall,
22
+ logError,
23
+ mark,
24
+ perf0,
25
+ attemptStartMs,
26
+ stages,
27
+ startedAt,
28
+ plugins,
29
+ res,
30
+ hedgeDelayMs,
31
+ deps = {},
32
+ }) {
33
+ const { createPipeline = createRelayPipeline, hedgedFirstChunkRace: race = hedgedFirstChunkRace } = deps;
34
+ const d = hedgeDelayMs;
35
+ try {
36
+ const hedged = await race({ localUpRes: upRes, peers, handlerCtx, hedgeDelayMs: d, evt });
37
+ if (hedged && hedged.winner) {
38
+ if (hedged.winner === "local") {
39
+ const bufferedUpRes = { ...upRes, body: hedged.bufferedBody, headers: upRes.headers, status: upRes.status, _t: upRes._t };
40
+ const pipeline = createPipeline({
41
+ relay,
42
+ buildFallbackInfo,
43
+ auto,
44
+ plugins,
45
+ evt,
46
+ mark,
47
+ logCall,
48
+ logError,
49
+ constants: { STREAM_TIMEOUT_MS, SLOW_TOTAL_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS },
50
+ startedAt,
51
+ stages,
52
+ });
53
+ const r = await pipeline.execute({
54
+ res,
55
+ upRes: bufferedUpRes,
56
+ body,
57
+ requested,
58
+ actual: model,
59
+ lastErr,
60
+ via: "local",
61
+ lockModel,
62
+ useAuto,
63
+ handlerCtx,
64
+ mark,
65
+ perf0,
66
+ attemptStartMs,
67
+ stages,
68
+ startedAt,
69
+ });
70
+ // 保留 hedged 语义:若超时则透传 needs fallback
71
+ if (!r.handled) return { handled: false, upRes: null, lastErr: r.lastErr };
72
+ return { handled: true };
73
+ }
74
+ if (hedged.winner === "peer" && hedged.peerInfo) {
75
+ const win = hedged.peerInfo;
76
+ evt("peer-race-win", { reqId: handlerCtx.reqId, model, winPeer: win.peer.url, winTarget: win.target, latencyMs: win.latencyMs, hedged: true, ttfMs: hedged.ttfMs });
77
+ await peers.recordResult(win.peer.url, { ok: true, latencyMs: win.latencyMs, model: win.target });
78
+ const bufferedPeerRes = { ...win.res, body: hedged.bufferedBody, headers: win.res.headers, status: win.res.status, _t: win.res._t };
79
+ const pipeline = createPipeline({
80
+ relay,
81
+ buildFallbackInfo,
82
+ auto,
83
+ plugins,
84
+ evt,
85
+ mark,
86
+ logCall,
87
+ logError: () => {},
88
+ constants: { STREAM_TIMEOUT_MS, SLOW_TOTAL_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS },
89
+ startedAt,
90
+ stages,
91
+ });
92
+ const r = await pipeline.execute({
93
+ res,
94
+ upRes: bufferedPeerRes,
95
+ body,
96
+ requested,
97
+ actual: win.target,
98
+ lastErr,
99
+ via: "peer",
100
+ lockModel,
101
+ useAuto,
102
+ handlerCtx: { ...handlerCtx, model: win.target },
103
+ mark: (n) => mark(n),
104
+ perf0,
105
+ attemptStartMs,
106
+ stages,
107
+ startedAt,
108
+ });
109
+ if (!r.handled) return { handled: false, upRes: null, lastErr: r.lastErr };
110
+ return { handled: true };
111
+ }
112
+ }
113
+ if (hedged && hedged.needsPeer) {
114
+ return { handled: false, upRes: null, lastErr, needsPeer: true };
115
+ }
116
+ if (!hedged || !hedged.winner) {
117
+ evt("hedge-both-fail", { reqId: handlerCtx.reqId, model });
118
+ if (!hedged) {
119
+ if (auto) await auto.recordError(model, { status: 502, slow: false, note: "hedge both fail" });
120
+ const err = { model, upstream: null, status: 502, message: "hedge both failed" };
121
+ return { handled: false, upRes: null, lastErr: err };
122
+ }
123
+ return { handled: false, upRes: null, lastErr };
124
+ }
125
+ return { handled: false, upRes: null, lastErr };
126
+ } catch (hedgeErr) {
127
+ evt("hedge-error", { reqId: handlerCtx.reqId, model, error: String(hedgeErr?.message || hedgeErr).slice(0, 300) });
128
+ return { handled: false, upRes, lastErr };
129
+ }
130
+ }
@@ -1 +1 @@
1
- export { createChatGateway, chatHandler } from "./gateway.js";
1
+ export { createChatGateway, chatHandler } from "./gateway.js";
@@ -1,63 +1,63 @@
1
- import { relay, SLOW_TOTAL_MS, STREAM_TIMEOUT_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS } from "../stream.js";
2
- import { buildFallbackInfo } from "../fallback.js";
3
- import { createRelayPipeline } from "./relay-pipeline.js";
4
-
5
- /** 薄适配:本地透传唯一经由 relay-pipeline */
6
- export async function handleLocalRelay({
7
- upRes,
8
- model,
9
- body,
10
- order,
11
- idx,
12
- lastErr,
13
- requested,
14
- useAuto,
15
- lockModel,
16
- auto,
17
- handlerCtx,
18
- evt,
19
- logCall,
20
- logError,
21
- mark,
22
- perf0,
23
- attemptStartMs,
24
- stages,
25
- startedAt,
26
- plugins,
27
- res,
28
- }) {
29
- const pipeline = createRelayPipeline({
30
- relay,
31
- buildFallbackInfo,
32
- auto,
33
- plugins,
34
- evt,
35
- mark,
36
- logCall,
37
- logError,
38
- constants: { STREAM_TIMEOUT_MS, SLOW_TOTAL_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS },
39
- startedAt,
40
- stages,
41
- });
42
- const r = await pipeline.execute({
43
- res,
44
- upRes,
45
- body,
46
- requested,
47
- actual: model,
48
- lastErr,
49
- via: "local",
50
- lockModel,
51
- useAuto,
52
- handlerCtx,
53
- mark,
54
- perf0,
55
- attemptStartMs,
56
- stages,
57
- startedAt,
58
- });
59
- // wrotePayload 是「正文真到了下游」的送达证据:serial-trial 记 empty-turn-recovered 只认它,
60
- // 不认 handled 本身(handled 也覆盖下游已断开等零输出路径,见 ADR-0043)。
61
- if (!r.handled) return { handled: false, upRes: null, lastErr: r.lastErr };
62
- return { handled: true, wrotePayload: r.wrotePayload === true };
63
- }
1
+ import { relay, SLOW_TOTAL_MS, STREAM_TIMEOUT_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS } from "../stream.js";
2
+ import { buildFallbackInfo } from "../fallback.js";
3
+ import { createRelayPipeline } from "./relay-pipeline.js";
4
+
5
+ /** 薄适配:本地透传唯一经由 relay-pipeline */
6
+ export async function handleLocalRelay({
7
+ upRes,
8
+ model,
9
+ body,
10
+ order,
11
+ idx,
12
+ lastErr,
13
+ requested,
14
+ useAuto,
15
+ lockModel,
16
+ auto,
17
+ handlerCtx,
18
+ evt,
19
+ logCall,
20
+ logError,
21
+ mark,
22
+ perf0,
23
+ attemptStartMs,
24
+ stages,
25
+ startedAt,
26
+ plugins,
27
+ res,
28
+ }) {
29
+ const pipeline = createRelayPipeline({
30
+ relay,
31
+ buildFallbackInfo,
32
+ auto,
33
+ plugins,
34
+ evt,
35
+ mark,
36
+ logCall,
37
+ logError,
38
+ constants: { STREAM_TIMEOUT_MS, SLOW_TOTAL_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS },
39
+ startedAt,
40
+ stages,
41
+ });
42
+ const r = await pipeline.execute({
43
+ res,
44
+ upRes,
45
+ body,
46
+ requested,
47
+ actual: model,
48
+ lastErr,
49
+ via: "local",
50
+ lockModel,
51
+ useAuto,
52
+ handlerCtx,
53
+ mark,
54
+ perf0,
55
+ attemptStartMs,
56
+ stages,
57
+ startedAt,
58
+ });
59
+ // wrotePayload 是「正文真到了下游」的送达证据:serial-trial 记 empty-turn-recovered 只认它,
60
+ // 不认 handled 本身(handled 也覆盖下游已断开等零输出路径,见 ADR-0043)。
61
+ if (!r.handled) return { handled: false, upRes: null, lastErr: r.lastErr };
62
+ return { handled: true, wrotePayload: r.wrotePayload === true };
63
+ }
@@ -1,82 +1,82 @@
1
- import { relay, SLOW_TOTAL_MS, STREAM_TIMEOUT_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS } from "../stream.js";
2
- import { buildFallbackInfo } from "../fallback.js";
3
- import { createRelayPipeline } from "./relay-pipeline.js";
4
- import { racePeerCandidates, peerStageCtx } from "../peers.js";
5
-
6
- /** 薄适配:peer 赛跑后经由 pipeline(via=peer) */
7
- export async function handlePeerRelay({
8
- model,
9
- body,
10
- lastErr,
11
- requested,
12
- useAuto,
13
- lockModel,
14
- auto,
15
- peers,
16
- handlerCtx,
17
- evt,
18
- logCall,
19
- mark,
20
- perf0,
21
- attemptStartMs,
22
- stages,
23
- startedAt,
24
- plugins,
25
- res,
26
- deps = {},
27
- }) {
28
- const { createPipeline = createRelayPipeline, racePeerCandidates: race = racePeerCandidates } = deps;
29
- evt("peer-race-start", { reqId: handlerCtx.reqId, model, peers: peers.ordered().length });
30
- const peerErrors = [];
31
- // 三批共享同一 peer 阶段总预算(同 hedge:旧行为是每批各吃满一次等头超时,串行叠加到 90s+)
32
- const pctx = peerStageCtx({ ...handlerCtx, peerErrors });
33
- const win =
34
- (await race(peers.ordered(), pctx)) ||
35
- (await race(peers.orderedByLastError(), pctx)) ||
36
- (await race(peers.coolingByLastError(), pctx));
37
- if (!win) {
38
- evt("peer-race-lose", { reqId: handlerCtx.reqId, model });
39
- // 组员全失败:把每个组员的真实返回汇总给调用者(否则只剩一个无信息的 429/502)
40
- const detail = peerErrors.length
41
- ? peerErrors.map((e) => `${e.peer} -> ${e.status}${e.message ? ` (${String(e.message).slice(0, 160)})` : ""}`).join("; ")
42
- : "no peers available";
43
- const allLimit = peerErrors.length > 0 && peerErrors.every((e) => e.status === 429);
44
- return { handled: false, lastErr: { model, upstream: null, status: allLimit ? 429 : 502, message: `peers failed: ${detail}` } };
45
- }
46
- evt("peer-race-win", { reqId: handlerCtx.reqId, model, winPeer: win.peer.url, winTarget: win.target, latencyMs: win.latencyMs });
47
- await peers.recordResult(win.peer.url, { ok: true, latencyMs: win.latencyMs, model: win.target });
48
-
49
- const pipeline = createPipeline({
50
- relay,
51
- buildFallbackInfo,
52
- auto,
53
- plugins,
54
- evt,
55
- mark,
56
- logCall,
57
- logError: () => {},
58
- constants: { STREAM_TIMEOUT_MS, SLOW_TOTAL_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS },
59
- startedAt,
60
- stages,
61
- });
62
- const r = await pipeline.execute({
63
- res,
64
- upRes: win.res,
65
- body,
66
- requested,
67
- actual: win.target,
68
- lastErr,
69
- via: "peer",
70
- lockModel,
71
- useAuto,
72
- handlerCtx: { ...handlerCtx, model: win.target },
73
- mark,
74
- perf0,
75
- attemptStartMs,
76
- stages,
77
- startedAt,
78
- });
79
- // Note: 超时/失败必须把 handled:false 交回上层换候选(丢弃 → 响应永不 end)— 见 .agents/notes/implemented/bug-fix/2026-09-17-relay-first-chunk-gate-real-cancel.md
80
- if (!r.handled) return { handled: false, upRes: null, lastErr: r.lastErr };
81
- return { handled: true };
1
+ import { relay, SLOW_TOTAL_MS, STREAM_TIMEOUT_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS } from "../stream.js";
2
+ import { buildFallbackInfo } from "../fallback.js";
3
+ import { createRelayPipeline } from "./relay-pipeline.js";
4
+ import { racePeerCandidates, peerStageCtx } from "../peers.js";
5
+
6
+ /** 薄适配:peer 赛跑后经由 pipeline(via=peer) */
7
+ export async function handlePeerRelay({
8
+ model,
9
+ body,
10
+ lastErr,
11
+ requested,
12
+ useAuto,
13
+ lockModel,
14
+ auto,
15
+ peers,
16
+ handlerCtx,
17
+ evt,
18
+ logCall,
19
+ mark,
20
+ perf0,
21
+ attemptStartMs,
22
+ stages,
23
+ startedAt,
24
+ plugins,
25
+ res,
26
+ deps = {},
27
+ }) {
28
+ const { createPipeline = createRelayPipeline, racePeerCandidates: race = racePeerCandidates } = deps;
29
+ evt("peer-race-start", { reqId: handlerCtx.reqId, model, peers: peers.ordered().length });
30
+ const peerErrors = [];
31
+ // 三批共享同一 peer 阶段总预算(同 hedge:旧行为是每批各吃满一次等头超时,串行叠加到 90s+)
32
+ const pctx = peerStageCtx({ ...handlerCtx, peerErrors });
33
+ const win =
34
+ (await race(peers.ordered(), pctx)) ||
35
+ (await race(peers.orderedByLastError(), pctx)) ||
36
+ (await race(peers.coolingByLastError(), pctx));
37
+ if (!win) {
38
+ evt("peer-race-lose", { reqId: handlerCtx.reqId, model });
39
+ // 组员全失败:把每个组员的真实返回汇总给调用者(否则只剩一个无信息的 429/502)
40
+ const detail = peerErrors.length
41
+ ? peerErrors.map((e) => `${e.peer} -> ${e.status}${e.message ? ` (${String(e.message).slice(0, 160)})` : ""}`).join("; ")
42
+ : "no peers available";
43
+ const allLimit = peerErrors.length > 0 && peerErrors.every((e) => e.status === 429);
44
+ return { handled: false, lastErr: { model, upstream: null, status: allLimit ? 429 : 502, message: `peers failed: ${detail}` } };
45
+ }
46
+ evt("peer-race-win", { reqId: handlerCtx.reqId, model, winPeer: win.peer.url, winTarget: win.target, latencyMs: win.latencyMs });
47
+ await peers.recordResult(win.peer.url, { ok: true, latencyMs: win.latencyMs, model: win.target });
48
+
49
+ const pipeline = createPipeline({
50
+ relay,
51
+ buildFallbackInfo,
52
+ auto,
53
+ plugins,
54
+ evt,
55
+ mark,
56
+ logCall,
57
+ logError: () => {},
58
+ constants: { STREAM_TIMEOUT_MS, SLOW_TOTAL_MS, STALL_TIMEOUT_MS, SCORE_STALL_MS },
59
+ startedAt,
60
+ stages,
61
+ });
62
+ const r = await pipeline.execute({
63
+ res,
64
+ upRes: win.res,
65
+ body,
66
+ requested,
67
+ actual: win.target,
68
+ lastErr,
69
+ via: "peer",
70
+ lockModel,
71
+ useAuto,
72
+ handlerCtx: { ...handlerCtx, model: win.target },
73
+ mark,
74
+ perf0,
75
+ attemptStartMs,
76
+ stages,
77
+ startedAt,
78
+ });
79
+ // Note: 超时/失败必须把 handled:false 交回上层换候选(丢弃 → 响应永不 end)— 见 .agents/notes/implemented/bug-fix/2026-09-17-relay-first-chunk-gate-real-cancel.md
80
+ if (!r.handled) return { handled: false, upRes: null, lastErr: r.lastErr };
81
+ return { handled: true };
82
82
  }
@@ -1,3 +1,3 @@
1
- // Facade — chat 逻辑已拆至 ./chat/ 子模块,按需加载保持单文件 <10KB
2
- export * from "./chat/index.js";
3
- export { chatHandler } from "./chat/index.js";
1
+ // Facade — chat 逻辑已拆至 ./chat/ 子模块,按需加载保持单文件 <10KB
2
+ export * from "./chat/index.js";
3
+ export { chatHandler } from "./chat/index.js";