llm-relay 0.16.2 → 0.16.4

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.
@@ -92,31 +92,33 @@ function pickQuery(url, param) {
92
92
  * Returns true if the request was an admin route and has been handled, false otherwise.
93
93
  */
94
94
  export async function handleAdminRoutes(req, res, pathname, path, started, reqJson, cfg, h) {
95
+ const ok = (body, pretty = false) => {
96
+ res.writeHead(200, { "content-type": "application/json" });
97
+ res.end(pretty ? JSON.stringify(body, null, 2) : JSON.stringify(body));
98
+ h.logger.write(baseLog(started, path, false, false, 200, "skipped", null));
99
+ return true;
100
+ };
101
+ const bad = (status, message) => {
102
+ failClosed(res, status, message);
103
+ h.logger.write(baseLog(started, path, false, false, status, "skipped", null));
104
+ return true;
105
+ };
95
106
  if (req.method === "GET" && (pathname === "/v1/models" || pathname === "/models")) {
96
107
  const models = relayModels(cfg);
97
- res.writeHead(200, { "content-type": "application/json" });
98
108
  // `data` is the standard OpenAI shape; Codex's custom-provider catalog reader also accepts
99
109
  // the same entries under `models`. Returning both keeps the endpoint useful to both clients.
100
- res.end(JSON.stringify({ object: "list", data: models, models }));
101
- h.logger.write(baseLog(started, path, false, false, 200, "skipped", null));
102
- return true;
110
+ return ok({ object: "list", data: models, models });
103
111
  }
104
112
  // Discovery endpoint for an external dispatcher
105
113
  if (req.method === "GET" && pathname === "/registry") {
106
114
  const view = await buildRegistry(cfg, h.catalog, h.pingLoop ? { pingLoop: h.pingLoop } : {});
107
- res.writeHead(200, { "content-type": "application/json" });
108
- res.end(JSON.stringify(view));
109
- h.logger.write(baseLog(started, path, false, false, 200, "skipped", null));
110
- return true;
115
+ return ok(view);
111
116
  }
112
117
  if (req.method === "GET" && pathname === "/ping") {
113
118
  if (h.pingLoop) {
114
119
  await h.pingLoop.tickOnce();
115
120
  }
116
- res.writeHead(200, { "content-type": "application/json" });
117
- res.end(JSON.stringify({ ok: true, pingMode: h.pingLoop?.getMode(), intervalMs: h.pingLoop?.getIntervalMs() }));
118
- h.logger.write(baseLog(started, path, false, false, 200, "skipped", null));
119
- return true;
121
+ return ok({ ok: true, pingMode: h.pingLoop?.getMode(), intervalMs: h.pingLoop?.getIntervalMs() });
120
122
  }
121
123
  if (req.method === "GET" && (pathname === "/health/stats" || pathname === "/health")) {
122
124
  const view = await buildRegistry(cfg, h.catalog, h.pingLoop ? { pingLoop: h.pingLoop } : {});
@@ -125,10 +127,7 @@ export async function handleAdminRoutes(req, res, pathname, path, started, reqJs
125
127
  ping_mode: h.pingLoop?.getMode(),
126
128
  providers: view.providers,
127
129
  };
128
- res.writeHead(200, { "content-type": "application/json" });
129
- res.end(JSON.stringify(stats));
130
- h.logger.write(baseLog(started, path, false, false, 200, "skipped", null));
131
- return true;
130
+ return ok(stats);
132
131
  }
133
132
  if (req.method === "GET" && pathname === "/candidates") {
134
133
  const providerFilter = pickQuery(path, "provider");
@@ -138,10 +137,7 @@ export async function handleAdminRoutes(req, res, pathname, path, started, reqJs
138
137
  ...(h.pingLoop ? { pingLoop: h.pingLoop } : {}),
139
138
  ...(providerFilter ? { provider: providerFilter } : {}),
140
139
  });
141
- res.writeHead(200, { "content-type": "application/json" });
142
- res.end(JSON.stringify(view, null, 2));
143
- h.logger.write(baseLog(started, path, false, false, 200, "skipped", null));
144
- return true;
140
+ return ok(view, true);
145
141
  }
146
142
  if ((req.method === "GET" || req.method === "POST") && pathname === "/offload") {
147
143
  const queryClient = pickQuery(path, "client");
@@ -151,25 +147,17 @@ export async function handleAdminRoutes(req, res, pathname, path, started, reqJs
151
147
  const client = typeof body.client === "string" && body.client.length > 0 ? body.client : queryClient;
152
148
  const scope = body.scope === undefined ? undefined : body.scope;
153
149
  if (body.client !== undefined && (typeof body.client !== "string" || body.client.length === 0)) {
154
- failClosed(res, 400, `POST /offload client must be a non-empty string`);
155
- h.logger.write(baseLog(started, path, false, false, 400, "skipped", null));
156
- return true;
150
+ return bad(400, `POST /offload client must be a non-empty string`);
157
151
  }
158
152
  if (scope !== undefined && scope !== "subagents" && scope !== "all") {
159
- failClosed(res, 400, `POST /offload scope must be "subagents" or "all"`);
160
- h.logger.write(baseLog(started, path, false, false, 400, "skipped", null));
161
- return true;
153
+ return bad(400, `POST /offload scope must be "subagents" or "all"`);
162
154
  }
163
155
  if (scope !== undefined && client === undefined) {
164
- failClosed(res, 400, `POST /offload scope requires a client`);
165
- h.logger.write(baseLog(started, path, false, false, 400, "skipped", null));
166
- return true;
156
+ return bad(400, `POST /offload scope requires a client`);
167
157
  }
168
158
  const want = body.enabled;
169
159
  if (typeof want !== "boolean") {
170
- failClosed(res, 400, `POST /offload needs {"enabled": true|false, "client"?: string, "scope"?: "subagents"|"all"}`);
171
- h.logger.write(baseLog(started, path, false, false, 400, "skipped", null));
172
- return true;
160
+ return bad(400, `POST /offload needs {"enabled": true|false, "client"?: string, "scope"?: "subagents"|"all"}`);
173
161
  }
174
162
  // A toggle keyed to a name no front door produces would be dead config that silently does
175
163
  // nothing — refuse it like an unknown pool. An already-configured key stays togglable (an
@@ -177,17 +165,12 @@ export async function handleAdminRoutes(req, res, pathname, path, started, reqJs
177
165
  if (client !== undefined) {
178
166
  const unroutable = unroutableOffloadClient(client, cfg);
179
167
  if (unroutable?.fatal) {
180
- failClosed(res, 400, `POST /offload: ${unroutable.message}`);
181
- h.logger.write(baseLog(started, path, false, false, 400, "skipped", null));
182
- return true;
168
+ return bad(400, `POST /offload: ${unroutable.message}`);
183
169
  }
184
170
  }
185
171
  state = setOffload(cfg, want, client, scope);
186
172
  }
187
- res.writeHead(200, { "content-type": "application/json" });
188
- res.end(JSON.stringify(state, null, 2));
189
- h.logger.write(baseLog(started, path, false, false, 200, "skipped", null));
190
- return true;
173
+ return ok(state, true);
191
174
  }
192
175
  if ((req.method === "GET" || req.method === "POST") && pathname === "/dispatch") {
193
176
  let bodyTier;
@@ -197,9 +180,7 @@ export async function handleAdminRoutes(req, res, pathname, path, started, reqJs
197
180
  let outcome;
198
181
  if (body.outcome !== undefined) {
199
182
  if (body.outcome !== "rate_limited" && body.outcome !== "quota_exhausted") {
200
- failClosed(res, 400, `POST /dispatch outcome must be "rate_limited" or "quota_exhausted"`);
201
- h.logger.write(baseLog(started, path, false, false, 400, "skipped", null));
202
- return true;
183
+ return bad(400, `POST /dispatch outcome must be "rate_limited" or "quota_exhausted"`);
203
184
  }
204
185
  outcome = body.outcome;
205
186
  }
@@ -211,9 +192,7 @@ export async function handleAdminRoutes(req, res, pathname, path, started, reqJs
211
192
  (outcome !== undefined ? OUTCOME_DEFAULT_MS[outcome] : undefined);
212
193
  bodyTier = typeof body.tier === "string" ? body.tier : undefined;
213
194
  if (body.client !== undefined && (typeof body.client !== "string" || body.client.length === 0)) {
214
- failClosed(res, 400, `POST /dispatch client must be a non-empty string`);
215
- h.logger.write(baseLog(started, path, false, false, 400, "skipped", null));
216
- return true;
195
+ return bad(400, `POST /dispatch client must be a non-empty string`);
217
196
  }
218
197
  if (typeof body.client === "string")
219
198
  bodyClient = body.client;
@@ -225,22 +204,16 @@ export async function handleAdminRoutes(req, res, pathname, path, started, reqJs
225
204
  }
226
205
  else if (typeof body.exhausted === "string") {
227
206
  if (!markExhausted(cfg, body.exhausted, ttlMs, bodyTier)) {
228
- failClosed(res, 400, `POST /dispatch: no lane "${body.exhausted}" in routing.ladder`);
229
- h.logger.write(baseLog(started, path, false, false, 400, "skipped", null));
230
- return true;
207
+ return bad(400, `POST /dispatch: no lane "${body.exhausted}" in routing.ladder`);
231
208
  }
232
209
  }
233
210
  else {
234
- failClosed(res, 400, `POST /dispatch needs {"exhausted":"<lane>"} or {"clear":"<lane>"|true}`);
235
- h.logger.write(baseLog(started, path, false, false, 400, "skipped", null));
236
- return true;
211
+ return bad(400, `POST /dispatch needs {"exhausted":"<lane>"} or {"clear":"<lane>"|true}`);
237
212
  }
238
213
  }
239
214
  const rawTask = pickQuery(path, "task");
240
215
  if (typeof rawTask === "string" && rawTask.length > MAX_TASK_LEN) {
241
- failClosed(res, 400, `?task= exceeds ${MAX_TASK_LEN} characters`);
242
- h.logger.write(baseLog(started, path, false, false, 400, "skipped", null));
243
- return true;
216
+ return bad(400, `?task= exceeds ${MAX_TASK_LEN} characters`);
244
217
  }
245
218
  const taskParam = typeof rawTask === "string" && rawTask.length > 0 ? rawTask : undefined;
246
219
  const view = buildDispatch(cfg, {
@@ -250,17 +223,10 @@ export async function handleAdminRoutes(req, res, pathname, path, started, reqJs
250
223
  ...((pickQuery(path, "tier") ?? bodyTier) ? { tier: (pickQuery(path, "tier") ?? bodyTier) } : {}),
251
224
  ...(bodyClient ? { client: bodyClient } : {}),
252
225
  });
253
- res.writeHead(200, { "content-type": "application/json" });
254
- res.end(JSON.stringify(view, null, 2));
255
- h.logger.write(baseLog(started, path, false, false, 200, "skipped", null));
256
- return true;
226
+ return ok(view, true);
257
227
  }
258
228
  if (req.method === "GET" && pathname === "/telemetry") {
259
- const report = getTelemetryReport(cfg, h.breaker);
260
- res.writeHead(200, { "content-type": "application/json" });
261
- res.end(JSON.stringify(report, null, 2));
262
- h.logger.write(baseLog(started, path, false, false, 200, "skipped", null));
263
- return true;
229
+ return ok(getTelemetryReport(cfg, h.breaker), true);
264
230
  }
265
231
  return false;
266
232
  }
@@ -1 +1 @@
1
- {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/routes/admin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAkC,MAAM,cAAc,CAAC;AAIvF,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,kBAAkB,EAAwB,MAAM,gBAAgB,CAAC;AACxH,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B,SAAS,mBAAmB,CAAC,KAAc,EAAE,GAAgB;IAC3D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACf,OAAO;IACT,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,mBAAmB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACzD,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,mBAAmB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC9C,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC5C,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAChD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;QAAE,GAAG,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IACjF,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAClC,EAAE;QACF,IAAI,EAAE,EAAE;QACR,YAAY,EAAE,EAAE;QAChB,WAAW,EAAE,iCAAiC;QAC9C,uBAAuB,EAAE,QAAQ;QACjC,0BAA0B,EAAE;YAC1B,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,uCAAuC,EAAE;YAC3E,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,uCAAuC,EAAE;YACvE,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,uDAAuD,EAAE;YAC1F,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,8CAA8C,EAAE;YAC/E,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,iDAAiD,EAAE;SACpF;QACD,UAAU,EAAE,eAAe;QAC3B,UAAU,EAAE,MAAM;QAClB,gBAAgB,EAAE,IAAI;QACtB,QAAQ,EAAE,CAAC;QACX,sBAAsB,EAAE,CAAC,MAAM,CAAC;QAChC,aAAa,EAAE,EAAE;QACjB,gBAAgB,EAAE,IAAI;QACtB,OAAO,EAAE,IAAI;QACb,iBAAiB,EAAE,EAAE;QACrB,cAAc,EAAE,EAAE,qBAAqB,EAAE,EAAE,EAAE,sBAAsB,EAAE,IAAI,EAAE;QAC3E,iCAAiC,EAAE,KAAK;QACxC,yBAAyB,EAAE,MAAM;QACjC,iBAAiB,EAAE,IAAI;QACvB,iBAAiB,EAAE,QAAQ;QAC3B,qBAAqB,EAAE,UAAU;QACjC,oBAAoB,EAAE,gBAAgB;QACtC,iBAAiB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE;QACnD,4BAA4B,EAAE,IAAI;QAClC,8BAA8B,EAAE,IAAI;QACpC,cAAc,EAAE,MAAM;QACtB,kBAAkB,EAAE,MAAM;QAC1B,SAAS,EAAE,WAAW;QACtB,gCAAgC,EAAE,EAAE;QACpC,4BAA4B,EAAE,EAAE;QAChC,gBAAgB,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;QACnC,oBAAoB,EAAE,IAAI;QAC1B,kBAAkB,EAAE,KAAK;QACzB,SAAS,EAAE,gBAAgB;QAC3B,mBAAmB,EAAE,IAAI;QACzB,MAAM,EAAE,OAAO;QACf,OAAO,EAAE,CAAC;QACV,QAAQ,EAAE,WAAW;KACtB,CAAC,CAAC,CAAC;AACN,CAAC;AASD,SAAS,UAAU,CAAC,GAAmB,EAAE,MAAc,EAAE,OAAe;IACtE,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC9D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,SAAS,CAAC,GAAW,EAAE,KAAa;IAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,IAAI,KAAK,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAClC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;IACxD,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAoB,EACpB,GAAmB,EACnB,QAAgB,EAChB,IAAY,EACZ,OAAe,EACf,OAAgB,EAChB,GAAW,EACX,CAAgB;IAEhB,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,QAAQ,KAAK,YAAY,IAAI,QAAQ,KAAK,SAAS,CAAC,EAAE,CAAC;QAClF,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAChC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,2FAA2F;QAC3F,6FAA6F;QAC7F,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAClE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,gDAAgD;IAChD,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC7F,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9B,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjD,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;YACf,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAC9B,CAAC;QACD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC;QAChH,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,CAAC,QAAQ,KAAK,eAAe,IAAI,QAAQ,KAAK,SAAS,CAAC,EAAE,CAAC;QACrF,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC7F,MAAM,KAAK,GAA4B;YACrC,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,SAAS,EAAE,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE;YAChC,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC;QACF,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/B,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;QACvD,MAAM,cAAc,GAAG,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE;YACtC,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxD,CAAC,CAAC;QACH,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACvC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;QAC/E,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC9C,IAAI,KAAK,GAAG,YAAY,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC3C,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAA6D,CAAC;YACzF,MAAM,MAAM,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC;YACrG,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;YAChE,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC/F,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,iDAAiD,CAAC,CAAC;gBACxE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC3E,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,WAAW,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;gBACpE,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,kDAAkD,CAAC,CAAC;gBACzE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC3E,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,KAAK,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBAChD,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,uCAAuC,CAAC,CAAC;gBAC9D,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC3E,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC;YAC1B,IAAI,OAAO,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC9B,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,6FAA6F,CAAC,CAAC;gBACpH,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC3E,OAAO,IAAI,CAAC;YACd,CAAC;YACD,0FAA0F;YAC1F,0FAA0F;YAC1F,2FAA2F;YAC3F,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,MAAM,UAAU,GAAG,uBAAuB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;gBACxD,IAAI,UAAU,EAAE,KAAK,EAAE,CAAC;oBACtB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,kBAAkB,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;oBAC7D,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;oBAC3E,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;YACD,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,KAAiC,CAAC,CAAC;QAC3E,CAAC;QACD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACxC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;QAChF,IAAI,QAA4B,CAAC;QACjC,IAAI,UAAU,GAAuB,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC/D,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAA2I,CAAC;YACvK,IAAI,OAAoC,CAAC;YACzC,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC/B,IAAI,IAAI,CAAC,OAAO,KAAK,cAAc,IAAI,IAAI,CAAC,OAAO,KAAK,iBAAiB,EAAE,CAAC;oBAC1E,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,oEAAoE,CAAC,CAAC;oBAC3F,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;oBAC3E,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YACzB,CAAC;YACD,0FAA0F;YAC1F,uFAAuF;YACvF,MAAM,YAAY,GAAG,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;YAC3F,MAAM,KAAK,GACT,CAAC,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;gBACzD,YAAY;gBACZ,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YACpE,QAAQ,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;YACjE,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC/F,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,kDAAkD,CAAC,CAAC;gBACzE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC3E,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;gBAAE,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;YAC9D,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACnC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC5C,CAAC;iBAAM,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;gBAC/B,cAAc,CAAC,GAAG,CAAC,CAAC;YACtB,CAAC;iBAAM,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;gBAC9C,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC;oBACzD,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,4BAA4B,IAAI,CAAC,SAAS,qBAAqB,CAAC,CAAC;oBACtF,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;oBAC3E,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,wEAAwE,CAAC,CAAC;gBAC/F,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC3E,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;YACjE,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,kBAAkB,YAAY,aAAa,CAAC,CAAC;YAClE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;YAC3E,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,SAAS,GAAG,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1F,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,EAAE;YAC9B,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,MAAM,CAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/E,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,OAAO,CAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClF,GAAG,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,QAAQ,CAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3G,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9C,CAAC,CAAC;QACH,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACvC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;QACtD,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QAClD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/routes/admin.ts"],"names":[],"mappings":"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"}
package/dist/server.js CHANGED
@@ -15,6 +15,7 @@ import { PingLoop } from "./ping/cadence.js";
15
15
  import { recordModelCall } from "./ping/runtime-telemetry.js";
16
16
  import { CircuitBreaker, globalCircuitBreaker } from "./circuit-breaker.js";
17
17
  import { estimateRequestTokens, assessCost } from "./metadata.js";
18
+ import { specOfTarget } from "./benchmarks.js";
18
19
  import { materializeDynamicPools } from "./dynamic-pools.js";
19
20
  import { baseLog } from "./request-log.js";
20
21
  import { CONTROL_AUTHORIZATION_HEADER, createControlAuthorization, resolveControlAuthorizationConfigDir, validateControlAuthorization, } from "./control-authorization.js";
@@ -442,14 +443,9 @@ async function handle(req, res, cfg, h) {
442
443
  return;
443
444
  }
444
445
  }
445
- // Candidate execution loop with failover across healthyTargets
446
- //
447
- // When the whole pool is rate-limited, the client is served the LAST candidate's real 429 —
448
- // but that candidate's Retry-After may be the pool's worst. Track the earliest reset among
449
- // the 429s failed over past, and only when every skipped response was a 429 (a mixed walk
450
- // says nothing about when the POOL frees up) surface the minimum on the returned error.
451
- let pool429RetryAfterMs = null;
452
- let failedOverOnly429 = true;
446
+ // Candidate execution loop with failover across healthyTargets.
447
+ // All-429 exhaustion Retry-After policy: `Pool429Tracker`.
448
+ const pool429 = new Pool429Tracker();
453
449
  for (let i = 0; i < healthyTargets.length; i++) {
454
450
  if (res.destroyed)
455
451
  break;
@@ -538,14 +534,7 @@ async function handle(req, res, cfg, h) {
538
534
  clearTimeout(timer);
539
535
  res.off("close", onResClose);
540
536
  await backendRes.body?.cancel().catch(() => { });
541
- if (backendRes.status === 429) {
542
- if (retryAfterMs !== null) {
543
- pool429RetryAfterMs = pool429RetryAfterMs === null ? retryAfterMs : Math.min(pool429RetryAfterMs, retryAfterMs);
544
- }
545
- }
546
- else {
547
- failedOverOnly429 = false;
548
- }
537
+ pool429.recordFailover(backendRes.status, retryAfterMs);
549
538
  completeAttemptFailure(h, attempt, {
550
539
  failure: "http",
551
540
  provenance: localFailure ? "relay-mapper-defect" : "upstream",
@@ -562,9 +551,7 @@ async function handle(req, res, cfg, h) {
562
551
  await repairPath(res, backendRes, timer, { tools, wantsStream, streamed, started, path, hadTools, reshaper: reshaper, maxAttempts: cfg.repair.maxAttempts, req, target, attempt, signal: controller.signal }, h);
563
552
  }
564
553
  else {
565
- const poolRetryAfterMs = backendRes.status === 429 && failedOverOnly429 && pool429RetryAfterMs !== null
566
- ? Math.min(pool429RetryAfterMs, retryAfterMs ?? Infinity)
567
- : undefined;
554
+ const poolRetryAfterMs = pool429.overrideMs(backendRes.status, retryAfterMs);
568
555
  await transparentPath(res, backendRes, timer, { tools, streamed, willValidate, started, path, hadTools, req, target, attempt, signal: controller.signal, retryAfterOverrideMs: poolRetryAfterMs }, h);
569
556
  }
570
557
  return;
@@ -630,6 +617,35 @@ export function classifyStatus(status) {
630
617
  function shouldTryNext(cls) {
631
618
  return cls === "retriable" || cls === "credential";
632
619
  }
620
+ /**
621
+ * All-429 exhaustion policy — one policy, both fronts (same maxim as `classifyStatus`).
622
+ *
623
+ * When the whole pool is rate-limited, the client is served the LAST candidate's real 429, but
624
+ * that candidate's Retry-After may be the pool's worst: the earliest reset among the walked 429s
625
+ * is when the POOL next has capacity. Only an all-429 walk qualifies — a mixed walk says nothing
626
+ * about when the pool frees up, so any non-429 failure leaves the final header untouched.
627
+ */
628
+ class Pool429Tracker {
629
+ minRetryAfterMs = null;
630
+ only429 = true;
631
+ /** Record a response being failed over past. */
632
+ recordFailover(status, retryAfterMs) {
633
+ if (status === 429) {
634
+ if (retryAfterMs !== null) {
635
+ this.minRetryAfterMs = this.minRetryAfterMs === null ? retryAfterMs : Math.min(this.minRetryAfterMs, retryAfterMs);
636
+ }
637
+ }
638
+ else {
639
+ this.only429 = false;
640
+ }
641
+ }
642
+ /** Retry-After (ms) to serve on the FINAL response, or undefined to leave its real header alone. */
643
+ overrideMs(finalStatus, finalRetryAfterMs) {
644
+ if (finalStatus !== 429 || !this.only429 || this.minRetryAfterMs === null)
645
+ return undefined;
646
+ return Math.min(this.minRetryAfterMs, finalRetryAfterMs ?? Infinity);
647
+ }
648
+ }
633
649
  /**
634
650
  * Feed the proxy's own request outcome into runtime telemetry — the "observed traffic"
635
651
  * evidence `getStrength()` ranks on (basis "telemetry") and `/candidates` reports under
@@ -751,16 +767,14 @@ function detectOpenAiFrontProtocol(method, pathname) {
751
767
  */
752
768
  async function openAiFrontPath(res, candidates, ctx, h) {
753
769
  const tried = [];
754
- // Same earliest-reset policy as the Anthropic path's loop: on an all-429 walk, the served
755
- // Retry-After is the pool's minimum, not the last candidate's. One policy, both fronts.
756
- let pool429RetryAfterMs = null;
757
- let failedOverOnly429 = true;
770
+ // All-429 exhaustion Retry-After policy, shared with the Anthropic path: `Pool429Tracker`.
771
+ const pool429 = new Pool429Tracker();
758
772
  for (let i = 0; i < candidates.length; i++) {
759
773
  if (res.destroyed)
760
774
  break;
761
775
  const target = candidates[i];
762
776
  const isLast = i === candidates.length - 1;
763
- tried.push(specOf(target));
777
+ tried.push(specOfTarget(target));
764
778
  const controller = new AbortController();
765
779
  const timer = setTimeout(() => controller.abort(), target.timeoutMs);
766
780
  const onResClose = () => {
@@ -838,14 +852,7 @@ async function openAiFrontPath(res, candidates, ctx, h) {
838
852
  res.off("close", onResClose);
839
853
  // Release the skipped candidate's socket — an un-consumed body holds the connection open.
840
854
  await upstream.body?.cancel().catch(() => { });
841
- if (upstream.status === 429) {
842
- if (retryAfterMs !== null) {
843
- pool429RetryAfterMs = pool429RetryAfterMs === null ? retryAfterMs : Math.min(pool429RetryAfterMs, retryAfterMs);
844
- }
845
- }
846
- else {
847
- failedOverOnly429 = false;
848
- }
855
+ pool429.recordFailover(upstream.status, retryAfterMs);
849
856
  completeAttemptFailure(h, attempt, {
850
857
  failure: "http",
851
858
  provenance: "upstream",
@@ -862,11 +869,11 @@ async function openAiFrontPath(res, candidates, ctx, h) {
862
869
  // see that the failure they are holding is the last of N, not the only one.
863
870
  const streamed = (upstream.headers.get("content-type") ?? "").includes("text/event-stream");
864
871
  try {
865
- const servedBy = upstream.status >= 400 ? tried.join(", ") : specOf(target);
872
+ const servedBy = upstream.status >= 400 ? tried.join(", ") : specOfTarget(target);
866
873
  const headers = { ...filterResponseHeaders(upstream.headers), [SERVED_BY_HEADER]: servedBy };
867
- if (upstream.status === 429 && failedOverOnly429 && pool429RetryAfterMs !== null) {
868
- const effective = Math.min(pool429RetryAfterMs, retryAfterMs ?? Infinity);
869
- headers["retry-after"] = String(Math.max(1, Math.ceil(effective / 1000)));
874
+ const poolRetryAfterMs = pool429.overrideMs(upstream.status, retryAfterMs);
875
+ if (poolRetryAfterMs !== undefined) {
876
+ headers["retry-after"] = String(Math.max(1, Math.ceil(poolRetryAfterMs / 1000)));
870
877
  }
871
878
  if (upstream.status >= 400) {
872
879
  // Error bodies are small and are never streamed: buffer, normalize the envelope, send.
@@ -912,10 +919,6 @@ async function openAiFrontPath(res, candidates, ctx, h) {
912
919
  // Unreachable with candidates present: the last iteration always responds and returns. An
913
920
  // empty candidate list cannot get here either — routing rejects that with a 400 upstream.
914
921
  }
915
- /** The `provider/model` spec a resolved target came from — what a reader recognises from config. */
916
- function specOf(t) {
917
- return t.model ? `${t.provider}/${t.model}` : t.provider;
918
- }
919
922
  /** detect/default: forward bytes unchanged, observe + log if applicable. */
920
923
  async function transparentPath(res, backendRes, timer, ctx, h) {
921
924
  const responseHeaders = filterResponseHeaders(backendRes.headers);
@@ -1662,13 +1665,6 @@ function pickString(obj, key) {
1662
1665
  }
1663
1666
  return null;
1664
1667
  }
1665
- /** Read one query-string param off a raw request path. */
1666
- function pickQuery(path, key) {
1667
- const q = path.indexOf("?");
1668
- if (q === -1)
1669
- return null;
1670
- return new URLSearchParams(path.slice(q + 1)).get(key);
1671
- }
1672
1668
  function pickBool(obj, key) {
1673
1669
  return typeof obj === "object" && obj !== null && obj[key] === true;
1674
1670
  }