@nick3/copilot-api 1.5.5 → 1.5.9

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 (32) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +34 -4
  3. package/dist/{account-AacnHem5.js → account-CbYMFuS4.js} +12 -4
  4. package/dist/account-CbYMFuS4.js.map +1 -0
  5. package/dist/accounts-manager-BKG9aZEL.js +2899 -0
  6. package/dist/accounts-manager-BKG9aZEL.js.map +1 -0
  7. package/dist/admin/assets/index-BFN8rXmt.css +1 -0
  8. package/dist/admin/assets/index-HnEqzcKv.js +101 -0
  9. package/dist/admin/index.html +2 -2
  10. package/dist/{auth-B7x3wjry.js → auth-Ckj1wD43.js} +3 -3
  11. package/dist/{auth-B7x3wjry.js.map → auth-Ckj1wD43.js.map} +1 -1
  12. package/dist/{check-usage-B1cbDEOI.js → check-usage-bIbj_1Q_.js} +3 -3
  13. package/dist/check-usage-bIbj_1Q_.js.map +1 -0
  14. package/dist/{get-copilot-token-cha9rQwA.js → get-copilot-token-MAZsr5Vu.js} +2 -2
  15. package/dist/{get-copilot-token-cha9rQwA.js.map → get-copilot-token-MAZsr5Vu.js.map} +1 -1
  16. package/dist/main.js +3 -3
  17. package/dist/{poll-access-token-DFooFWhY.js → poll-access-token-DiwBJNtK.js} +58 -33
  18. package/dist/poll-access-token-DiwBJNtK.js.map +1 -0
  19. package/dist/{server-CuXJhEMC.js → server-DAxpfPde.js} +934 -899
  20. package/dist/server-DAxpfPde.js.map +1 -0
  21. package/dist/{start-D6O1XcfI.js → start-8dkfsQqd.js} +7 -6
  22. package/dist/start-8dkfsQqd.js.map +1 -0
  23. package/package.json +2 -1
  24. package/dist/account-AacnHem5.js.map +0 -1
  25. package/dist/accounts-manager-BevCBoaF.js +0 -1449
  26. package/dist/accounts-manager-BevCBoaF.js.map +0 -1
  27. package/dist/admin/assets/index-519a65q_.js +0 -66
  28. package/dist/admin/assets/index-ChMaMig2.css +0 -1
  29. package/dist/check-usage-B1cbDEOI.js.map +0 -1
  30. package/dist/poll-access-token-DFooFWhY.js.map +0 -1
  31. package/dist/server-CuXJhEMC.js.map +0 -1
  32. package/dist/start-D6O1XcfI.js.map +0 -1
@@ -1,8 +1,8 @@
1
- import { A as resolveTraceId, C as normalizeDomain, D as accountFromState, E as prepareMessageProxyHeaders, O as state, T as prepareInteractionHeaders, _ as HTTPError, b as copilotHeaders, c as getRootSessionId, d as parseUserIdMetadata, f as sleep, g as getCopilotUsage, h as getDeviceCode, k as requestContext, l as getUUID, m as getGitHubUser, r as cacheModels, s as generateRequestIdFromPayload, t as pollAccessToken, u as isNullish, v as forwardError, w as prepareForCompact, y as copilotBaseUrl } from "./poll-access-token-DFooFWhY.js";
2
- import { a as getAccountClientIdentityByLoginAndApp, c as listAccountsFromRegistry, f as removeAccountFromRegistry, g as DEFAULT_IDENTITY_ENTERPRISE_DOMAIN, h as saveRegistry, m as saveAccountToken, p as removeAccountToken, r as addAccountToRegistry, t as isAccountType, u as loadRegistry, y as getCurrentIdentityEnvironment } from "./account-AacnHem5.js";
1
+ import { A as requestContext, D as prepareMessageProxyHeaders, E as prepareInteractionHeaders, O as accountFromState, T as prepareForCompact, _ as HTTPError, b as copilotHeaders, c as getUUID, d as parseUserIdMetadata, f as resolveAffinityKey, g as getCopilotUsage, h as getDeviceCode, j as resolveTraceId, k as state, l as isNullish, m as getGitHubUser, o as generateRequestIdFromPayload, p as sleep, s as getRootSessionId, t as pollAccessToken, u as normalizeStableSessionId, v as forwardError, w as normalizeDomain, y as copilotBaseUrl } from "./poll-access-token-DiwBJNtK.js";
2
+ import { _ as DEFAULT_IDENTITY_ENTERPRISE_DOMAIN, a as getAccountClientIdentityByLoginAndApp, b as getCurrentIdentityEnvironment, d as loadRegistry, g as saveRegistry, h as saveAccountToken, l as listAccountsFromRegistry, m as removeAccountToken, p as removeAccountFromRegistry, r as addAccountToRegistry, t as isAccountType } from "./account-CbYMFuS4.js";
3
3
  import { r as ensurePaths, t as PATHS } from "./paths-DGlr310R.js";
4
- import "./get-copilot-token-cha9rQwA.js";
5
- import { _ as isMessagesApiEnabled, a as getClaudeTokenMultiplier, b as mergeConfigWithDefaults, c as getModelAliases, d as getProviderConfig, f as getReasoningEffortForModel, g as isMessageStartInputTokensFallbackEnabled, h as isForceAgentEnabled, i as getAnthropicApiKey, l as getModelAliasesInfo, m as isAccountAffinityEnabled, n as PROVIDER_TYPE_ANTHROPIC, o as getConfig, p as getSmallModel, r as getAliasTargetSet, s as getExtraPromptForModel, t as accountsManager, u as getModelRefreshIntervalMs, v as isResponsesApiContextManagementModel, x as shouldCompactUseSmallModel, y as isResponsesApiWebSearchEnabled } from "./accounts-manager-BevCBoaF.js";
4
+ import "./get-copilot-token-MAZsr5Vu.js";
5
+ import { A as isResponsesApiWebSearchEnabled, C as getReasoningEffortForModel, D as isMessageStartInputTokensFallbackEnabled, E as isForceAgentEnabled, M as resolveModelAlias, N as shouldCompactUseSmallModel, O as isMessagesApiEnabled, S as getProviderConfig, T as isAccountAffinityEnabled, _ as getExtraPromptForModel, a as getClientIpInfo, b as getModelAliasesInfo, c as normalizeChatCompletionsUsage, d as toLocalDateString, f as PROVIDER_TYPE_ANTHROPIC, g as getConfig, h as getClaudeTokenMultiplier, i as extractResponsesUsageFromStreamEvent, j as mergeConfigWithDefaults, k as isResponsesApiContextManagementModel, l as normalizeEmbeddingsUsage, m as getAnthropicApiKey, n as applySharedSessionAffinityRetention, o as getRequestHistoryStore, p as getAliasTargetSet, r as extractResponsesUsageFromResult, s as getStatsStore, t as accountsManager, u as normalizeMessagesUsage, v as getLogLevel, w as getSmallModel, x as getModelRefreshIntervalMs, y as getModelAliases } from "./accounts-manager-BKG9aZEL.js";
6
6
  import consola from "consola";
7
7
  import fs, { readFile } from "node:fs/promises";
8
8
  import { randomUUID, timingSafeEqual } from "node:crypto";
@@ -12,7 +12,6 @@ import { Hono } from "hono";
12
12
  import { cors } from "hono/cors";
13
13
  import { logger } from "hono/logger";
14
14
  import fs$1, { existsSync } from "node:fs";
15
- import { Database } from "bun:sqlite";
16
15
  import { fileURLToPath } from "node:url";
17
16
  import { streamSSE } from "hono/streaming";
18
17
  import util from "node:util";
@@ -121,577 +120,6 @@ const traceIdMiddleware = async (c, next) => {
121
120
  });
122
121
  };
123
122
 
124
- //#endregion
125
- //#region src/lib/admin-db.ts
126
- const DEFAULT_DB_PATH = path.join(PATHS.APP_DIR, "admin.sqlite");
127
- let sharedDb = null;
128
- let initialized = false;
129
- const INIT_WARN_THROTTLE_MS = 3e4;
130
- let lastInitWarnAtMs = 0;
131
- let suppressedInitWarnCount = 0;
132
- function warnAdminDbInitFailure(error) {
133
- const now = Date.now();
134
- if (now - lastInitWarnAtMs < INIT_WARN_THROTTLE_MS) {
135
- suppressedInitWarnCount++;
136
- return;
137
- }
138
- const suppressed = suppressedInitWarnCount;
139
- suppressedInitWarnCount = 0;
140
- lastInitWarnAtMs = now;
141
- const suffix = suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : "";
142
- consola.warn(`Failed to initialize admin DB; admin features disabled${suffix}`, error);
143
- }
144
- function getAdminDbPath() {
145
- return DEFAULT_DB_PATH;
146
- }
147
- function openAdminDb(filePath = DEFAULT_DB_PATH) {
148
- return new Database(filePath);
149
- }
150
- function initAdminDb(db) {
151
- db.run("PRAGMA journal_mode = WAL;");
152
- db.run("PRAGMA synchronous = NORMAL;");
153
- db.run("PRAGMA busy_timeout = 3000;");
154
- db.run("PRAGMA foreign_keys = ON;");
155
- migrateAdminDb(db);
156
- }
157
- function getAdminDb() {
158
- if (!sharedDb) sharedDb = openAdminDb();
159
- if (!initialized) try {
160
- initAdminDb(sharedDb);
161
- initialized = true;
162
- } catch (error) {
163
- warnAdminDbInitFailure(error);
164
- }
165
- return sharedDb;
166
- }
167
- function getAdminDbUserVersion(db = getAdminDb()) {
168
- try {
169
- return db.query("PRAGMA user_version;").get()?.user_version ?? 0;
170
- } catch {
171
- return 0;
172
- }
173
- }
174
- function migrateV1(db) {
175
- db.run(`
176
- CREATE TABLE IF NOT EXISTS request_log (
177
- id INTEGER PRIMARY KEY AUTOINCREMENT,
178
- request_id TEXT NOT NULL UNIQUE,
179
-
180
- started_at_ms INTEGER NOT NULL,
181
- finished_at_ms INTEGER,
182
- duration_ms INTEGER,
183
- ttfb_ms INTEGER,
184
-
185
- method TEXT NOT NULL,
186
- path TEXT NOT NULL,
187
- upstream_endpoint TEXT,
188
- stream INTEGER NOT NULL DEFAULT 0,
189
-
190
- account_id TEXT,
191
- account_type TEXT,
192
- cost_units REAL,
193
- client_model TEXT,
194
- upstream_model TEXT,
195
-
196
- client_ip TEXT,
197
- client_ip_source TEXT,
198
- user_agent TEXT,
199
-
200
- tokens_input INTEGER,
201
- tokens_output INTEGER,
202
- tokens_total INTEGER,
203
- tokens_cached_input INTEGER,
204
- usage_json TEXT,
205
-
206
- premium_remaining_before REAL,
207
- premium_remaining_after REAL,
208
- premium_remaining_diff REAL,
209
- premium_unlimited_before INTEGER,
210
- premium_unlimited_after INTEGER,
211
-
212
- http_status INTEGER,
213
- error_name TEXT,
214
- error_status INTEGER,
215
- error_message TEXT,
216
- selection_failure_reason TEXT
217
- );
218
-
219
- CREATE INDEX IF NOT EXISTS idx_request_log_started_at
220
- ON request_log(started_at_ms DESC);
221
- CREATE INDEX IF NOT EXISTS idx_request_log_account_started_at
222
- ON request_log(account_id, started_at_ms DESC);
223
- CREATE INDEX IF NOT EXISTS idx_request_log_model_started_at
224
- ON request_log(upstream_model, started_at_ms DESC);
225
- CREATE INDEX IF NOT EXISTS idx_request_log_endpoint_started_at
226
- ON request_log(upstream_endpoint, started_at_ms DESC);
227
- CREATE INDEX IF NOT EXISTS idx_request_log_status_started_at
228
- ON request_log(http_status, started_at_ms DESC);
229
-
230
- PRAGMA user_version = 1;
231
- `);
232
- }
233
- function migrateAdminDb(db) {
234
- const current = db.query("PRAGMA user_version;").get()?.user_version ?? 0;
235
- if (current >= 5) return;
236
- if (current < 1) migrateV1(db);
237
- if (current < 2) db.run(`
238
- ALTER TABLE request_log ADD COLUMN user_id TEXT;
239
- ALTER TABLE request_log ADD COLUMN safety_identifier TEXT;
240
- ALTER TABLE request_log ADD COLUMN prompt_cache_key TEXT;
241
- ALTER TABLE request_log ADD COLUMN initiator TEXT;
242
- ALTER TABLE request_log ADD COLUMN upstream_request_id TEXT;
243
-
244
- PRAGMA user_version = 2;
245
- `);
246
- if (current < 3) db.run(`
247
- CREATE INDEX IF NOT EXISTS idx_request_log_session_finished
248
- ON request_log(
249
- prompt_cache_key,
250
- safety_identifier,
251
- finished_at_ms DESC
252
- )
253
- WHERE finished_at_ms IS NOT NULL
254
- AND tokens_input IS NOT NULL;
255
-
256
- PRAGMA user_version = 3;
257
- `);
258
- if (current < 4) db.run(`
259
- CREATE INDEX IF NOT EXISTS idx_request_log_session_finished_by_client_model
260
- ON request_log(
261
- prompt_cache_key,
262
- safety_identifier,
263
- client_model,
264
- finished_at_ms DESC
265
- )
266
- WHERE finished_at_ms IS NOT NULL
267
- AND tokens_input IS NOT NULL;
268
-
269
- PRAGMA user_version = 4;
270
- `);
271
- if (current < 5) db.run(`
272
- ALTER TABLE request_log ADD COLUMN affinity_hit INTEGER;
273
- ALTER TABLE request_log ADD COLUMN affinity_cache_key TEXT;
274
-
275
- PRAGMA user_version = 5;
276
- `);
277
- }
278
-
279
- //#endregion
280
- //#region src/lib/request-history.ts
281
- const DEFAULT_RETENTION_DAYS = 14;
282
- const DEFAULT_MAX_ROWS = 2e5;
283
- const INSERT_WARN_THROTTLE_MS = 3e4;
284
- let lastInsertWarnAtMs = 0;
285
- let suppressedInsertWarnCount = 0;
286
- function warnInsertFailure(error) {
287
- const now = Date.now();
288
- if (now - lastInsertWarnAtMs < INSERT_WARN_THROTTLE_MS) {
289
- suppressedInsertWarnCount++;
290
- return;
291
- }
292
- const suppressed = suppressedInsertWarnCount;
293
- suppressedInsertWarnCount = 0;
294
- lastInsertWarnAtMs = now;
295
- const suffix = suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : "";
296
- consola.warn(`Failed to insert request log${suffix}`, error);
297
- }
298
- function toDbNull(value) {
299
- return value === void 0 ? null : value;
300
- }
301
- function toDbBool(value) {
302
- if (value === true) return 1;
303
- if (value === false) return 0;
304
- return null;
305
- }
306
- function getClientIpInfo(c) {
307
- const cf = c.req.header("cf-connecting-ip");
308
- if (cf) return {
309
- ip: cf.trim(),
310
- source: "cf-connecting-ip"
311
- };
312
- const xff = c.req.header("x-forwarded-for");
313
- if (xff) {
314
- const first = xff.split(",")[0]?.trim();
315
- if (first) return {
316
- ip: first,
317
- source: "x-forwarded-for"
318
- };
319
- }
320
- const xri = c.req.header("x-real-ip");
321
- if (xri) return {
322
- ip: xri.trim(),
323
- source: "x-real-ip"
324
- };
325
- return {};
326
- }
327
- function normalizeChatCompletionsUsage(usage) {
328
- if (!usage) return {};
329
- const cached = usage.prompt_tokens_details?.cached_tokens ?? 0;
330
- const prompt = usage.prompt_tokens;
331
- const completion = usage.completion_tokens;
332
- const total = usage.total_tokens;
333
- return {
334
- tokensCachedInput: cached,
335
- tokensInput: Math.max(0, prompt - cached),
336
- tokensOutput: completion,
337
- tokensTotal: total,
338
- usageJson: JSON.stringify(usage)
339
- };
340
- }
341
- function normalizeResponsesUsage(usage) {
342
- if (!usage) return {};
343
- const cached = usage.input_tokens_details?.cached_tokens ?? 0;
344
- const input = usage.input_tokens;
345
- const output = usage.output_tokens ?? 0;
346
- const total = usage.total_tokens;
347
- return {
348
- tokensCachedInput: cached,
349
- tokensInput: Math.max(0, input - cached),
350
- tokensOutput: output,
351
- tokensTotal: total,
352
- usageJson: JSON.stringify(usage)
353
- };
354
- }
355
- function normalizeMessagesUsage(usage) {
356
- if (!usage) return {};
357
- const cached = usage.cache_read_input_tokens ?? 0;
358
- const input = usage.input_tokens;
359
- const output = usage.output_tokens;
360
- const hasInput = typeof input === "number";
361
- const hasOutput = typeof output === "number";
362
- return {
363
- tokensCachedInput: cached,
364
- tokensInput: hasInput ? Math.max(0, input - cached) : void 0,
365
- tokensOutput: hasOutput ? output : void 0,
366
- tokensTotal: hasInput || hasOutput ? (input ?? 0) + (output ?? 0) : void 0,
367
- usageJson: JSON.stringify(usage)
368
- };
369
- }
370
- function normalizeEmbeddingsUsage(usage) {
371
- if (!usage) return {};
372
- return {
373
- tokensCachedInput: 0,
374
- tokensInput: usage.prompt_tokens,
375
- tokensOutput: 0,
376
- tokensTotal: usage.total_tokens,
377
- usageJson: JSON.stringify(usage)
378
- };
379
- }
380
- var RequestHistoryStore = class {
381
- db;
382
- insertStmt;
383
- getByRequestIdStmt;
384
- getLastCompletedUsageBySessionStmt;
385
- constructor(db) {
386
- this.db = db;
387
- this.insertStmt = db.query(`
388
- INSERT INTO request_log (
389
- request_id,
390
- started_at_ms,
391
- finished_at_ms,
392
- duration_ms,
393
- ttfb_ms,
394
- method,
395
- path,
396
- upstream_endpoint,
397
- stream,
398
- account_id,
399
- account_type,
400
- cost_units,
401
- client_model,
402
- upstream_model,
403
- client_ip,
404
- client_ip_source,
405
- user_agent,
406
- user_id,
407
- safety_identifier,
408
- prompt_cache_key,
409
- initiator,
410
- upstream_request_id,
411
- tokens_input,
412
- tokens_output,
413
- tokens_total,
414
- tokens_cached_input,
415
- usage_json,
416
- premium_remaining_before,
417
- premium_remaining_after,
418
- premium_remaining_diff,
419
- premium_unlimited_before,
420
- premium_unlimited_after,
421
- http_status,
422
- error_name,
423
- error_status,
424
- error_message,
425
- selection_failure_reason,
426
- affinity_hit,
427
- affinity_cache_key
428
- ) VALUES (
429
- ?,?,?,?,?,?,?,?,
430
- ?,?,?,?,?,?,?,?,
431
- ?,?,?,?,?,?,?,?,
432
- ?,?,?,?,?,?,?,?,
433
- ?,?,?,?,?,?,?
434
- );
435
- `);
436
- this.getByRequestIdStmt = db.query("SELECT * FROM request_log WHERE request_id = ? LIMIT 1;");
437
- this.getLastCompletedUsageBySessionStmt = db.query(`
438
- SELECT
439
- tokens_input,
440
- tokens_output,
441
- tokens_total,
442
- tokens_cached_input
443
- FROM request_log
444
- WHERE prompt_cache_key = ?
445
- AND safety_identifier = ?
446
- AND client_model = ?
447
- AND finished_at_ms IS NOT NULL
448
- AND tokens_input IS NOT NULL
449
- ORDER BY finished_at_ms DESC
450
- LIMIT 1;
451
- `);
452
- }
453
- insert(record) {
454
- try {
455
- const args = [
456
- record.requestId,
457
- record.startedAtMs,
458
- toDbNull(record.finishedAtMs),
459
- toDbNull(record.durationMs),
460
- toDbNull(record.ttfbMs),
461
- record.method,
462
- record.path,
463
- toDbNull(record.upstreamEndpoint),
464
- record.stream ? 1 : 0,
465
- toDbNull(record.accountId),
466
- toDbNull(record.accountType),
467
- toDbNull(record.costUnits),
468
- toDbNull(record.clientModel),
469
- toDbNull(record.upstreamModel),
470
- toDbNull(record.clientIp),
471
- toDbNull(record.clientIpSource),
472
- toDbNull(record.userAgent),
473
- toDbNull(record.userId),
474
- toDbNull(record.safetyIdentifier),
475
- toDbNull(record.promptCacheKey),
476
- toDbNull(record.initiator),
477
- toDbNull(record.upstreamRequestId),
478
- toDbNull(record.tokensInput),
479
- toDbNull(record.tokensOutput),
480
- toDbNull(record.tokensTotal),
481
- toDbNull(record.tokensCachedInput),
482
- toDbNull(record.usageJson),
483
- toDbNull(record.premiumRemainingBefore),
484
- toDbNull(record.premiumRemainingAfter),
485
- toDbNull(record.premiumRemainingDiff),
486
- toDbBool(record.premiumUnlimitedBefore),
487
- toDbBool(record.premiumUnlimitedAfter),
488
- toDbNull(record.httpStatus),
489
- toDbNull(record.errorName),
490
- toDbNull(record.errorStatus),
491
- toDbNull(record.errorMessage),
492
- toDbNull(record.selectionFailureReason),
493
- toDbBool(record.affinityHit),
494
- toDbNull(record.affinityCacheKey)
495
- ];
496
- this.insertStmt.run(...args);
497
- } catch (error) {
498
- warnInsertFailure(error);
499
- }
500
- }
501
- getByRequestId(requestId) {
502
- try {
503
- return this.getByRequestIdStmt.get(requestId) ?? null;
504
- } catch (error) {
505
- consola.debug("Failed to fetch request log by request_id", error);
506
- return null;
507
- }
508
- }
509
- getLastCompletedUsageBySession(session) {
510
- if (!session.promptCacheKey || !session.safetyIdentifier || !session.clientModel) return null;
511
- try {
512
- const row = this.getLastCompletedUsageBySessionStmt.get(session.promptCacheKey, session.safetyIdentifier, session.clientModel);
513
- if (!row || row.tokens_input === null) return null;
514
- const tokensOutput = row.tokens_output === null ? void 0 : row.tokens_output;
515
- const tokensTotal = row.tokens_total === null ? void 0 : row.tokens_total;
516
- const tokensCachedInput = row.tokens_cached_input === null ? void 0 : row.tokens_cached_input;
517
- return {
518
- tokensInput: row.tokens_input,
519
- tokensOutput,
520
- tokensTotal,
521
- tokensCachedInput
522
- };
523
- } catch (error) {
524
- consola.debug("Failed to fetch last completed usage by session", error);
525
- return null;
526
- }
527
- }
528
- query(params) {
529
- const limit = Math.max(1, Math.min(params.limit, 200));
530
- const where = [];
531
- const values = [];
532
- if (params.cursorId !== void 0) {
533
- where.push("id < ?");
534
- values.push(params.cursorId);
535
- }
536
- if (params.accountId) {
537
- where.push("account_id = ?");
538
- values.push(params.accountId);
539
- }
540
- if (params.upstreamModel) {
541
- where.push("upstream_model = ?");
542
- values.push(params.upstreamModel);
543
- }
544
- if (params.clientModel) {
545
- where.push("client_model = ?");
546
- values.push(params.clientModel);
547
- }
548
- if (params.upstreamEndpoint) {
549
- where.push("upstream_endpoint = ?");
550
- values.push(params.upstreamEndpoint);
551
- }
552
- if (params.path) {
553
- where.push("path = ?");
554
- values.push(params.path);
555
- }
556
- if (params.status !== void 0) {
557
- where.push("http_status = ?");
558
- values.push(params.status);
559
- }
560
- if (params.hasError === true) where.push("http_status >= 400");
561
- if (params.hasError === false) where.push("http_status < 400");
562
- if (params.fromMs !== void 0) {
563
- where.push("started_at_ms >= ?");
564
- values.push(params.fromMs);
565
- }
566
- if (params.toMs !== void 0) {
567
- where.push("started_at_ms <= ?");
568
- values.push(params.toMs);
569
- }
570
- const sql = `
571
- SELECT *
572
- FROM request_log
573
- ${where.length > 0 ? `WHERE ${where.join(" AND ")}` : ""}
574
- ORDER BY id DESC
575
- LIMIT ?;
576
- `;
577
- const rows = this.db.query(sql).all(...values, limit + 1);
578
- const items = rows.slice(0, limit);
579
- const hasMore = rows.length > limit;
580
- return {
581
- items,
582
- nextCursorId: hasMore ? items.at(-1)?.id : void 0,
583
- hasMore
584
- };
585
- }
586
- getAccountStatsSince(sinceMs) {
587
- try {
588
- const rows = this.db.query(`
589
- SELECT
590
- account_id,
591
- COUNT(*) AS request_count,
592
- SUM(CASE WHEN http_status >= 400 THEN 1 ELSE 0 END) AS error_count,
593
- COALESCE(SUM(tokens_total), 0) AS tokens_total,
594
- COALESCE(AVG(duration_ms), 0) AS avg_duration_ms,
595
- COALESCE(MAX(started_at_ms), 0) AS last_request_at_ms
596
- FROM request_log
597
- WHERE started_at_ms >= ? AND account_id IS NOT NULL
598
- GROUP BY account_id;
599
- `).all(sinceMs);
600
- const map = {};
601
- for (const row of rows) map[row.account_id] = row;
602
- return map;
603
- } catch (error) {
604
- consola.debug("Failed to fetch account stats", error);
605
- return {};
606
- }
607
- }
608
- cleanupRetention(retentionDays = DEFAULT_RETENTION_DAYS, maxRows = DEFAULT_MAX_ROWS) {
609
- try {
610
- const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
611
- this.db.query("DELETE FROM request_log WHERE started_at_ms < ?;").run(cutoffMs);
612
- if (this.db.query("SELECT COUNT(*) AS c FROM request_log;").get().c <= maxRows) return;
613
- const offset = maxRows - 1;
614
- const thresholdId = this.db.query("SELECT id FROM request_log ORDER BY id DESC LIMIT 1 OFFSET ?;").get(offset)?.id;
615
- if (!thresholdId) return;
616
- this.db.query("DELETE FROM request_log WHERE id < ?;").run(thresholdId);
617
- } catch (error) {
618
- consola.debug("Failed to cleanup request_log retention", error);
619
- }
620
- }
621
- meta() {
622
- return {
623
- dbPath: getAdminDbPath(),
624
- userVersion: getAdminDbUserVersion(this.db),
625
- retentionDays: DEFAULT_RETENTION_DAYS,
626
- maxRows: DEFAULT_MAX_ROWS
627
- };
628
- }
629
- };
630
- const STORE_INIT_WARN_THROTTLE_MS = 3e4;
631
- const STORE_INIT_RETRY_DELAY_MS = 3e4;
632
- let lastStoreInitWarnAtMs = 0;
633
- let suppressedStoreInitWarnCount = 0;
634
- let nextStoreRetryAtMs = 0;
635
- function warnStoreInitFailure(error) {
636
- const now = Date.now();
637
- if (now - lastStoreInitWarnAtMs < STORE_INIT_WARN_THROTTLE_MS) {
638
- suppressedStoreInitWarnCount++;
639
- return;
640
- }
641
- const suppressed = suppressedStoreInitWarnCount;
642
- suppressedStoreInitWarnCount = 0;
643
- lastStoreInitWarnAtMs = now;
644
- const suffix = suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : "";
645
- consola.warn(`Request history store is disabled${suffix}`, error);
646
- }
647
- const disabledStore = {
648
- insert: () => {},
649
- getByRequestId: () => null,
650
- getLastCompletedUsageBySession: () => null,
651
- query: () => ({
652
- items: [],
653
- hasMore: false
654
- }),
655
- getAccountStatsSince: () => ({}),
656
- cleanupRetention: () => {},
657
- meta: () => ({
658
- dbPath: getAdminDbPath(),
659
- userVersion: 0,
660
- retentionDays: DEFAULT_RETENTION_DAYS,
661
- maxRows: DEFAULT_MAX_ROWS
662
- })
663
- };
664
- let sharedStore = null;
665
- let maintenanceStarted = false;
666
- function getRequestHistoryStore() {
667
- if (sharedStore) return sharedStore;
668
- const now = Date.now();
669
- if (now < nextStoreRetryAtMs) return disabledStore;
670
- try {
671
- sharedStore = new RequestHistoryStore(getAdminDb());
672
- if (!maintenanceStarted) {
673
- maintenanceStarted = true;
674
- sharedStore.cleanupRetention();
675
- setInterval(() => {
676
- sharedStore?.cleanupRetention();
677
- }, 1440 * 60 * 1e3);
678
- }
679
- return sharedStore;
680
- } catch (error) {
681
- nextStoreRetryAtMs = now + STORE_INIT_RETRY_DELAY_MS;
682
- warnStoreInitFailure(error);
683
- return disabledStore;
684
- }
685
- }
686
- function extractResponsesUsageFromStreamEvent(event) {
687
- if (event.type === "response.completed" || event.type === "response.incomplete") return normalizeResponsesUsage(event.response.usage);
688
- if (event.type === "response.failed") return normalizeResponsesUsage(event.response.usage);
689
- return {};
690
- }
691
- function extractResponsesUsageFromResult(result) {
692
- return normalizeResponsesUsage(result.usage);
693
- }
694
-
695
123
  //#endregion
696
124
  //#region src/routes/admin-api/auth-sessions.ts
697
125
  function buildOauthUrls(enterpriseDomain) {
@@ -812,6 +240,7 @@ var AuthSessionManager = class {
812
240
  });
813
241
  }
814
242
  if (!this.getLiveSession(sessionId)) return;
243
+ await accountsManager.reloadRegistryNow();
815
244
  this.completeSession(sessionId, accountId);
816
245
  } catch (error) {
817
246
  if (session.abortController.signal.aborted) return;
@@ -910,6 +339,7 @@ const CONFIG_KEYS = new Set([
910
339
  "auth",
911
340
  "extraPrompts",
912
341
  "smallModel",
342
+ "logLevel",
913
343
  "accountAffinity",
914
344
  "apiKey",
915
345
  "anthropicApiKey",
@@ -923,6 +353,7 @@ const CONFIG_KEYS = new Set([
923
353
  "compactUseSmallModel",
924
354
  "messageStartInputTokensFallback",
925
355
  "modelRefreshIntervalHours",
356
+ "sessionAffinityRetentionDays",
926
357
  "useMessagesApi",
927
358
  "useResponsesApiWebSearch"
928
359
  ]);
@@ -934,6 +365,12 @@ const REASONING_EFFORTS = new Set([
934
365
  "high",
935
366
  "xhigh"
936
367
  ]);
368
+ const LOG_LEVELS = new Set([
369
+ "error",
370
+ "warn",
371
+ "info",
372
+ "debug"
373
+ ]);
937
374
  const BLOCKED_KEYS = new Set([
938
375
  "__proto__",
939
376
  "constructor",
@@ -952,6 +389,13 @@ function parseOptionalString(value, field) {
952
389
  if (!trimmed) return { clear: true };
953
390
  return { value: trimmed };
954
391
  }
392
+ function parseOptionalLogLevel(value) {
393
+ const parsed = parseOptionalString(value, "logLevel");
394
+ if ("error" in parsed) return parsed;
395
+ if ("clear" in parsed) return parsed;
396
+ if (!LOG_LEVELS.has(parsed.value)) return { error: `logLevel must be one of: ${[...LOG_LEVELS].join(", ")}` };
397
+ return { value: parsed.value };
398
+ }
955
399
  function parseOptionalBoolean(value, field) {
956
400
  if (value === null || value === void 0) return { clear: true };
957
401
  if (typeof value !== "boolean") return { error: `${field} must be a boolean` };
@@ -1001,13 +445,20 @@ const PROVIDER_MODEL_CONFIG_KEYS = new Set([
1001
445
  "topP",
1002
446
  "topK"
1003
447
  ]);
1004
- const PROVIDER_CONFIG_KEYS = new Set([
448
+ const PROVIDER_CONFIG_FIELDS = [
1005
449
  "type",
1006
450
  "enabled",
1007
451
  "baseUrl",
1008
452
  "apiKey",
1009
- "models"
1010
- ]);
453
+ "authType",
454
+ "models",
455
+ "adjustInputTokens"
456
+ ];
457
+ const PROVIDER_AUTH_TYPES = ["authorization", "x-api-key"];
458
+ const PROVIDER_CONFIG_KEYS = new Set(PROVIDER_CONFIG_FIELDS);
459
+ function isProviderAuthType(value) {
460
+ return PROVIDER_AUTH_TYPES.includes(value);
461
+ }
1011
462
  function validateAllowedObjectKeys(value, field, allowed) {
1012
463
  for (const key of Object.keys(value)) if (!allowed.has(key)) return `${field}.${key} is not supported`;
1013
464
  }
@@ -1087,12 +538,27 @@ function applyProviderApiKey(provider, value, field) {
1087
538
  if ("error" in parsed) return parsed.error;
1088
539
  if ("value" in parsed) provider.apiKey = parsed.value;
1089
540
  }
541
+ function applyProviderAuthType(provider, value, field) {
542
+ if (!Object.hasOwn(value, "authType")) return void 0;
543
+ const parsed = parseOptionalString(value.authType, `${field}.authType`);
544
+ if ("error" in parsed) return parsed.error;
545
+ if ("value" in parsed) {
546
+ if (!isProviderAuthType(parsed.value)) return `${field}.authType must be one of: ${PROVIDER_AUTH_TYPES.map((item) => `"${item}"`).join(", ")}`;
547
+ provider.authType = parsed.value;
548
+ }
549
+ }
1090
550
  function applyProviderModels(provider, value, field) {
1091
551
  if (!Object.hasOwn(value, "models")) return void 0;
1092
552
  const parsed = parseProviderModelsRecord(value.models, `${field}.models`);
1093
553
  if ("error" in parsed) return parsed.error;
1094
554
  if ("value" in parsed) provider.models = parsed.value;
1095
555
  }
556
+ function applyProviderAdjustInputTokens(provider, value, field) {
557
+ if (!Object.hasOwn(value, "adjustInputTokens")) return void 0;
558
+ const parsed = parseOptionalBoolean(value.adjustInputTokens, `${field}.adjustInputTokens`);
559
+ if ("error" in parsed) return parsed.error;
560
+ if ("value" in parsed) provider.adjustInputTokens = parsed.value;
561
+ }
1096
562
  function parseProviderConfig(value, field) {
1097
563
  if (value === null || value === void 0) return { error: `${field} must be an object` };
1098
564
  if (!isPlainObject(value)) return { error: `${field} must be an object` };
@@ -1107,8 +573,12 @@ function parseProviderConfig(value, field) {
1107
573
  if (baseUrlError) return { error: baseUrlError };
1108
574
  const apiKeyError = applyProviderApiKey(provider, value, field);
1109
575
  if (apiKeyError) return { error: apiKeyError };
576
+ const authTypeError = applyProviderAuthType(provider, value, field);
577
+ if (authTypeError) return { error: authTypeError };
1110
578
  const modelsError = applyProviderModels(provider, value, field);
1111
579
  if (modelsError) return { error: modelsError };
580
+ const adjustInputTokensError = applyProviderAdjustInputTokens(provider, value, field);
581
+ if (adjustInputTokensError) return { error: adjustInputTokensError };
1112
582
  return { value: provider };
1113
583
  }
1114
584
  function parseProviders(value) {
@@ -1205,6 +675,15 @@ function applyAuthConfig(next, value) {
1205
675
  }
1206
676
  next.auth = parsed.value;
1207
677
  }
678
+ function applyLogLevel(next, value) {
679
+ const parsed = parseOptionalLogLevel(value);
680
+ if ("error" in parsed) return parsed.error;
681
+ if ("clear" in parsed) {
682
+ next.logLevel = void 0;
683
+ return;
684
+ }
685
+ next.logLevel = parsed.value;
686
+ }
1208
687
  function applyOptionalBoolean(next, key, value) {
1209
688
  const parsed = parseOptionalBoolean(value, key);
1210
689
  if ("error" in parsed) return parsed.error;
@@ -1272,6 +751,7 @@ const CONFIG_PATCH_HANDLERS = {
1272
751
  auth: applyAuthConfig,
1273
752
  extraPrompts: applyExtraPrompts,
1274
753
  smallModel: (next, value) => applyOptionalString(next, "smallModel", value),
754
+ logLevel: applyLogLevel,
1275
755
  accountAffinity: (next, value) => applyOptionalBoolean(next, "accountAffinity", value),
1276
756
  apiKey: (next, value) => applyOptionalString(next, "apiKey", value),
1277
757
  anthropicApiKey: (next, value) => applyOptionalString(next, "anthropicApiKey", value),
@@ -1285,6 +765,7 @@ const CONFIG_PATCH_HANDLERS = {
1285
765
  compactUseSmallModel: (next, value) => applyOptionalBoolean(next, "compactUseSmallModel", value),
1286
766
  messageStartInputTokensFallback: (next, value) => applyOptionalBoolean(next, "messageStartInputTokensFallback", value),
1287
767
  modelRefreshIntervalHours: (next, value) => applyOptionalNumber(next, "modelRefreshIntervalHours", value),
768
+ sessionAffinityRetentionDays: (next, value) => applyOptionalNumber(next, "sessionAffinityRetentionDays", value),
1288
769
  useMessagesApi: (next, value) => applyOptionalBoolean(next, "useMessagesApi", value),
1289
770
  useResponsesApiWebSearch: (next, value) => applyOptionalBoolean(next, "useResponsesApiWebSearch", value)
1290
771
  };
@@ -1367,6 +848,7 @@ adminApiRoutes.post("/config", async (c) => {
1367
848
  const merged = mergeConfigWithDefaults();
1368
849
  accountsManager.setAccountAffinityEnabled(isAccountAffinityEnabled());
1369
850
  accountsManager.setModelsRefreshIntervalMs(getModelRefreshIntervalMs());
851
+ applySharedSessionAffinityRetention();
1370
852
  return c.json({
1371
853
  ...merged,
1372
854
  _configPath: PATHS.CONFIG_PATH
@@ -1515,7 +997,8 @@ adminApiRoutes.get("/accounts", async (c) => {
1515
997
  remaining: s.remaining,
1516
998
  unlimited: s.unlimited,
1517
999
  failed: s.failed,
1518
- failureReason: s.failureReason
1000
+ failureReason: s.failureReason,
1001
+ enabled: s.enabled
1519
1002
  },
1520
1003
  stats
1521
1004
  };
@@ -1575,11 +1058,7 @@ adminApiRoutes.post("/accounts/auth/start", async (c) => {
1575
1058
  });
1576
1059
  const enterpriseDomainRaw = payload.enterpriseDomain;
1577
1060
  let enterpriseDomain;
1578
- if (accountType === "enterprise" && typeof enterpriseDomainRaw === "string") enterpriseDomain = enterpriseDomainRaw.trim();
1579
- if (accountType === "enterprise" && !enterpriseDomain) return jsonError(c, 400, {
1580
- message: "enterpriseDomain is required for enterprise accounts.",
1581
- type: "bad_request"
1582
- });
1061
+ if (accountType === "enterprise" && typeof enterpriseDomainRaw === "string") enterpriseDomain = enterpriseDomainRaw.trim() || void 0;
1583
1062
  try {
1584
1063
  const result = await authSessionManager.startAuth({
1585
1064
  accountType,
@@ -1610,6 +1089,40 @@ adminApiRoutes.post("/accounts/auth/cancel/:sessionId", (c) => {
1610
1089
  });
1611
1090
  return c.json({ cancelled: true });
1612
1091
  });
1092
+ adminApiRoutes.patch("/accounts/:id", async (c) => {
1093
+ const accountId = c.req.param("id");
1094
+ let payload;
1095
+ try {
1096
+ payload = await c.req.json();
1097
+ } catch {
1098
+ return jsonError(c, 400, {
1099
+ message: "Invalid JSON body.",
1100
+ type: "bad_request"
1101
+ });
1102
+ }
1103
+ if (typeof payload !== "object" || payload === null || Array.isArray(payload) || typeof payload.enabled !== "boolean") return jsonError(c, 400, {
1104
+ message: "Request body must contain { enabled: boolean }.",
1105
+ type: "bad_request"
1106
+ });
1107
+ const enabled = payload.enabled;
1108
+ try {
1109
+ const registry = await loadRegistry();
1110
+ const entry = registry.accounts.find((a) => a.id === accountId);
1111
+ if (!entry) return jsonError(c, 404, {
1112
+ message: "Account not found.",
1113
+ type: "not_found"
1114
+ });
1115
+ entry.enabled = enabled;
1116
+ await saveRegistry(registry);
1117
+ await accountsManager.reloadRegistryNow();
1118
+ return c.json({ success: true });
1119
+ } catch (error) {
1120
+ return jsonError(c, 500, {
1121
+ message: `Failed to update account: ${error instanceof Error ? error.message : String(error)}`,
1122
+ type: "internal_error"
1123
+ });
1124
+ }
1125
+ });
1613
1126
  adminApiRoutes.delete("/accounts/:id", async (c) => {
1614
1127
  const accountId = c.req.param("id");
1615
1128
  try {
@@ -1623,6 +1136,7 @@ adminApiRoutes.delete("/accounts/:id", async (c) => {
1623
1136
  } catch (error) {
1624
1137
  console.error(`Account ${accountId} deleted but token cleanup failed.`, error);
1625
1138
  }
1139
+ await accountsManager.reloadRegistryNow();
1626
1140
  return c.json({
1627
1141
  deleted: true,
1628
1142
  accountId
@@ -1646,10 +1160,6 @@ adminApiRoutes.post("/accounts/:id/reauth", async (c) => {
1646
1160
  const resolvedEnterpriseDomain = (await getAccountClientIdentityByLoginAndApp(accountId, oauthApp))?.enterpriseDomain;
1647
1161
  let enterpriseDomain;
1648
1162
  if (resolvedEnterpriseDomain && resolvedEnterpriseDomain !== DEFAULT_IDENTITY_ENTERPRISE_DOMAIN) enterpriseDomain = resolvedEnterpriseDomain;
1649
- if (account.accountType === "enterprise" && !enterpriseDomain) return jsonError(c, 400, {
1650
- message: "Cannot re-authenticate enterprise account: enterprise domain could not be resolved from stored identity.",
1651
- type: "bad_request"
1652
- });
1653
1163
  const result = await authSessionManager.startAuth({
1654
1164
  accountType: account.accountType,
1655
1165
  enterpriseDomain,
@@ -1663,6 +1173,70 @@ adminApiRoutes.post("/accounts/:id/reauth", async (c) => {
1663
1173
  });
1664
1174
  }
1665
1175
  });
1176
+ adminApiRoutes.get("/stats/premium-daily", (c) => {
1177
+ const p = new URL(c.req.url, "http://local").searchParams;
1178
+ const from = p.get("from") || void 0;
1179
+ const to = p.get("to") || void 0;
1180
+ const accountId = p.get("account_id") || void 0;
1181
+ const granularity = p.get("granularity") === "hour" ? "hour" : "day";
1182
+ const now = /* @__PURE__ */ new Date();
1183
+ const todayStr = toLocalDateString(now.getTime());
1184
+ const resolvedFrom = from || toLocalDateString(now.getTime() - 10080 * 60 * 1e3);
1185
+ const resolvedTo = to || todayStr;
1186
+ function parseLocalDate(dateStr) {
1187
+ const [y, m, d] = dateStr.split("-").map(Number);
1188
+ return new Date(y, m - 1, d);
1189
+ }
1190
+ if (granularity === "hour") {
1191
+ const fromDate = parseLocalDate(resolvedFrom);
1192
+ if (parseLocalDate(resolvedTo).getTime() - fromDate.getTime() + 1440 * 60 * 1e3 > 2880 * 60 * 1e3) return jsonError(c, 400, {
1193
+ message: "Hourly granularity is only supported for ranges up to 48 hours.",
1194
+ type: "bad_request"
1195
+ });
1196
+ }
1197
+ const statsStore = getStatsStore();
1198
+ if (!statsStore) return c.json({
1199
+ daily: [],
1200
+ by_account: [],
1201
+ range: {
1202
+ from: resolvedFrom,
1203
+ to: resolvedTo,
1204
+ granularity
1205
+ }
1206
+ });
1207
+ if (granularity === "hour") {
1208
+ const fromMs = parseLocalDate(resolvedFrom).getTime();
1209
+ const toMs = parseLocalDate(resolvedTo).getTime() + 86399999;
1210
+ const result$1 = statsStore.getHourlyPremiumStats({
1211
+ fromMs,
1212
+ toMs,
1213
+ accountId
1214
+ });
1215
+ return c.json({
1216
+ daily: result$1.daily,
1217
+ by_account: result$1.byAccount,
1218
+ range: {
1219
+ from: resolvedFrom,
1220
+ to: resolvedTo,
1221
+ granularity
1222
+ }
1223
+ });
1224
+ }
1225
+ const result = statsStore.getDailyPremiumStats({
1226
+ from: resolvedFrom,
1227
+ to: resolvedTo,
1228
+ accountId
1229
+ });
1230
+ return c.json({
1231
+ daily: result.daily,
1232
+ by_account: result.byAccount,
1233
+ range: {
1234
+ from: resolvedFrom,
1235
+ to: resolvedTo,
1236
+ granularity
1237
+ }
1238
+ });
1239
+ });
1666
1240
 
1667
1241
  //#endregion
1668
1242
  //#region src/routes/admin/route.ts
@@ -2332,39 +1906,122 @@ function toAccountContext(account) {
2332
1906
  clientSessionId: account.clientSessionId
2333
1907
  };
2334
1908
  }
1909
+ const OWNERSHIP_MISMATCH_PATTERN = /does not belong to this connection/i;
1910
+ const UUID_PATTERN = /\b[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\b/gi;
1911
+ const OPAQUE_ID_PATTERN = /\b(?:msg|resp|chatcmpl|out|toolu|call|item)_[\w-]+\b/g;
1912
+ const UPSTREAM_ERROR_MAX_LENGTH = 1e3;
1913
+ const UPSTREAM_ERROR_READ_FAILED_SENTINEL = "[upstream body read failed]";
1914
+ function sanitizeUpstreamErrorMessage(value) {
1915
+ return truncate(value.trim().replaceAll(UUID_PATTERN, "<uuid>").replaceAll(OPAQUE_ID_PATTERN, "<opaque_id>"), UPSTREAM_ERROR_MAX_LENGTH);
1916
+ }
1917
+ function readErrorField(value) {
1918
+ return typeof value === "string" ? value : void 0;
1919
+ }
1920
+ function formatUpstreamErrorBody(payload) {
1921
+ if (typeof payload === "string") {
1922
+ const text = payload.trim();
1923
+ return text.length > 0 ? text : void 0;
1924
+ }
1925
+ if (!payload || typeof payload !== "object") return;
1926
+ const root = payload;
1927
+ const message = readErrorField(root.error?.message) ?? readErrorField(root.message);
1928
+ const code = readErrorField(root.error?.code) ?? readErrorField(root.code);
1929
+ if (message && code) return `${message} [code:${code}]`;
1930
+ return message ?? (code ? `[code:${code}]` : void 0);
1931
+ }
1932
+ async function extractUpstreamErrorMessageRaw(error) {
1933
+ if (!(error instanceof HTTPError)) return { upstreamErrorMessageReadFailed: false };
1934
+ try {
1935
+ const bodyText = await error.response.clone().text();
1936
+ if (!bodyText) return { upstreamErrorMessageReadFailed: false };
1937
+ let candidate;
1938
+ try {
1939
+ candidate = formatUpstreamErrorBody(JSON.parse(bodyText));
1940
+ } catch {
1941
+ candidate = bodyText;
1942
+ }
1943
+ if (!candidate) return { upstreamErrorMessageReadFailed: false };
1944
+ const sanitized = sanitizeUpstreamErrorMessage(candidate);
1945
+ return {
1946
+ upstreamErrorMessageRaw: sanitized.length > 0 ? sanitized : void 0,
1947
+ upstreamErrorMessageReadFailed: false
1948
+ };
1949
+ } catch (readError) {
1950
+ consola.warn("Failed to read upstream HTTP error response body:", {
1951
+ status: error.response.status,
1952
+ readError
1953
+ });
1954
+ return { upstreamErrorMessageReadFailed: true };
1955
+ }
1956
+ }
2335
1957
  function extractErrorDetails(error) {
2336
1958
  const errorName = error instanceof Error ? error.name : "Error";
2337
1959
  const errorMessage = error instanceof Error ? truncate(error.message) : truncate(String(error));
2338
1960
  const errorStatus = error instanceof HTTPError ? error.response.status : void 0;
1961
+ const httpStatus = errorStatus ?? 500;
1962
+ const unauthorized = errorStatus === 401;
2339
1963
  return {
2340
- httpStatus: errorStatus ?? 500,
1964
+ httpStatus,
2341
1965
  errorName,
2342
1966
  errorStatus,
2343
1967
  errorMessage,
2344
- unauthorized: errorStatus === 401
1968
+ unauthorized,
1969
+ ownershipMismatch: unauthorized && OWNERSHIP_MISMATCH_PATTERN.test(errorMessage)
1970
+ };
1971
+ }
1972
+ async function extractErrorObservability(error) {
1973
+ const details = extractErrorDetails(error);
1974
+ const { upstreamErrorMessageRaw, upstreamErrorMessageReadFailed } = await extractUpstreamErrorMessageRaw(error);
1975
+ const observableUpstreamErrorMessageRaw = upstreamErrorMessageRaw ?? (upstreamErrorMessageReadFailed ? UPSTREAM_ERROR_READ_FAILED_SENTINEL : void 0);
1976
+ return {
1977
+ ...details,
1978
+ ownershipMismatch: details.ownershipMismatch || details.unauthorized && OWNERSHIP_MISMATCH_PATTERN.test(upstreamErrorMessageRaw ?? ""),
1979
+ upstreamErrorMessageRaw: observableUpstreamErrorMessageRaw,
1980
+ upstreamErrorMessageReadFailed
2345
1981
  };
2346
1982
  }
1983
+ function getUserVisibleErrorMessage(details) {
1984
+ if (details.upstreamErrorMessageReadFailed) return details.errorMessage;
1985
+ return details.upstreamErrorMessageRaw ?? details.errorMessage;
1986
+ }
1987
+ /**
1988
+ * Returns true when the 401 indicates a genuine auth/token failure
1989
+ * (not an ownership mismatch) and the account should be marked failed.
1990
+ */
1991
+ function shouldMarkAccountFailed(details) {
1992
+ return details.unauthorized && !details.ownershipMismatch && details.upstreamErrorMessageReadFailed !== true;
1993
+ }
2347
1994
 
2348
1995
  //#endregion
2349
1996
  //#region src/lib/logger.ts
2350
1997
  const LOG_RETENTION_MS = 10080 * 60 * 1e3;
2351
1998
  const CLEANUP_INTERVAL_MS = 1440 * 60 * 1e3;
2352
- const LOG_DIR = path.join(PATHS.APP_DIR, "logs");
2353
1999
  const FLUSH_INTERVAL_MS = 1e3;
2354
2000
  const MAX_BUFFER_SIZE = 100;
2001
+ const FILE_LOG_LEVEL_PRIORITY = {
2002
+ error: 0,
2003
+ warn: 1,
2004
+ info: 2,
2005
+ debug: 3
2006
+ };
2007
+ let logDir = path.join(PATHS.APP_DIR, "logs");
2008
+ let testLogLevelOverride;
2355
2009
  const logStreams = /* @__PURE__ */ new Map();
2356
2010
  const logBuffers = /* @__PURE__ */ new Map();
2357
2011
  let runtimeInitialized = false;
2358
2012
  let flushInterval;
2359
2013
  let cleanupInterval;
2014
+ let exitHandler;
2015
+ let sigintHandler;
2016
+ let sigtermHandler;
2360
2017
  const ensureLogDirectory = () => {
2361
- if (!fs$1.existsSync(LOG_DIR)) fs$1.mkdirSync(LOG_DIR, { recursive: true });
2018
+ if (!fs$1.existsSync(logDir)) fs$1.mkdirSync(logDir, { recursive: true });
2362
2019
  };
2363
2020
  const cleanupOldLogs = () => {
2364
- if (!fs$1.existsSync(LOG_DIR)) return;
2021
+ if (!fs$1.existsSync(logDir)) return;
2365
2022
  const now = Date.now();
2366
- for (const entry of fs$1.readdirSync(LOG_DIR)) {
2367
- const filePath = path.join(LOG_DIR, entry);
2023
+ for (const entry of fs$1.readdirSync(logDir)) {
2024
+ const filePath = path.join(logDir, entry);
2368
2025
  let stats;
2369
2026
  try {
2370
2027
  stats = fs$1.statSync(filePath);
@@ -2387,6 +2044,14 @@ const sanitizeName = (name) => {
2387
2044
  const normalized = name.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replaceAll(/^-+|-+$/g, "");
2388
2045
  return normalized === "" ? "handler" : normalized;
2389
2046
  };
2047
+ const getHandlerLogFilePath = (name, date) => {
2048
+ const dateKey = [
2049
+ date.getFullYear(),
2050
+ String(date.getMonth() + 1).padStart(2, "0"),
2051
+ String(date.getDate()).padStart(2, "0")
2052
+ ].join("-");
2053
+ return path.join(logDir, `${sanitizeName(name)}-${dateKey}.log`);
2054
+ };
2390
2055
  const maybeUnref = (timer) => {
2391
2056
  timer.unref();
2392
2057
  };
@@ -2426,15 +2091,18 @@ const initializeLoggerRuntime = () => {
2426
2091
  maybeUnref(flushInterval);
2427
2092
  cleanupInterval = setInterval(cleanupOldLogs, CLEANUP_INTERVAL_MS);
2428
2093
  maybeUnref(cleanupInterval);
2429
- process.once("exit", cleanup);
2430
- process.once("SIGINT", () => {
2094
+ exitHandler = cleanup;
2095
+ sigintHandler = () => {
2431
2096
  cleanup();
2432
2097
  process.exit(0);
2433
- });
2434
- process.once("SIGTERM", () => {
2098
+ };
2099
+ sigtermHandler = () => {
2435
2100
  cleanup();
2436
2101
  process.exit(0);
2437
- });
2102
+ };
2103
+ process.once("exit", exitHandler);
2104
+ process.once("SIGINT", sigintHandler);
2105
+ process.once("SIGTERM", sigtermHandler);
2438
2106
  };
2439
2107
  const getLogStream = (filePath) => {
2440
2108
  initializeLoggerRuntime();
@@ -2458,8 +2126,21 @@ const appendLine = (filePath, line) => {
2458
2126
  buffer.push(line);
2459
2127
  if (buffer.length >= MAX_BUFFER_SIZE) flushBuffer(filePath);
2460
2128
  };
2129
+ const normalizeLogTypeToLevel = (type) => {
2130
+ switch (type) {
2131
+ case "error": return "error";
2132
+ case "warn": return "warn";
2133
+ case "debug": return "debug";
2134
+ default: return "info";
2135
+ }
2136
+ };
2137
+ const shouldWriteFileLog = (type, logLevel = resolveLogLevel()) => {
2138
+ return FILE_LOG_LEVEL_PRIORITY[normalizeLogTypeToLevel(type)] <= FILE_LOG_LEVEL_PRIORITY[logLevel];
2139
+ };
2140
+ const resolveLogLevel = () => testLogLevelOverride ?? getLogLevel();
2141
+ const isDebugFileLoggingEnabled = () => resolveLogLevel() === "debug";
2461
2142
  const debugLazy = (logger$7, factory) => {
2462
- if (!state.verbose) return;
2143
+ if (!isDebugFileLoggingEnabled()) return;
2463
2144
  logger$7.debug(...factory());
2464
2145
  };
2465
2146
  const debugJson = (logger$7, label, value) => {
@@ -2468,18 +2149,31 @@ const debugJson = (logger$7, label, value) => {
2468
2149
  const debugJsonTail = (logger$7, label, { value, tailLength = 400 }) => {
2469
2150
  debugLazy(logger$7, () => [label, JSON.stringify(value).slice(-tailLength)]);
2470
2151
  };
2152
+ const getConsolaLevel = () => {
2153
+ const logLevel = resolveLogLevel();
2154
+ switch (logLevel) {
2155
+ case "error": return 0;
2156
+ case "warn": return 1;
2157
+ case "info": return 2;
2158
+ case "debug": return 4;
2159
+ default: return logLevel;
2160
+ }
2161
+ };
2471
2162
  const createHandlerLogger = (name) => {
2472
- const sanitizedName = sanitizeName(name);
2473
2163
  const instance = consola.withTag(name);
2474
- if (state.verbose) instance.level = 5;
2164
+ Object.defineProperty(instance, "level", {
2165
+ get: getConsolaLevel,
2166
+ configurable: true
2167
+ });
2475
2168
  instance.setReporters([]);
2476
2169
  instance.addReporter({ log(logObj) {
2170
+ const fileLogLevel = resolveLogLevel();
2171
+ if (!shouldWriteFileLog(logObj.type, fileLogLevel)) return;
2477
2172
  initializeLoggerRuntime();
2478
2173
  const traceId = requestContext.getStore()?.traceId;
2479
2174
  const date = logObj.date;
2480
- const dateKey = date.toLocaleDateString("sv-SE");
2481
2175
  const timestamp = date.toLocaleString("sv-SE", { hour12: false });
2482
- const filePath = path.join(LOG_DIR, `${sanitizedName}-${dateKey}.log`);
2176
+ const filePath = getHandlerLogFilePath(name, date);
2483
2177
  const message = formatArgs(logObj.args);
2484
2178
  const traceIdStr = traceId ? ` [${traceId}]` : "";
2485
2179
  appendLine(filePath, `[${timestamp}] [${logObj.type}] [${logObj.tag || name}]${traceIdStr}${message ? ` ${message}` : ""}`);
@@ -2728,6 +2422,13 @@ const getTokenCount = async (payload, model) => {
2728
2422
  };
2729
2423
  };
2730
2424
 
2425
+ //#endregion
2426
+ //#region src/lib/request-initiator.ts
2427
+ function resolveEffectiveInitiator(baseInitiator, options) {
2428
+ if (options.isCompact || options.isSubagent) return "agent";
2429
+ return baseInitiator;
2430
+ }
2431
+
2731
2432
  //#endregion
2732
2433
  //#region src/services/copilot/create-chat-completions.ts
2733
2434
  function isGpt5MiniFamily(modelId) {
@@ -2751,10 +2452,13 @@ const createChatCompletions = async (payload, account, options) => {
2751
2452
  const ctx = account ?? accountFromState();
2752
2453
  if (!ctx.copilotToken) throw new Error("Copilot token not found");
2753
2454
  const enableVision = payload.messages.some((x) => typeof x.content !== "string" && x.content?.some((x$1) => x$1.type === "image_url"));
2754
- const initiator = options?.initiator ?? getChatInitiator(payload.messages);
2455
+ const effectiveInitiator = resolveEffectiveInitiator(options?.initiator ?? getChatInitiator(payload.messages), {
2456
+ isCompact: options?.isCompact,
2457
+ isSubagent: Boolean(options?.subagentMarker)
2458
+ });
2755
2459
  const headers = {
2756
2460
  ...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
2757
- "x-initiator": options?.subagentMarker ? "agent" : initiator
2461
+ "x-initiator": effectiveInitiator
2758
2462
  };
2759
2463
  prepareInteractionHeaders(options?.sessionId, Boolean(options?.subagentMarker), headers);
2760
2464
  const upstreamPayload = applyDefaultReasoningEffort(payload);
@@ -2772,26 +2476,136 @@ const createChatCompletions = async (payload, account, options) => {
2772
2476
  return await response.json();
2773
2477
  };
2774
2478
 
2479
+ //#endregion
2480
+ //#region src/routes/chat-completions/support.ts
2481
+ const CHAT_COMPLETIONS_ENDPOINT$1 = "/chat/completions";
2482
+ const GPT_5_4_MODEL_ID = "gpt-5.4";
2483
+ const GPT_5_4_CHAT_COMPLETIONS_MESSAGE = "Please use `/v1/responses` or `/v1/messages` API";
2484
+ function buildRequestContext$1(c) {
2485
+ const requestId = randomUUID();
2486
+ const startedAtMs = Date.now();
2487
+ const method = c.req.raw.method;
2488
+ const path$2 = new URL(c.req.url, "http://local").pathname;
2489
+ const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
2490
+ return {
2491
+ requestId,
2492
+ startedAtMs,
2493
+ method,
2494
+ path: path$2,
2495
+ clientIp,
2496
+ clientIpSource,
2497
+ userAgent: c.req.header("user-agent") ?? void 0
2498
+ };
2499
+ }
2500
+ function insertRequestLog$2(store, request, record) {
2501
+ store.insert({
2502
+ requestId: request.requestId,
2503
+ startedAtMs: request.startedAtMs,
2504
+ method: request.method,
2505
+ path: request.path,
2506
+ clientIp: request.clientIp,
2507
+ clientIpSource: request.clientIpSource,
2508
+ userAgent: request.userAgent,
2509
+ userId: request.userId,
2510
+ safetyIdentifier: request.safetyIdentifier,
2511
+ promptCacheKey: request.promptCacheKey,
2512
+ initiator: request.initiator,
2513
+ upstreamRequestId: request.upstreamRequestId,
2514
+ affinityKeyUsed: request.affinityKeyUsed,
2515
+ affinityKeySource: request.affinityKeySource,
2516
+ selectionReason: request.selectionReason,
2517
+ affinityHit: request.affinityHit,
2518
+ affinityCacheKey: request.affinityCacheKey,
2519
+ ...record
2520
+ });
2521
+ }
2522
+ function recordUnsupportedChatCompletionsModel(store, params) {
2523
+ const { request, stream, clientModel, upstreamModel, accountId, accountType, costUnits, premiumRemainingBefore, premiumRemainingAfter, premiumUnlimitedBefore, premiumUnlimitedAfter } = params;
2524
+ const finishedAtMs = Date.now();
2525
+ let premiumRemainingDiff;
2526
+ if (premiumRemainingBefore !== void 0 && premiumRemainingAfter !== void 0) premiumRemainingDiff = premiumRemainingAfter - premiumRemainingBefore;
2527
+ insertRequestLog$2(store, request, {
2528
+ finishedAtMs,
2529
+ durationMs: finishedAtMs - request.startedAtMs,
2530
+ upstreamEndpoint: CHAT_COMPLETIONS_ENDPOINT$1,
2531
+ stream,
2532
+ accountId,
2533
+ accountType,
2534
+ costUnits,
2535
+ clientModel,
2536
+ upstreamModel,
2537
+ premiumRemainingBefore,
2538
+ premiumRemainingAfter,
2539
+ premiumRemainingDiff,
2540
+ premiumUnlimitedBefore,
2541
+ premiumUnlimitedAfter,
2542
+ httpStatus: 400,
2543
+ errorName: "invalid_request_error",
2544
+ errorMessage: GPT_5_4_CHAT_COMPLETIONS_MESSAGE
2545
+ });
2546
+ }
2547
+ function unsupportedChatCompletionsModelResponse(c) {
2548
+ return c.json({ error: {
2549
+ message: GPT_5_4_CHAT_COMPLETIONS_MESSAGE,
2550
+ type: "invalid_request_error"
2551
+ } }, 400);
2552
+ }
2553
+ function getSelectionFailureStatus(reason) {
2554
+ if (reason === "MODEL_NOT_SUPPORTED") return 400;
2555
+ if (reason === "NO_ACCOUNTS") return 503;
2556
+ return 429;
2557
+ }
2558
+ function recordSelectionFailure$2(store, params) {
2559
+ const { request, stream, clientModel, reason } = params;
2560
+ const finishedAtMs = Date.now();
2561
+ insertRequestLog$2(store, request, {
2562
+ finishedAtMs,
2563
+ durationMs: finishedAtMs - request.startedAtMs,
2564
+ upstreamEndpoint: CHAT_COMPLETIONS_ENDPOINT$1,
2565
+ stream,
2566
+ clientModel,
2567
+ httpStatus: getSelectionFailureStatus(reason),
2568
+ selectionFailureReason: reason
2569
+ });
2570
+ }
2571
+ function selectionFailureResponse$2(c, params) {
2572
+ const { clientModel, reason } = params;
2573
+ if (reason === "MODEL_NOT_SUPPORTED") return c.json({ error: {
2574
+ message: `Model "${clientModel}" is not available for any configured account.`,
2575
+ type: "invalid_request_error"
2576
+ } }, 400);
2577
+ if (reason === "NO_ACCOUNTS") return c.json({ error: {
2578
+ message: "No enabled Copilot accounts are configured. Add or re-enable an account.",
2579
+ type: "service_unavailable_error"
2580
+ } }, 503);
2581
+ return c.json({ error: {
2582
+ message: "All accounts have exhausted their quota. Please wait for quota refresh or add additional accounts.",
2583
+ type: "rate_limit_error"
2584
+ } }, 429);
2585
+ }
2586
+
2775
2587
  //#endregion
2776
2588
  //#region src/routes/chat-completions/handler.ts
2777
2589
  const logger$6 = createHandlerLogger("chat-completions-handler");
2778
- const CHAT_COMPLETIONS_ENDPOINT$1 = "/chat/completions";
2779
- async function handleCompletion$1(c) {
2780
- await checkRateLimit(state);
2781
- const store = getRequestHistoryStore();
2782
- const request = buildRequestContext$1(c);
2783
- const payload = await c.req.json();
2784
- const clientModel = payload.model;
2785
- const streamRequested = Boolean(payload.stream);
2786
- const initiator = getChatInitiator(payload.messages);
2787
- const userId = payload.user ?? void 0;
2788
- const { safetyIdentifier, sessionId: promptCacheKey } = parseUserIdMetadata(userId);
2789
- const normalizedSafetyIdentifier = safetyIdentifier ?? void 0;
2790
- const normalizedPromptCacheKey = promptCacheKey ?? void 0;
2791
- request.userId = userId;
2792
- request.safetyIdentifier = normalizedSafetyIdentifier;
2793
- request.promptCacheKey = normalizedPromptCacheKey;
2794
- request.initiator = initiator;
2590
+ function buildChatCompletionCandidates(clientModel) {
2591
+ return [{
2592
+ modelId: clientModel,
2593
+ endpoint: CHAT_COMPLETIONS_ENDPOINT$1
2594
+ }];
2595
+ }
2596
+ function isUnsupportedChatCompletionsModel(modelId) {
2597
+ return resolveModelAlias(modelId).toLowerCase() === GPT_5_4_MODEL_ID;
2598
+ }
2599
+ function maybeRejectChatCompletionsClientModel(c, store, params) {
2600
+ const { request, clientModel, streamRequested } = params;
2601
+ if (isUnsupportedChatCompletionsModel(clientModel)) {
2602
+ recordUnsupportedChatCompletionsModel(store, {
2603
+ request,
2604
+ clientModel,
2605
+ stream: streamRequested
2606
+ });
2607
+ return unsupportedChatCompletionsModelResponse(c);
2608
+ }
2795
2609
  if (getAliasTargetSet().has(clientModel.toLowerCase())) {
2796
2610
  recordSelectionFailure$2(store, {
2797
2611
  request,
@@ -2804,36 +2618,60 @@ async function handleCompletion$1(c) {
2804
2618
  reason: "MODEL_NOT_SUPPORTED"
2805
2619
  });
2806
2620
  }
2807
- debugJsonTail(logger$6, "Request payload:", {
2808
- value: payload,
2809
- tailLength: 400
2621
+ return null;
2622
+ }
2623
+ async function handleCompletion$1(c) {
2624
+ await checkRateLimit(state);
2625
+ const store = getRequestHistoryStore();
2626
+ const request = buildRequestContext$1(c);
2627
+ const payload = await c.req.json();
2628
+ const clientModel = payload.model;
2629
+ const streamRequested = Boolean(payload.stream);
2630
+ const normalizedPromptCacheKey = applyChatRequestMetadata(request, payload, getChatInitiator(payload.messages));
2631
+ const blockedResponse = maybeRejectChatCompletionsClientModel(c, store, {
2632
+ request,
2633
+ clientModel,
2634
+ streamRequested
2810
2635
  });
2811
- const upstreamRequestId = generateRequestIdFromPayload(payload, normalizedPromptCacheKey);
2812
- const selection = await accountsManager.selectAccountForRequest([{
2813
- modelId: clientModel,
2814
- endpoint: CHAT_COMPLETIONS_ENDPOINT$1
2815
- }], { requestId: upstreamRequestId });
2816
- if (!selection.ok) {
2817
- recordSelectionFailure$2(store, {
2636
+ if (blockedResponse) return blockedResponse;
2637
+ const selectionResult = await selectChatCompletionAccount({
2638
+ c,
2639
+ store,
2640
+ request,
2641
+ payload,
2642
+ clientModel,
2643
+ streamRequested,
2644
+ normalizedPromptCacheKey
2645
+ });
2646
+ if (selectionResult instanceof Response) return selectionResult;
2647
+ const { headerSessionId, selection, upstreamRequestId } = selectionResult;
2648
+ const { account, reservation, selectedModel } = selection;
2649
+ request.affinityHit = selection.affinityHit;
2650
+ request.affinityCacheKey = selection.affinityCacheKey;
2651
+ request.selectionReason = selection.selectionReason;
2652
+ const premiumRemainingBefore = account.premiumRemaining;
2653
+ const premiumUnlimitedBefore = account.unlimited;
2654
+ if (selectedModel.id === GPT_5_4_MODEL_ID) {
2655
+ await accountsManager.finalizeQuota(account, reservation);
2656
+ recordUnsupportedChatCompletionsModel(store, {
2818
2657
  request,
2819
2658
  clientModel,
2820
2659
  stream: streamRequested,
2821
- reason: selection.reason
2822
- });
2823
- return selectionFailureResponse$2(c, {
2824
- clientModel,
2825
- reason: selection.reason
2660
+ upstreamModel: selectedModel.id,
2661
+ accountId: account.id,
2662
+ accountType: account.accountType,
2663
+ costUnits: selection.costUnits,
2664
+ premiumRemainingBefore,
2665
+ premiumRemainingAfter: account.premiumRemaining,
2666
+ premiumUnlimitedBefore,
2667
+ premiumUnlimitedAfter: account.unlimited
2826
2668
  });
2827
- }
2828
- const { account, selectedModel } = selection;
2829
- request.affinityHit = selection.affinityHit;
2830
- request.affinityCacheKey = selection.affinityCacheKey;
2669
+ return unsupportedChatCompletionsModelResponse(c);
2670
+ }
2831
2671
  const upstreamPayload = {
2832
2672
  ...payload,
2833
2673
  model: selectedModel.id
2834
2674
  };
2835
- const premiumRemainingBefore = account.premiumRemaining;
2836
- const premiumUnlimitedBefore = account.unlimited;
2837
2675
  await logTokenCountForRequest({
2838
2676
  payload: upstreamPayload,
2839
2677
  selectedModel
@@ -2841,7 +2679,7 @@ async function handleCompletion$1(c) {
2841
2679
  if (state.manualApprove) await awaitApproval();
2842
2680
  const payloadWithMaxTokens = applyDefaultMaxTokens(upstreamPayload, selectedModel);
2843
2681
  const accountCtx = toAccountContext(account);
2844
- const upstreamSessionId = getUUID(upstreamRequestId);
2682
+ const upstreamSessionId = getUUID(normalizedPromptCacheKey ?? headerSessionId ?? upstreamRequestId);
2845
2683
  request.upstreamRequestId = upstreamRequestId;
2846
2684
  request.upstreamSessionId = upstreamSessionId;
2847
2685
  if (streamRequested) return handleStreamingRequest({
@@ -2867,64 +2705,60 @@ async function handleCompletion$1(c) {
2867
2705
  premiumUnlimitedBefore
2868
2706
  });
2869
2707
  }
2870
- function buildRequestContext$1(c) {
2871
- const requestId = randomUUID();
2872
- const startedAtMs = Date.now();
2873
- const method = c.req.raw.method;
2874
- const path$2 = new URL(c.req.url, "http://local").pathname;
2875
- const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
2876
- return {
2877
- requestId,
2878
- startedAtMs,
2879
- method,
2880
- path: path$2,
2881
- clientIp,
2882
- clientIpSource,
2883
- userAgent: c.req.header("user-agent") ?? void 0
2884
- };
2708
+ function applyChatRequestMetadata(request, payload, initiator) {
2709
+ const userId = payload.user ?? void 0;
2710
+ const { safetyIdentifier, sessionId: promptCacheKey } = parseUserIdMetadata(userId);
2711
+ const normalizedPromptCacheKey = promptCacheKey ?? void 0;
2712
+ request.userId = userId;
2713
+ request.safetyIdentifier = safetyIdentifier ?? void 0;
2714
+ request.promptCacheKey = normalizedPromptCacheKey;
2715
+ request.initiator = initiator;
2716
+ return normalizedPromptCacheKey;
2885
2717
  }
2886
- function insertRequestLog$2(store, request, record) {
2887
- store.insert({
2888
- requestId: request.requestId,
2889
- startedAtMs: request.startedAtMs,
2890
- method: request.method,
2891
- path: request.path,
2892
- clientIp: request.clientIp,
2893
- clientIpSource: request.clientIpSource,
2894
- userAgent: request.userAgent,
2895
- userId: request.userId,
2896
- safetyIdentifier: request.safetyIdentifier,
2897
- promptCacheKey: request.promptCacheKey,
2898
- initiator: request.initiator,
2899
- upstreamRequestId: request.upstreamRequestId,
2900
- affinityHit: request.affinityHit,
2901
- affinityCacheKey: request.affinityCacheKey,
2902
- ...record
2903
- });
2718
+ async function writeChatCompletionsStreamError(stream, message) {
2719
+ try {
2720
+ await stream.writeSSE({ data: JSON.stringify({ error: {
2721
+ message,
2722
+ type: "error"
2723
+ } }) });
2724
+ await stream.writeSSE({ data: "[DONE]" });
2725
+ } catch (streamError) {
2726
+ logger$6.warn("Failed to write chat completions stream error event:", streamError);
2727
+ }
2904
2728
  }
2905
- function recordSelectionFailure$2(store, params) {
2906
- const { request, stream, clientModel, reason } = params;
2907
- const finishedAtMs = Date.now();
2908
- insertRequestLog$2(store, request, {
2909
- finishedAtMs,
2910
- durationMs: finishedAtMs - request.startedAtMs,
2911
- upstreamEndpoint: CHAT_COMPLETIONS_ENDPOINT$1,
2912
- stream,
2913
- clientModel,
2914
- httpStatus: reason === "MODEL_NOT_SUPPORTED" ? 400 : 429,
2915
- selectionFailureReason: reason
2729
+ async function selectChatCompletionAccount(params) {
2730
+ const { c, store, request, payload, clientModel, streamRequested, normalizedPromptCacheKey } = params;
2731
+ debugJsonTail(logger$6, "Request payload:", {
2732
+ value: payload,
2733
+ tailLength: 400
2916
2734
  });
2917
- }
2918
- function selectionFailureResponse$2(c, params) {
2919
- const { clientModel, reason } = params;
2920
- if (reason === "MODEL_NOT_SUPPORTED") return c.json({ error: {
2921
- message: `Model "${clientModel}" is not available for any configured account.`,
2922
- type: "invalid_request_error"
2923
- } }, 400);
2924
- return c.json({ error: {
2925
- message: "All accounts have exhausted their quota. Please wait for quota refresh or add additional accounts.",
2926
- type: "rate_limit_error"
2927
- } }, 429);
2735
+ const upstreamRequestId = generateRequestIdFromPayload(payload, normalizedPromptCacheKey);
2736
+ const headerSessionId = c.req.header("x-session-id") ?? null;
2737
+ const affinityKey = resolveAffinityKey({
2738
+ metadataSessionId: normalizedPromptCacheKey,
2739
+ headerSessionId,
2740
+ upstreamRequestId
2741
+ });
2742
+ request.affinityKeyUsed = affinityKey.affinityKeyUsed;
2743
+ request.affinityKeySource = affinityKey.affinityKeySource;
2744
+ const selection = await accountsManager.selectAccountForRequest(buildChatCompletionCandidates(clientModel), { requestId: affinityKey.requestId });
2745
+ if (!selection.ok) {
2746
+ recordSelectionFailure$2(store, {
2747
+ request,
2748
+ clientModel,
2749
+ stream: streamRequested,
2750
+ reason: selection.reason
2751
+ });
2752
+ return selectionFailureResponse$2(c, {
2753
+ clientModel,
2754
+ reason: selection.reason
2755
+ });
2756
+ }
2757
+ return {
2758
+ headerSessionId,
2759
+ selection,
2760
+ upstreamRequestId
2761
+ };
2928
2762
  }
2929
2763
  async function logTokenCountForRequest(params) {
2930
2764
  try {
@@ -2989,8 +2823,8 @@ async function handleUpstreamCreateError$1(params) {
2989
2823
  const { store, request, selection, clientModel, premiumRemainingBefore, premiumUnlimitedBefore, error } = params;
2990
2824
  const { account, reservation, selectedModel, endpoint, costUnits } = selection;
2991
2825
  const finishedAtMs = Date.now();
2992
- const details = extractErrorDetails(error);
2993
- if (details.unauthorized) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
2826
+ const details = await extractErrorObservability(error);
2827
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
2994
2828
  await accountsManager.finalizeQuota(account, reservation);
2995
2829
  const premiumRemainingAfter = account.premiumRemaining;
2996
2830
  const premiumUnlimitedAfter = account.unlimited;
@@ -3012,7 +2846,8 @@ async function handleUpstreamCreateError$1(params) {
3012
2846
  httpStatus: details.httpStatus,
3013
2847
  errorName: details.errorName,
3014
2848
  errorStatus: details.errorStatus,
3015
- errorMessage: details.errorMessage
2849
+ errorMessage: details.errorMessage,
2850
+ upstreamErrorMessageRaw: details.upstreamErrorMessageRaw
3016
2851
  });
3017
2852
  throw error;
3018
2853
  }
@@ -3024,16 +2859,18 @@ async function handleNonStreamingUpstreamResponse(params) {
3024
2859
  let errorName;
3025
2860
  let errorStatus;
3026
2861
  let errorMessage;
2862
+ let upstreamErrorMessageRaw;
3027
2863
  const finishedAtMs = Date.now();
3028
2864
  try {
3029
2865
  debugJson(logger$6, "Non-streaming response:", response);
3030
2866
  return c.json(response);
3031
2867
  } catch (error) {
3032
- const details = extractErrorDetails(error);
2868
+ const details = await extractErrorObservability(error);
3033
2869
  httpStatus = details.httpStatus;
3034
2870
  errorName = details.errorName;
3035
2871
  errorStatus = details.errorStatus;
3036
2872
  errorMessage = details.errorMessage;
2873
+ upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
3037
2874
  throw error;
3038
2875
  } finally {
3039
2876
  await accountsManager.finalizeQuota(account, reservation);
@@ -3058,7 +2895,8 @@ async function handleNonStreamingUpstreamResponse(params) {
3058
2895
  httpStatus,
3059
2896
  errorName,
3060
2897
  errorStatus,
3061
- errorMessage
2898
+ errorMessage,
2899
+ upstreamErrorMessageRaw
3062
2900
  });
3063
2901
  }
3064
2902
  }
@@ -3070,6 +2908,7 @@ async function streamChatCompletionsAndLog$1(params) {
3070
2908
  let errorName;
3071
2909
  let errorStatus;
3072
2910
  let errorMessage;
2911
+ let upstreamErrorMessageRaw;
3073
2912
  try {
3074
2913
  for await (const rawChunk of response) {
3075
2914
  const chunk = rawChunk;
@@ -3080,11 +2919,14 @@ async function streamChatCompletionsAndLog$1(params) {
3080
2919
  await stream.writeSSE(chunk);
3081
2920
  }
3082
2921
  } catch (error) {
3083
- const details = extractErrorDetails(error);
2922
+ const details = await extractErrorObservability(error);
3084
2923
  errorName = details.errorName;
3085
2924
  errorStatus = details.errorStatus;
3086
2925
  errorMessage = details.errorMessage;
2926
+ upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
3087
2927
  logger$6.warn("Streaming error:", error);
2928
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
2929
+ await writeChatCompletionsStreamError(stream, getUserVisibleErrorMessage(details));
3088
2930
  } finally {
3089
2931
  const finishedAtMs = Date.now();
3090
2932
  await accountsManager.finalizeQuota(account, reservation);
@@ -3110,18 +2952,29 @@ async function streamChatCompletionsAndLog$1(params) {
3110
2952
  httpStatus: errorStatus ?? (errorName ? 500 : 200),
3111
2953
  errorName,
3112
2954
  errorStatus,
3113
- errorMessage
2955
+ errorMessage,
2956
+ upstreamErrorMessageRaw
3114
2957
  });
3115
2958
  }
3116
2959
  }
3117
2960
  async function extractUsageFromChunk(chunk) {
3118
- const data = typeof chunk.data === "string" ? chunk.data : await chunk.data;
2961
+ let data;
2962
+ try {
2963
+ data = typeof chunk.data === "string" ? chunk.data : await chunk.data;
2964
+ } catch (error) {
2965
+ logger$6.warn("Failed to read chat completions usage chunk:", error);
2966
+ return;
2967
+ }
3119
2968
  if (!data || data === "[DONE]") return;
3120
2969
  try {
3121
2970
  const parsed = JSON.parse(data);
3122
2971
  if (!parsed.usage) return void 0;
3123
2972
  return normalizeChatCompletionsUsage(parsed.usage);
3124
- } catch {
2973
+ } catch (error) {
2974
+ logger$6.warn("Failed to parse chat completions usage chunk:", {
2975
+ error,
2976
+ data
2977
+ });
3125
2978
  return;
3126
2979
  }
3127
2980
  }
@@ -3133,31 +2986,28 @@ async function handleNonStreamingRequest(params) {
3133
2986
  let errorName;
3134
2987
  let errorStatus;
3135
2988
  let errorMessage;
2989
+ let upstreamErrorMessageRaw;
3136
2990
  let finishedAtMs;
3137
2991
  try {
3138
2992
  const response = await createChatCompletions(payload, accountCtx, {
3139
2993
  upstreamRequestId: request.upstreamRequestId,
3140
2994
  sessionId: request.upstreamSessionId
3141
2995
  });
2996
+ if (!isNonStreaming$1(response)) throw new Error("Upstream returned a stream unexpectedly");
3142
2997
  selection.confirmAffinity?.();
3143
2998
  finishedAtMs = Date.now();
3144
- if (!isNonStreaming$1(response)) {
3145
- logger$6.debug("Unexpected streaming response");
3146
- return streamSSE(c, async (stream) => {
3147
- for await (const chunk of response) await stream.writeSSE(chunk);
3148
- });
3149
- }
3150
2999
  usage = normalizeChatCompletionsUsage(response.usage);
3151
3000
  debugJson(logger$6, "Non-streaming response:", response);
3152
3001
  return c.json(response);
3153
3002
  } catch (error) {
3154
3003
  finishedAtMs = Date.now();
3155
- const details = extractErrorDetails(error);
3004
+ const details = await extractErrorObservability(error);
3156
3005
  httpStatus = details.httpStatus;
3157
3006
  errorName = details.errorName;
3158
3007
  errorStatus = details.errorStatus;
3159
3008
  errorMessage = details.errorMessage;
3160
- if (details.unauthorized) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
3009
+ upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
3010
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
3161
3011
  throw error;
3162
3012
  } finally {
3163
3013
  const finishedAtMsFinal = finishedAtMs ?? Date.now();
@@ -3183,7 +3033,8 @@ async function handleNonStreamingRequest(params) {
3183
3033
  httpStatus,
3184
3034
  errorName,
3185
3035
  errorStatus,
3186
- errorMessage
3036
+ errorMessage,
3037
+ upstreamErrorMessageRaw
3187
3038
  });
3188
3039
  }
3189
3040
  }
@@ -3311,6 +3162,7 @@ async function runEmbeddingsWithAccount({ c, store, ctx, payload, clientModel, s
3311
3162
  let errorName;
3312
3163
  let errorStatus;
3313
3164
  let errorMessage;
3165
+ let upstreamErrorMessageRaw;
3314
3166
  let finishedAtMs;
3315
3167
  try {
3316
3168
  const response = await createEmbeddings(payload, toAccountContext(account));
@@ -3319,12 +3171,13 @@ async function runEmbeddingsWithAccount({ c, store, ctx, payload, clientModel, s
3319
3171
  return c.json(response);
3320
3172
  } catch (error) {
3321
3173
  finishedAtMs = Date.now();
3322
- const details = extractErrorDetails(error);
3174
+ const details = await extractErrorObservability(error);
3323
3175
  httpStatus = details.httpStatus;
3324
3176
  errorName = details.errorName;
3325
3177
  errorStatus = details.errorStatus;
3326
3178
  errorMessage = details.errorMessage;
3327
- if (details.unauthorized) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
3179
+ upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
3180
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
3328
3181
  throw error;
3329
3182
  } finally {
3330
3183
  const finishedAtMsFinal = finishedAtMs ?? Date.now();
@@ -3357,22 +3210,23 @@ async function runEmbeddingsWithAccount({ c, store, ctx, payload, clientModel, s
3357
3210
  httpStatus,
3358
3211
  errorName,
3359
3212
  errorStatus,
3360
- errorMessage
3213
+ errorMessage,
3214
+ upstreamErrorMessageRaw
3361
3215
  });
3362
3216
  }
3363
3217
  }
3364
3218
 
3365
3219
  //#endregion
3366
3220
  //#region src/lib/models.ts
3221
+ const getAvailableModels = () => (accountsManager.getFirstAccountModels()?.data ?? []).filter((model) => model.model_picker_enabled || model.capabilities.type === "embeddings");
3367
3222
  const findEndpointModel = (sdkModelId) => {
3368
- const models = state.models?.data ?? [];
3223
+ const models = getAvailableModels();
3369
3224
  const exactMatch = models.find((m) => m.id === sdkModelId);
3370
3225
  if (exactMatch) return exactMatch;
3371
3226
  const normalized = _normalizeSdkModelId(sdkModelId);
3372
3227
  if (!normalized) return;
3373
3228
  const modelName = `claude-${normalized.family}-${normalized.version}`;
3374
- const model = models.find((m) => m.id === modelName);
3375
- if (model) return model;
3229
+ return models.find((m) => m.id === modelName);
3376
3230
  };
3377
3231
  /**
3378
3232
  * Normalizes an SDK model ID to extract the model family and version.
@@ -3578,7 +3432,7 @@ const isWarmupProbeRequest = (payload) => {
3578
3432
  return false;
3579
3433
  };
3580
3434
  const handleSelectionFailure = (context) => {
3581
- const { c, store, requestId, startedAtMs, method, path: path$2, streamRequested, clientModel, clientIp, clientIpSource, userAgent, userId, safetyIdentifier, promptCacheKey, initiator, selection } = context;
3435
+ const { c, store, requestId, startedAtMs, method, path: path$2, streamRequested, clientModel, clientIp, clientIpSource, userAgent, userId, safetyIdentifier, promptCacheKey, initiator, isSubagent, affinityKeyUsed, affinityKeySource, selectionReason, selection } = context;
3582
3436
  const finishedAtMs = Date.now();
3583
3437
  store.insert({
3584
3438
  requestId,
@@ -3596,7 +3450,11 @@ const handleSelectionFailure = (context) => {
3596
3450
  safetyIdentifier,
3597
3451
  promptCacheKey,
3598
3452
  initiator,
3453
+ isSubagent,
3454
+ affinityKeyUsed,
3455
+ affinityKeySource,
3599
3456
  httpStatus: selection.reason === "MODEL_NOT_SUPPORTED" ? 400 : 429,
3457
+ selectionReason: selectionReason ?? selection.selectionReason,
3600
3458
  selectionFailureReason: selection.reason
3601
3459
  });
3602
3460
  if (selection.reason === "MODEL_NOT_SUPPORTED") return c.json({ error: {
@@ -3624,8 +3482,7 @@ const maybeBlockOriginalModelName = (context) => {
3624
3482
  const THINKING_TEXT = "Thinking...";
3625
3483
  function translateToOpenAI(payload) {
3626
3484
  const modelId = payload.model;
3627
- const model = state.models?.data.find((m) => m.id === modelId);
3628
- const thinkingBudget = getThinkingBudget(payload, model);
3485
+ const thinkingBudget = getThinkingBudget(payload, getAvailableModels().find((m) => m.id === modelId));
3629
3486
  return {
3630
3487
  model: modelId,
3631
3488
  messages: translateAnthropicMessagesToOpenAI(payload, modelId, thinkingBudget),
@@ -3921,9 +3778,13 @@ async function handleCountTokens(c) {
3921
3778
  const createResponses = async (payload, { vision, initiator, upstreamRequestId, subagentMarker, sessionId, isCompact }, account) => {
3922
3779
  const ctx = account ?? accountFromState();
3923
3780
  if (!ctx.copilotToken) throw new Error("Copilot token not found");
3781
+ const effectiveInitiator = resolveEffectiveInitiator(initiator, {
3782
+ isCompact,
3783
+ isSubagent: Boolean(subagentMarker)
3784
+ });
3924
3785
  const headers = {
3925
3786
  ...copilotHeaders(ctx, vision, upstreamRequestId),
3926
- "x-initiator": initiator
3787
+ "x-initiator": effectiveInitiator
3927
3788
  };
3928
3789
  prepareInteractionHeaders(sessionId, Boolean(subagentMarker), headers);
3929
3790
  prepareForCompact(headers, isCompact);
@@ -4848,6 +4709,44 @@ const getPayloadItems = (payload) => {
4848
4709
  if (Array.isArray(input)) result.push(...input);
4849
4710
  return result;
4850
4711
  };
4712
+ const useFunctionApplyPatch = (payload) => {
4713
+ if (!(getConfig().useFunctionApplyPatch ?? true)) return;
4714
+ if (Array.isArray(payload.tools)) {
4715
+ const toolsArr = payload.tools;
4716
+ for (let i = 0; i < toolsArr.length; i++) {
4717
+ const t = toolsArr[i];
4718
+ if (t.type === "custom" && t.name === "apply_patch") toolsArr[i] = {
4719
+ type: "function",
4720
+ name: t.name,
4721
+ description: "Use the `apply_patch` tool to edit files",
4722
+ parameters: {
4723
+ type: "object",
4724
+ properties: { input: {
4725
+ type: "string",
4726
+ description: "The entire contents of the apply_patch command"
4727
+ } },
4728
+ required: ["input"]
4729
+ },
4730
+ strict: false
4731
+ };
4732
+ }
4733
+ }
4734
+ };
4735
+ const removeWebSearchTool = (payload) => {
4736
+ if (!Array.isArray(payload.tools) || payload.tools.length === 0) return;
4737
+ payload.tools = payload.tools.filter((t) => {
4738
+ return t.type !== "web_search";
4739
+ });
4740
+ };
4741
+ function getStreamChunkFields(chunk) {
4742
+ const c = chunk;
4743
+ return {
4744
+ id: c.id,
4745
+ event: c.event,
4746
+ data: c.data
4747
+ };
4748
+ }
4749
+ const isAsyncIterable = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
4851
4750
  const containsVisionContent = (value) => {
4852
4751
  if (!value) return false;
4853
4752
  if (Array.isArray(value)) return value.some((entry) => containsVisionContent(entry));
@@ -4897,9 +4796,13 @@ const shouldUseMessageProxyHeaders = (payload) => {
4897
4796
  return Boolean(safetyIdentifier && sessionId);
4898
4797
  };
4899
4798
  const buildMessagesHeaders = ({ ctx, enableVision, initiator, options, payload }) => {
4799
+ const effectiveInitiator = resolveEffectiveInitiator(initiator, {
4800
+ isCompact: options?.isCompact,
4801
+ isSubagent: Boolean(options?.subagentMarker)
4802
+ });
4900
4803
  const headers = {
4901
4804
  ...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
4902
- "x-initiator": options?.subagentMarker ? "agent" : initiator
4805
+ "x-initiator": effectiveInitiator
4903
4806
  };
4904
4807
  prepareInteractionHeaders(options?.sessionId, Boolean(options?.subagentMarker), headers);
4905
4808
  prepareForCompact(headers, options?.isCompact);
@@ -5191,44 +5094,105 @@ function closeThinkingBlockIfOpen(state$1, events$1) {
5191
5094
  //#endregion
5192
5095
  //#region src/routes/messages/subagent-marker.ts
5193
5096
  const subagentMarkerPrefix = "__SUBAGENT_MARKER__";
5194
- const parseSubagentMarkerFromFirstUser = (payload) => {
5097
+ const subagentStartContextPrefix = "SubagentStart hook additional context:";
5098
+ const REMINDER_RE = /<system-reminder>([\s\S]*?)<\/system-reminder>/g;
5099
+ const NONE_INSPECTION = {
5100
+ kind: "none",
5101
+ marker: null
5102
+ };
5103
+ const INVALID_INSPECTION = {
5104
+ kind: "invalid",
5105
+ marker: null
5106
+ };
5107
+ const isSubagentMarker = (value) => {
5108
+ if (!value || typeof value !== "object") return false;
5109
+ const candidate = value;
5110
+ return typeof candidate.session_id === "string" && typeof candidate.agent_id === "string" && typeof candidate.agent_type === "string" && candidate.session_id.trim().length > 0 && candidate.agent_id.trim().length > 0 && candidate.agent_type.trim().length > 0;
5111
+ };
5112
+ const inspectSubagentMarkerFromFirstUser = (payload) => {
5195
5113
  const firstUserMessage = payload.messages.find((msg) => msg.role === "user" && Array.isArray(msg.content));
5196
- if (!firstUserMessage || !Array.isArray(firstUserMessage.content)) return null;
5114
+ if (!firstUserMessage || !Array.isArray(firstUserMessage.content)) return NONE_INSPECTION;
5115
+ let sawInvalidMarker = false;
5197
5116
  for (const block of firstUserMessage.content) {
5198
5117
  if (block.type !== "text") continue;
5199
- const marker = parseSubagentMarkerFromSystemReminder(block.text);
5200
- if (marker) return marker;
5201
- }
5202
- return null;
5203
- };
5204
- const parseSubagentMarkerFromSystemReminder = (text) => {
5205
- const startTag = "<system-reminder>";
5206
- const endTag = "</system-reminder>";
5207
- let searchFrom = 0;
5208
- while (true) {
5209
- const reminderStart = text.indexOf(startTag, searchFrom);
5210
- if (reminderStart === -1) break;
5211
- const contentStart = reminderStart + 17;
5212
- const reminderEnd = text.indexOf(endTag, contentStart);
5213
- if (reminderEnd === -1) break;
5214
- const reminderContent = text.slice(contentStart, reminderEnd);
5215
- const markerIndex = reminderContent.indexOf(subagentMarkerPrefix);
5216
- if (markerIndex === -1) {
5217
- searchFrom = reminderEnd + 18;
5218
- continue;
5118
+ const inspection = inspectSubagentMarkerFromSystemReminder(block.text);
5119
+ if (inspection.kind === "valid") return inspection;
5120
+ if (inspection.kind === "invalid") sawInvalidMarker = true;
5121
+ }
5122
+ return sawInvalidMarker ? INVALID_INSPECTION : NONE_INSPECTION;
5123
+ };
5124
+ const extractMarkerPayloadFromReminderLine = (line) => {
5125
+ const trimmedLine = line.trim();
5126
+ if (!trimmedLine) return null;
5127
+ let markerLine = trimmedLine;
5128
+ if (markerLine.startsWith(subagentStartContextPrefix)) markerLine = markerLine.slice(38).trimStart();
5129
+ if (!markerLine.startsWith(subagentMarkerPrefix)) return null;
5130
+ return markerLine.slice(19).trimStart();
5131
+ };
5132
+ const inspectSubagentMarkerFromSystemReminder = (text) => {
5133
+ let sawInvalidMarker = false;
5134
+ for (const [, content] of text.matchAll(REMINDER_RE)) {
5135
+ const lines = content.split(/\r?\n/);
5136
+ for (const line of lines) {
5137
+ const markerPayload = extractMarkerPayloadFromReminderLine(line);
5138
+ if (markerPayload === null) continue;
5139
+ if (!markerPayload.startsWith("{")) {
5140
+ sawInvalidMarker = true;
5141
+ continue;
5142
+ }
5143
+ const json = extractBalancedJson(markerPayload);
5144
+ if (!json) {
5145
+ sawInvalidMarker = true;
5146
+ continue;
5147
+ }
5148
+ try {
5149
+ const parsed = JSON.parse(json);
5150
+ if (!isSubagentMarker(parsed)) {
5151
+ sawInvalidMarker = true;
5152
+ continue;
5153
+ }
5154
+ return {
5155
+ kind: "valid",
5156
+ marker: parsed
5157
+ };
5158
+ } catch {
5159
+ sawInvalidMarker = true;
5160
+ }
5219
5161
  }
5220
- const markerJson = reminderContent.slice(markerIndex + 19).trim();
5221
- try {
5222
- const parsed = JSON.parse(markerJson);
5223
- if (!parsed.session_id || !parsed.agent_id || !parsed.agent_type) {
5224
- searchFrom = reminderEnd + 18;
5162
+ }
5163
+ return sawInvalidMarker ? INVALID_INSPECTION : NONE_INSPECTION;
5164
+ };
5165
+ /** Extract the first balanced `{...}` object from text that starts with `{`. */
5166
+ const extractBalancedJson = (text) => {
5167
+ let depth = 0;
5168
+ let inString = false;
5169
+ let escaped = false;
5170
+ for (let index = 0; index < text.length; index += 1) {
5171
+ const char = text[index];
5172
+ if (inString) {
5173
+ if (escaped) {
5174
+ escaped = false;
5225
5175
  continue;
5226
5176
  }
5227
- return parsed;
5228
- } catch {
5229
- searchFrom = reminderEnd + 18;
5177
+ if (char === "\\") {
5178
+ escaped = true;
5179
+ continue;
5180
+ }
5181
+ if (char === "\"") inString = false;
5182
+ continue;
5183
+ }
5184
+ if (char === "\"") {
5185
+ inString = true;
5230
5186
  continue;
5231
5187
  }
5188
+ if (char === "{") {
5189
+ depth += 1;
5190
+ continue;
5191
+ }
5192
+ if (char === "}") {
5193
+ depth -= 1;
5194
+ if (depth === 0) return text.slice(0, index + 1);
5195
+ }
5232
5196
  }
5233
5197
  return null;
5234
5198
  };
@@ -5250,13 +5214,18 @@ async function handleCompletion(c) {
5250
5214
  const userAgent = c.req.header("user-agent") ?? void 0;
5251
5215
  const anthropicPayload = await c.req.json();
5252
5216
  debugJson(logger$5, "Anthropic request payload:", anthropicPayload);
5253
- const subagentMarker = parseSubagentMarkerFromFirstUser(anthropicPayload);
5254
- const initiatorOverride = subagentMarker ? "agent" : void 0;
5217
+ const markerInspection = inspectSubagentMarkerFromFirstUser(anthropicPayload);
5218
+ const subagentMarker = markerInspection.kind === "valid" ? markerInspection.marker : null;
5219
+ const isSubagentRequest = subagentMarker !== null;
5220
+ const invalidSubagentMarkerSelectionReason = markerInspection.kind === "invalid" ? "subagent_marker_invalid_fallback" : void 0;
5255
5221
  if (subagentMarker) debugJson(logger$5, "Detected Subagent marker:", subagentMarker);
5256
5222
  const sessionId = getRootSessionId(anthropicPayload, c);
5257
5223
  logger$5.debug("Extracted session ID:", sessionId);
5224
+ const ownershipLookupSessionId = markerInspection.kind === "valid" ? normalizeStableSessionId(markerInspection.marker.session_id) : void 0;
5225
+ const ownershipWriteSessionId = markerInspection.kind === "none" ? sessionId : void 0;
5258
5226
  const anthropicBeta = c.req.header("anthropic-beta");
5259
5227
  const isCompact = isCompactRequest(anthropicPayload);
5228
+ const originalRequestModel = anthropicPayload.model;
5260
5229
  if (anthropicBeta && isWarmupProbeRequest(anthropicPayload)) anthropicPayload.model = getSmallModel();
5261
5230
  if (isCompact) {
5262
5231
  logger$5.debug("Is compact request:", isCompact);
@@ -5274,6 +5243,11 @@ async function handleCompletion(c) {
5274
5243
  const { safetyIdentifier, sessionId: promptCacheKey } = parseUserIdMetadata(userId);
5275
5244
  const normalizedSafetyIdentifier = safetyIdentifier ?? void 0;
5276
5245
  const normalizedPromptCacheKey = promptCacheKey ?? void 0;
5246
+ const openAIPayload = translateToOpenAI(anthropicPayload);
5247
+ const fallbackInitiator = resolveEffectiveInitiator(getChatInitiator(openAIPayload.messages), {
5248
+ isCompact,
5249
+ isSubagent: isSubagentRequest
5250
+ });
5277
5251
  const blockedResponse = maybeBlockOriginalModelName({
5278
5252
  c,
5279
5253
  store,
@@ -5289,13 +5263,14 @@ async function handleCompletion(c) {
5289
5263
  userId,
5290
5264
  safetyIdentifier: normalizedSafetyIdentifier,
5291
5265
  promptCacheKey: normalizedPromptCacheKey,
5292
- initiator: initiatorOverride
5266
+ initiator: fallbackInitiator,
5267
+ isSubagent: isSubagentRequest,
5268
+ selectionReason: invalidSubagentMarkerSelectionReason
5293
5269
  });
5294
5270
  if (blockedResponse) return blockedResponse;
5295
- const openAIPayload = translateToOpenAI(anthropicPayload);
5296
- const fallbackInitiator = initiatorOverride ?? getChatInitiator(openAIPayload.messages);
5297
5271
  const endpointModel = findEndpointModel(clientModel);
5298
5272
  const resolvedClientModel = endpointModel?.id ?? clientModel;
5273
+ const affinityModelId = clientModel !== originalRequestModel ? findEndpointModel(originalRequestModel)?.id ?? originalRequestModel : void 0;
5299
5274
  const useMessagesApi = isMessagesApiEnabled();
5300
5275
  const candidates = [];
5301
5276
  if (useMessagesApi) candidates.push({
@@ -5309,7 +5284,18 @@ async function handleCompletion(c) {
5309
5284
  modelId: endpointModel?.id ?? openAIPayload.model,
5310
5285
  endpoint: CHAT_COMPLETIONS_ENDPOINT
5311
5286
  });
5312
- const selection = await accountsManager.selectAccountForRequest(candidates, { requestId: upstreamRequestId });
5287
+ const affinityKey = resolveAffinityKey({
5288
+ metadataSessionId: promptCacheKey,
5289
+ headerSessionId: c.req.header("x-session-id") ?? null,
5290
+ upstreamRequestId
5291
+ });
5292
+ const selection = await accountsManager.selectAccountForRequest(candidates, {
5293
+ requestId: affinityKey.requestId,
5294
+ affinityModelId,
5295
+ ownershipLookupSessionId,
5296
+ ownershipWriteSessionId
5297
+ });
5298
+ const selectionReason = invalidSubagentMarkerSelectionReason ?? selection.selectionReason;
5313
5299
  if (!selection.ok) return handleSelectionFailure({
5314
5300
  c,
5315
5301
  store,
@@ -5326,6 +5312,10 @@ async function handleCompletion(c) {
5326
5312
  safetyIdentifier: normalizedSafetyIdentifier,
5327
5313
  promptCacheKey: normalizedPromptCacheKey,
5328
5314
  initiator: fallbackInitiator,
5315
+ isSubagent: isSubagentRequest,
5316
+ affinityKeyUsed: affinityKey.affinityKeyUsed,
5317
+ affinityKeySource: affinityKey.affinityKeySource,
5318
+ selectionReason,
5329
5319
  selection
5330
5320
  });
5331
5321
  const { account, reservation, selectedModel, endpoint, costUnits } = selection;
@@ -5346,6 +5336,7 @@ async function handleCompletion(c) {
5346
5336
  userId,
5347
5337
  safetyIdentifier: normalizedSafetyIdentifier,
5348
5338
  promptCacheKey: normalizedPromptCacheKey,
5339
+ isSubagent: isSubagentRequest,
5349
5340
  clientModel,
5350
5341
  account,
5351
5342
  reservation,
@@ -5356,14 +5347,17 @@ async function handleCompletion(c) {
5356
5347
  premiumRemainingBefore,
5357
5348
  premiumUnlimitedBefore,
5358
5349
  confirmAffinity: selection.confirmAffinity,
5350
+ confirmOwnership: selection.confirmOwnership,
5359
5351
  affinityHit: selection.affinityHit,
5360
- affinityCacheKey: selection.affinityCacheKey
5352
+ affinityCacheKey: selection.affinityCacheKey,
5353
+ affinityKeyUsed: affinityKey.affinityKeyUsed,
5354
+ affinityKeySource: affinityKey.affinityKeySource,
5355
+ selectionReason
5361
5356
  };
5362
5357
  if (endpoint === MESSAGES_ENDPOINT) return await handleWithMessagesApi({
5363
5358
  c,
5364
5359
  anthropicPayload,
5365
5360
  anthropicBetaHeader: anthropicBeta ?? void 0,
5366
- initiatorOverride,
5367
5361
  subagentMarker,
5368
5362
  sessionId,
5369
5363
  instr,
@@ -5374,7 +5368,6 @@ async function handleCompletion(c) {
5374
5368
  c,
5375
5369
  anthropicPayload,
5376
5370
  openAIPayload,
5377
- initiatorOverride,
5378
5371
  subagentMarker,
5379
5372
  sessionId,
5380
5373
  selectedModel,
@@ -5384,7 +5377,6 @@ async function handleCompletion(c) {
5384
5377
  return await handleWithChatCompletions({
5385
5378
  c,
5386
5379
  openAIPayload,
5387
- initiatorOverride,
5388
5380
  subagentMarker,
5389
5381
  sessionId,
5390
5382
  selectedModel,
@@ -5393,21 +5385,25 @@ async function handleCompletion(c) {
5393
5385
  });
5394
5386
  }
5395
5387
  const handleWithChatCompletions = async (params) => {
5396
- const { c, openAIPayload, initiatorOverride, subagentMarker, sessionId, selectedModel, instr, isCompact } = params;
5388
+ const { c, openAIPayload, subagentMarker, sessionId, selectedModel, instr, isCompact } = params;
5397
5389
  debugJson(logger$5, "Translated OpenAI request payload:", openAIPayload);
5398
5390
  const ctx = toAccountContext(instr.account);
5399
- const initiator = initiatorOverride ?? getChatInitiator(openAIPayload.messages);
5400
- instr.initiator = initiator;
5391
+ const effectiveInitiator = resolveEffectiveInitiator(getChatInitiator(openAIPayload.messages), {
5392
+ isCompact,
5393
+ isSubagent: Boolean(subagentMarker)
5394
+ });
5395
+ instr.initiator = effectiveInitiator;
5401
5396
  let response;
5402
5397
  try {
5403
5398
  response = await createChatCompletions(openAIPayload, ctx, {
5404
5399
  upstreamRequestId: instr.upstreamRequestId,
5405
- initiator,
5400
+ initiator: effectiveInitiator,
5406
5401
  subagentMarker,
5407
5402
  sessionId,
5408
5403
  isCompact
5409
5404
  });
5410
5405
  instr.confirmAffinity?.();
5406
+ instr.confirmOwnership?.();
5411
5407
  } catch (error) {
5412
5408
  return await handleChatCompletionsCreateError({
5413
5409
  error,
@@ -5437,26 +5433,30 @@ const handleWithChatCompletions = async (params) => {
5437
5433
  }));
5438
5434
  };
5439
5435
  const handleWithResponsesApi = async (params) => {
5440
- const { c, anthropicPayload, openAIPayload, initiatorOverride, subagentMarker, sessionId, selectedModel, instr, isCompact } = params;
5436
+ const { c, anthropicPayload, openAIPayload, subagentMarker, sessionId, selectedModel, instr, isCompact } = params;
5441
5437
  const responsesPayload = translateAnthropicMessagesToResponsesPayload(anthropicPayload, selectedModel.id);
5442
5438
  applyResponsesApiContextManagement(responsesPayload, selectedModel.capabilities.limits.max_prompt_tokens);
5443
5439
  compactInputByLatestCompaction(responsesPayload);
5444
5440
  debugJson(logger$5, "Translated Responses payload:", responsesPayload);
5445
5441
  const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
5446
- const resolvedInitiator = initiatorOverride ?? initiator;
5442
+ const effectiveInitiator = resolveEffectiveInitiator(initiator, {
5443
+ isCompact,
5444
+ isSubagent: Boolean(subagentMarker)
5445
+ });
5447
5446
  const ctx = toAccountContext(instr.account);
5448
- instr.initiator = resolvedInitiator;
5447
+ instr.initiator = effectiveInitiator;
5449
5448
  let response;
5450
5449
  try {
5451
5450
  response = await createResponses(responsesPayload, {
5452
5451
  vision,
5453
- initiator: resolvedInitiator,
5452
+ initiator: effectiveInitiator,
5454
5453
  upstreamRequestId: instr.upstreamRequestId,
5455
5454
  subagentMarker,
5456
5455
  sessionId,
5457
5456
  isCompact
5458
5457
  }, ctx);
5459
5458
  instr.confirmAffinity?.();
5459
+ instr.confirmOwnership?.();
5460
5460
  } catch (error) {
5461
5461
  return await handleResponsesCreateError({
5462
5462
  error,
@@ -5501,9 +5501,13 @@ function insertRequestLog$1(instr, record) {
5501
5501
  safetyIdentifier: instr.safetyIdentifier,
5502
5502
  promptCacheKey: instr.promptCacheKey,
5503
5503
  initiator: instr.initiator,
5504
+ isSubagent: instr.isSubagent,
5504
5505
  upstreamRequestId: instr.upstreamRequestId,
5505
5506
  affinityHit: instr.affinityHit,
5506
5507
  affinityCacheKey: instr.affinityCacheKey,
5508
+ affinityKeyUsed: instr.affinityKeyUsed,
5509
+ affinityKeySource: instr.affinityKeySource,
5510
+ selectionReason: instr.selectionReason,
5507
5511
  clientModel,
5508
5512
  upstreamEndpoint,
5509
5513
  accountId: account.id,
@@ -5527,8 +5531,8 @@ async function finalizeQuotaAndGetPremiumSnapshot(instr) {
5527
5531
  async function handleChatCompletionsCreateError(params) {
5528
5532
  const { error, instr, stream } = params;
5529
5533
  const finishedAtMs = Date.now();
5530
- const details = extractErrorDetails(error);
5531
- if (details.unauthorized) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5534
+ const details = await extractErrorObservability(error);
5535
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5532
5536
  const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
5533
5537
  insertRequestLog$1(instr, {
5534
5538
  finishedAtMs,
@@ -5540,7 +5544,8 @@ async function handleChatCompletionsCreateError(params) {
5540
5544
  httpStatus: details.httpStatus,
5541
5545
  errorName: details.errorName,
5542
5546
  errorStatus: details.errorStatus,
5543
- errorMessage: details.errorMessage
5547
+ errorMessage: details.errorMessage,
5548
+ upstreamErrorMessageRaw: details.upstreamErrorMessageRaw
5544
5549
  });
5545
5550
  throw error;
5546
5551
  }
@@ -5551,6 +5556,7 @@ async function handleChatCompletionsNonStreaming(params) {
5551
5556
  let errorName;
5552
5557
  let errorStatus;
5553
5558
  let errorMessage;
5559
+ let upstreamErrorMessageRaw;
5554
5560
  const finishedAtMs = Date.now();
5555
5561
  try {
5556
5562
  logger$5.debug("Non-streaming response from Copilot:", JSON.stringify(response));
@@ -5558,12 +5564,13 @@ async function handleChatCompletionsNonStreaming(params) {
5558
5564
  debugJson(logger$5, "Translated Anthropic response:", anthropicResponse);
5559
5565
  return c.json(anthropicResponse);
5560
5566
  } catch (error) {
5561
- const details = extractErrorDetails(error);
5567
+ const details = await extractErrorObservability(error);
5562
5568
  httpStatus = details.httpStatus;
5563
5569
  errorName = details.errorName;
5564
5570
  errorStatus = details.errorStatus;
5565
5571
  errorMessage = details.errorMessage;
5566
- if (details.unauthorized) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5572
+ upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
5573
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5567
5574
  throw error;
5568
5575
  } finally {
5569
5576
  const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
@@ -5578,7 +5585,8 @@ async function handleChatCompletionsNonStreaming(params) {
5578
5585
  httpStatus,
5579
5586
  errorName,
5580
5587
  errorStatus,
5581
- errorMessage
5588
+ errorMessage,
5589
+ upstreamErrorMessageRaw
5582
5590
  });
5583
5591
  }
5584
5592
  }
@@ -5589,6 +5597,7 @@ async function streamChatCompletionsAndLog(params) {
5589
5597
  let errorName;
5590
5598
  let errorStatus;
5591
5599
  let errorMessage;
5600
+ let upstreamErrorMessageRaw;
5592
5601
  const streamState = {
5593
5602
  messageStartSent: false,
5594
5603
  contentBlockIndex: 0,
@@ -5620,12 +5629,14 @@ async function streamChatCompletionsAndLog(params) {
5620
5629
  }
5621
5630
  }
5622
5631
  } catch (error) {
5623
- const details = extractErrorDetails(error);
5632
+ const details = await extractErrorObservability(error);
5624
5633
  errorName = details.errorName;
5625
5634
  errorStatus = details.errorStatus;
5626
5635
  errorMessage = details.errorMessage;
5636
+ upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
5627
5637
  logger$5.warn("Streaming error:", error);
5628
- if (details.unauthorized) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5638
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5639
+ await writeAnthropicStreamError(stream, getUserVisibleErrorMessage(details));
5629
5640
  } finally {
5630
5641
  const finishedAtMs = Date.now();
5631
5642
  const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
@@ -5641,15 +5652,16 @@ async function streamChatCompletionsAndLog(params) {
5641
5652
  httpStatus: errorStatus ?? (errorName ? 500 : 200),
5642
5653
  errorName,
5643
5654
  errorStatus,
5644
- errorMessage
5655
+ errorMessage,
5656
+ upstreamErrorMessageRaw
5645
5657
  });
5646
5658
  }
5647
5659
  }
5648
5660
  async function handleResponsesCreateError(params) {
5649
5661
  const { error, instr, stream } = params;
5650
5662
  const finishedAtMs = Date.now();
5651
- const details = extractErrorDetails(error);
5652
- if (details.unauthorized) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5663
+ const details = await extractErrorObservability(error);
5664
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5653
5665
  const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
5654
5666
  insertRequestLog$1(instr, {
5655
5667
  finishedAtMs,
@@ -5661,7 +5673,8 @@ async function handleResponsesCreateError(params) {
5661
5673
  httpStatus: details.httpStatus,
5662
5674
  errorName: details.errorName,
5663
5675
  errorStatus: details.errorStatus,
5664
- errorMessage: details.errorMessage
5676
+ errorMessage: details.errorMessage,
5677
+ upstreamErrorMessageRaw: details.upstreamErrorMessageRaw
5665
5678
  });
5666
5679
  throw error;
5667
5680
  }
@@ -5672,6 +5685,7 @@ async function handleResponsesNonStreaming(params) {
5672
5685
  let errorName;
5673
5686
  let errorStatus;
5674
5687
  let errorMessage;
5688
+ let upstreamErrorMessageRaw;
5675
5689
  const finishedAtMs = Date.now();
5676
5690
  try {
5677
5691
  usage = extractResponsesUsageFromResult(result);
@@ -5680,12 +5694,13 @@ async function handleResponsesNonStreaming(params) {
5680
5694
  debugJson(logger$5, "Translated Anthropic response:", anthropicResponse);
5681
5695
  return c.json(anthropicResponse);
5682
5696
  } catch (error) {
5683
- const details = extractErrorDetails(error);
5697
+ const details = await extractErrorObservability(error);
5684
5698
  httpStatus = details.httpStatus;
5685
5699
  errorName = details.errorName;
5686
5700
  errorStatus = details.errorStatus;
5687
5701
  errorMessage = details.errorMessage;
5688
- if (details.unauthorized) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5702
+ upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
5703
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5689
5704
  throw error;
5690
5705
  } finally {
5691
5706
  const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
@@ -5700,7 +5715,8 @@ async function handleResponsesNonStreaming(params) {
5700
5715
  httpStatus,
5701
5716
  errorName,
5702
5717
  errorStatus,
5703
- errorMessage
5718
+ errorMessage,
5719
+ upstreamErrorMessageRaw
5704
5720
  });
5705
5721
  }
5706
5722
  }
@@ -5716,6 +5732,17 @@ async function ensureResponsesStreamCompleted(params) {
5716
5732
  data: JSON.stringify(errorEvent)
5717
5733
  });
5718
5734
  }
5735
+ async function writeAnthropicStreamError(stream, message) {
5736
+ try {
5737
+ const errorEvent = buildErrorEvent(message);
5738
+ await stream.writeSSE({
5739
+ event: errorEvent.type,
5740
+ data: JSON.stringify(errorEvent)
5741
+ });
5742
+ } catch (streamError) {
5743
+ logger$5.warn("Failed to write Anthropic stream error event:", streamError);
5744
+ }
5745
+ }
5719
5746
  async function streamResponsesAndLog$1(params) {
5720
5747
  const { stream, response, instr, estimatedInputTokens, historicalUsage } = params;
5721
5748
  let ttfbMs;
@@ -5723,6 +5750,7 @@ async function streamResponsesAndLog$1(params) {
5723
5750
  let errorName;
5724
5751
  let errorStatus;
5725
5752
  let errorMessage;
5753
+ let upstreamErrorMessageRaw;
5726
5754
  const streamState = createResponsesStreamState();
5727
5755
  streamState.estimatedInputTokens = estimatedInputTokens;
5728
5756
  streamState.historicalInputTokens = historicalUsage?.tokensInput;
@@ -5767,12 +5795,14 @@ async function streamResponsesAndLog$1(params) {
5767
5795
  }
5768
5796
  });
5769
5797
  } catch (error) {
5770
- const details = extractErrorDetails(error);
5798
+ const details = await extractErrorObservability(error);
5771
5799
  errorName = details.errorName;
5772
5800
  errorStatus = details.errorStatus;
5773
5801
  errorMessage = details.errorMessage;
5802
+ upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
5774
5803
  logger$5.warn("Streaming error:", error);
5775
- if (details.unauthorized) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5804
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5805
+ await writeAnthropicStreamError(stream, getUserVisibleErrorMessage(details));
5776
5806
  } finally {
5777
5807
  const finishedAtMs = Date.now();
5778
5808
  const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
@@ -5788,15 +5818,16 @@ async function streamResponsesAndLog$1(params) {
5788
5818
  httpStatus: errorStatus ?? (errorName ? 500 : 200),
5789
5819
  errorName,
5790
5820
  errorStatus,
5791
- errorMessage
5821
+ errorMessage,
5822
+ upstreamErrorMessageRaw
5792
5823
  });
5793
5824
  }
5794
5825
  }
5795
5826
  async function handleMessagesCreateError(params) {
5796
5827
  const { error, instr, stream } = params;
5797
5828
  const finishedAtMs = Date.now();
5798
- const details = extractErrorDetails(error);
5799
- if (details.unauthorized) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5829
+ const details = await extractErrorObservability(error);
5830
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5800
5831
  const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
5801
5832
  insertRequestLog$1(instr, {
5802
5833
  finishedAtMs,
@@ -5808,7 +5839,8 @@ async function handleMessagesCreateError(params) {
5808
5839
  httpStatus: details.httpStatus,
5809
5840
  errorName: details.errorName,
5810
5841
  errorStatus: details.errorStatus,
5811
- errorMessage: details.errorMessage
5842
+ errorMessage: details.errorMessage,
5843
+ upstreamErrorMessageRaw: details.upstreamErrorMessageRaw
5812
5844
  });
5813
5845
  throw error;
5814
5846
  }
@@ -5819,17 +5851,19 @@ async function handleMessagesNonStreaming(params) {
5819
5851
  let errorName;
5820
5852
  let errorStatus;
5821
5853
  let errorMessage;
5854
+ let upstreamErrorMessageRaw;
5822
5855
  const finishedAtMs = Date.now();
5823
5856
  try {
5824
5857
  logger$5.debug("Non-streaming Messages result:", JSON.stringify(response).slice(-400));
5825
5858
  return c.json(response);
5826
5859
  } catch (error) {
5827
- const details = extractErrorDetails(error);
5860
+ const details = await extractErrorObservability(error);
5828
5861
  httpStatus = details.httpStatus;
5829
5862
  errorName = details.errorName;
5830
5863
  errorStatus = details.errorStatus;
5831
5864
  errorMessage = details.errorMessage;
5832
- if (details.unauthorized) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5865
+ upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
5866
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5833
5867
  throw error;
5834
5868
  } finally {
5835
5869
  const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
@@ -5844,7 +5878,8 @@ async function handleMessagesNonStreaming(params) {
5844
5878
  httpStatus,
5845
5879
  errorName,
5846
5880
  errorStatus,
5847
- errorMessage
5881
+ errorMessage,
5882
+ upstreamErrorMessageRaw
5848
5883
  });
5849
5884
  }
5850
5885
  }
@@ -5866,6 +5901,7 @@ async function streamMessagesAndLog(params) {
5866
5901
  let errorName;
5867
5902
  let errorStatus;
5868
5903
  let errorMessage;
5904
+ let upstreamErrorMessageRaw;
5869
5905
  try {
5870
5906
  for await (const rawEvent of response) {
5871
5907
  if (ttfbMs === void 0) ttfbMs = Date.now() - instr.startedAtMs;
@@ -5881,12 +5917,14 @@ async function streamMessagesAndLog(params) {
5881
5917
  });
5882
5918
  }
5883
5919
  } catch (error) {
5884
- const details = extractErrorDetails(error);
5920
+ const details = await extractErrorObservability(error);
5885
5921
  errorName = details.errorName;
5886
5922
  errorStatus = details.errorStatus;
5887
5923
  errorMessage = details.errorMessage;
5924
+ upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
5888
5925
  logger$5.warn("Streaming error:", error);
5889
- if (details.unauthorized) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5926
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
5927
+ await writeAnthropicStreamError(stream, getUserVisibleErrorMessage(details));
5890
5928
  } finally {
5891
5929
  const finishedAtMs = Date.now();
5892
5930
  const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
@@ -5902,28 +5940,33 @@ async function streamMessagesAndLog(params) {
5902
5940
  httpStatus: errorStatus ?? (errorName ? 500 : 200),
5903
5941
  errorName,
5904
5942
  errorStatus,
5905
- errorMessage
5943
+ errorMessage,
5944
+ upstreamErrorMessageRaw
5906
5945
  });
5907
5946
  }
5908
5947
  }
5909
5948
  const handleWithMessagesApi = async (params) => {
5910
- const { c, anthropicPayload, anthropicBetaHeader, initiatorOverride, subagentMarker, sessionId, instr, selectedModel, isCompact } = params;
5949
+ const { c, anthropicPayload, anthropicBetaHeader, subagentMarker, sessionId, instr, selectedModel, isCompact } = params;
5911
5950
  prepareMessagesApiPayload(anthropicPayload, selectedModel);
5912
5951
  debugJson(logger$5, "Translated Messages payload:", anthropicPayload);
5913
5952
  const ctx = toAccountContext(instr.account);
5914
- const initiator = initiatorOverride ?? getMessagesInitiator(anthropicPayload);
5915
- instr.initiator = initiator;
5953
+ const effectiveInitiator = resolveEffectiveInitiator(getMessagesInitiator(anthropicPayload), {
5954
+ isCompact,
5955
+ isSubagent: Boolean(subagentMarker)
5956
+ });
5957
+ instr.initiator = effectiveInitiator;
5916
5958
  let response;
5917
5959
  try {
5918
5960
  response = await createMessages(anthropicPayload, ctx, {
5919
5961
  anthropicBetaHeader,
5920
5962
  upstreamRequestId: instr.upstreamRequestId,
5921
- initiator,
5963
+ initiator: effectiveInitiator,
5922
5964
  subagentMarker,
5923
5965
  sessionId,
5924
5966
  isCompact
5925
5967
  });
5926
5968
  instr.confirmAffinity?.();
5969
+ instr.confirmOwnership?.();
5927
5970
  } catch (error) {
5928
5971
  return await handleMessagesCreateError({
5929
5972
  error,
@@ -5971,9 +6014,8 @@ messageRoutes.post("/count_tokens", async (c) => {
5971
6014
  const modelRoutes = new Hono();
5972
6015
  modelRoutes.get("/", async (c) => {
5973
6016
  try {
5974
- if (!state.models) await cacheModels();
5975
6017
  const blockedTargets = getAliasTargetSet();
5976
- const models = state.models?.data.filter((model) => !blockedTargets.has(model.id.toLowerCase())).map((model) => ({
6018
+ const models = getAvailableModels().filter((model) => !blockedTargets.has(model.id.toLowerCase())).map((model) => ({
5977
6019
  id: model.id,
5978
6020
  object: "model",
5979
6021
  type: "model",
@@ -5981,7 +6023,7 @@ modelRoutes.get("/", async (c) => {
5981
6023
  created_at: (/* @__PURE__ */ new Date(0)).toISOString(),
5982
6024
  owned_by: model.vendor,
5983
6025
  display_name: model.name
5984
- })) ?? [];
6026
+ }));
5985
6027
  const aliasModels = Object.keys(getModelAliases()).map((alias) => ({
5986
6028
  id: alias,
5987
6029
  object: "model",
@@ -6030,7 +6072,7 @@ async function handleProviderCountTokens(c) {
6030
6072
  const anthropicPayload = await c.req.json();
6031
6073
  const openAIPayload = translateToOpenAI(anthropicPayload);
6032
6074
  const modelId = anthropicPayload.model.trim();
6033
- let selectedModel = state.models?.data.find((model) => model.id === modelId);
6075
+ let selectedModel = getAvailableModels().find((model) => model.id === modelId);
6034
6076
  if (!selectedModel && modelId) selectedModel = createFallbackModel(modelId);
6035
6077
  if (!selectedModel) {
6036
6078
  logger$4.warn("provider.count_tokens.model_not_found", {
@@ -6077,10 +6119,13 @@ const STRIPPED_RESPONSE_HEADERS = [
6077
6119
  "upgrade"
6078
6120
  ];
6079
6121
  function buildProviderUpstreamHeaders(providerConfig, requestHeaders) {
6122
+ const authHeaders = {};
6123
+ if (providerConfig.authType === "authorization") authHeaders.authorization = `Bearer ${providerConfig.apiKey}`;
6124
+ else authHeaders["x-api-key"] = providerConfig.apiKey;
6080
6125
  const headers = {
6081
6126
  "content-type": "application/json",
6082
6127
  accept: "application/json",
6083
- "x-api-key": providerConfig.apiKey
6128
+ ...authHeaders
6084
6129
  };
6085
6130
  for (const headerName of FORWARDABLE_HEADERS) {
6086
6131
  const headerValue = requestHeaders.get(headerName);
@@ -6287,9 +6332,10 @@ const handleResponses = async (c) => {
6287
6332
  const streamRequested = Boolean(payload.stream);
6288
6333
  const { initiator: initialInitiator } = getResponsesRequestOptions(payload);
6289
6334
  const userId = payload.metadata?.user_id;
6290
- const { safetyIdentifier, sessionId: promptCacheKey } = parseUserIdMetadata(userId);
6335
+ const requestBodyPromptCacheKey = typeof payload.prompt_cache_key === "string" ? payload.prompt_cache_key : null;
6336
+ const { safetyIdentifier, sessionId: metadataSessionId } = parseUserIdMetadata(userId);
6291
6337
  const normalizedSafetyIdentifier = safetyIdentifier ?? void 0;
6292
- const normalizedPromptCacheKey = promptCacheKey ?? void 0;
6338
+ const normalizedPromptCacheKey = requestBodyPromptCacheKey ?? metadataSessionId ?? void 0;
6293
6339
  request.userId = userId;
6294
6340
  request.safetyIdentifier = normalizedSafetyIdentifier;
6295
6341
  request.promptCacheKey = normalizedPromptCacheKey;
@@ -6307,10 +6353,19 @@ const handleResponses = async (c) => {
6307
6353
  });
6308
6354
  }
6309
6355
  const upstreamRequestId = generateRequestIdFromPayload({ messages: payload.input }, normalizedPromptCacheKey);
6356
+ const headerSessionId = c.req.header("x-session-id") ?? null;
6357
+ const affinityKey = resolveAffinityKey({
6358
+ promptCacheKey: requestBodyPromptCacheKey,
6359
+ metadataSessionId,
6360
+ headerSessionId,
6361
+ upstreamRequestId
6362
+ });
6363
+ request.affinityKeyUsed = affinityKey.affinityKeyUsed;
6364
+ request.affinityKeySource = affinityKey.affinityKeySource;
6310
6365
  const selection = await accountsManager.selectAccountForRequest([{
6311
6366
  modelId: clientModel,
6312
6367
  endpoint: RESPONSES_ENDPOINT
6313
- }], { requestId: upstreamRequestId });
6368
+ }], { requestId: affinityKey.requestId });
6314
6369
  if (!selection.ok) {
6315
6370
  recordSelectionFailure(store, {
6316
6371
  request,
@@ -6323,6 +6378,7 @@ const handleResponses = async (c) => {
6323
6378
  const { account, selectedModel } = selection;
6324
6379
  request.affinityHit = selection.affinityHit;
6325
6380
  request.affinityCacheKey = selection.affinityCacheKey;
6381
+ request.selectionReason = selection.selectionReason;
6326
6382
  const upstreamPayload = {
6327
6383
  ...payload,
6328
6384
  model: selectedModel.id
@@ -6336,7 +6392,7 @@ const handleResponses = async (c) => {
6336
6392
  request.initiator = initiator;
6337
6393
  if (state.manualApprove) await awaitApproval();
6338
6394
  const accountCtx = toAccountContext(account);
6339
- const upstreamSessionId = getUUID(upstreamRequestId);
6395
+ const upstreamSessionId = getUUID(normalizedPromptCacheKey ?? headerSessionId ?? upstreamRequestId);
6340
6396
  request.upstreamRequestId = upstreamRequestId;
6341
6397
  request.upstreamSessionId = upstreamSessionId;
6342
6398
  if (streamRequested) return handleStreamingResponses({
@@ -6366,6 +6422,37 @@ const handleResponses = async (c) => {
6366
6422
  premiumUnlimitedBefore
6367
6423
  });
6368
6424
  };
6425
+ async function observeRequestError(accountId, error) {
6426
+ const details = await extractErrorObservability(error);
6427
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(accountId, "Unauthorized (401)");
6428
+ return {
6429
+ httpStatus: details.httpStatus,
6430
+ errorName: details.errorName,
6431
+ errorStatus: details.errorStatus,
6432
+ errorMessage: details.errorMessage,
6433
+ upstreamErrorMessageRaw: details.upstreamErrorMessageRaw
6434
+ };
6435
+ }
6436
+ function buildResponsesStreamError(message) {
6437
+ return {
6438
+ type: "error",
6439
+ code: null,
6440
+ message,
6441
+ param: null,
6442
+ sequence_number: 0
6443
+ };
6444
+ }
6445
+ async function writeResponsesStreamError(stream, message) {
6446
+ try {
6447
+ const errorEvent = buildResponsesStreamError(message);
6448
+ await stream.writeSSE({
6449
+ event: errorEvent.type,
6450
+ data: JSON.stringify(errorEvent)
6451
+ });
6452
+ } catch (streamError) {
6453
+ logger$1.warn("Failed to write Responses stream error event:", streamError);
6454
+ }
6455
+ }
6369
6456
  function buildRequestContext(c) {
6370
6457
  const requestId = randomUUID();
6371
6458
  const startedAtMs = Date.now();
@@ -6396,6 +6483,9 @@ function insertRequestLog(store, request, record) {
6396
6483
  promptCacheKey: request.promptCacheKey,
6397
6484
  initiator: request.initiator,
6398
6485
  upstreamRequestId: request.upstreamRequestId,
6486
+ affinityKeyUsed: request.affinityKeyUsed,
6487
+ affinityKeySource: request.affinityKeySource,
6488
+ selectionReason: request.selectionReason,
6399
6489
  affinityHit: request.affinityHit,
6400
6490
  affinityCacheKey: request.affinityCacheKey,
6401
6491
  ...record
@@ -6434,14 +6524,6 @@ function extractUsageFromChunkData(data) {
6434
6524
  return;
6435
6525
  }
6436
6526
  }
6437
- function getStreamChunkFields(chunk) {
6438
- const c = chunk;
6439
- return {
6440
- id: c.id,
6441
- event: c.event,
6442
- data: c.data
6443
- };
6444
- }
6445
6527
  async function handleStreamingResponses(params) {
6446
6528
  const { c, store, request, payload, selection, clientModel, accountCtx, vision, initiator, premiumRemainingBefore, premiumUnlimitedBefore } = params;
6447
6529
  let response;
@@ -6492,8 +6574,8 @@ async function handleUpstreamCreateError(params) {
6492
6574
  const { store, request, selection, clientModel, premiumRemainingBefore, premiumUnlimitedBefore, error } = params;
6493
6575
  const { account, reservation, selectedModel, endpoint, costUnits } = selection;
6494
6576
  const finishedAtMs = Date.now();
6495
- const details = extractErrorDetails(error);
6496
- if (details.unauthorized) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
6577
+ const details = await extractErrorObservability(error);
6578
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
6497
6579
  await accountsManager.finalizeQuota(account, reservation);
6498
6580
  const premiumRemainingAfter = account.premiumRemaining;
6499
6581
  const premiumUnlimitedAfter = account.unlimited;
@@ -6515,7 +6597,8 @@ async function handleUpstreamCreateError(params) {
6515
6597
  httpStatus: details.httpStatus,
6516
6598
  errorName: details.errorName,
6517
6599
  errorStatus: details.errorStatus,
6518
- errorMessage: details.errorMessage
6600
+ errorMessage: details.errorMessage,
6601
+ upstreamErrorMessageRaw: details.upstreamErrorMessageRaw
6519
6602
  });
6520
6603
  throw error;
6521
6604
  }
@@ -6527,6 +6610,7 @@ async function handleNonStreamingUpstreamResult(params) {
6527
6610
  let errorName;
6528
6611
  let errorStatus;
6529
6612
  let errorMessage;
6613
+ let upstreamErrorMessageRaw;
6530
6614
  const finishedAtMs = Date.now();
6531
6615
  try {
6532
6616
  debugJsonTail(logger$1, "Forwarding native Responses result:", {
@@ -6535,11 +6619,12 @@ async function handleNonStreamingUpstreamResult(params) {
6535
6619
  });
6536
6620
  return c.json(result);
6537
6621
  } catch (error) {
6538
- const details = extractErrorDetails(error);
6622
+ const details = await extractErrorObservability(error);
6539
6623
  httpStatus = details.httpStatus;
6540
6624
  errorName = details.errorName;
6541
6625
  errorStatus = details.errorStatus;
6542
6626
  errorMessage = details.errorMessage;
6627
+ upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
6543
6628
  throw error;
6544
6629
  } finally {
6545
6630
  await accountsManager.finalizeQuota(account, reservation);
@@ -6564,7 +6649,8 @@ async function handleNonStreamingUpstreamResult(params) {
6564
6649
  httpStatus,
6565
6650
  errorName,
6566
6651
  errorStatus,
6567
- errorMessage
6652
+ errorMessage,
6653
+ upstreamErrorMessageRaw
6568
6654
  });
6569
6655
  }
6570
6656
  }
@@ -6577,6 +6663,7 @@ async function streamResponsesAndLog(params) {
6577
6663
  let errorName;
6578
6664
  let errorStatus;
6579
6665
  let errorMessage;
6666
+ let upstreamErrorMessageRaw;
6580
6667
  try {
6581
6668
  for await (const chunk of response) {
6582
6669
  if (ttfbMs === void 0) ttfbMs = Date.now() - request.startedAtMs;
@@ -6592,11 +6679,14 @@ async function streamResponsesAndLog(params) {
6592
6679
  });
6593
6680
  }
6594
6681
  } catch (error) {
6595
- const details = extractErrorDetails(error);
6682
+ const details = await extractErrorObservability(error);
6596
6683
  errorName = details.errorName;
6597
6684
  errorStatus = details.errorStatus;
6598
6685
  errorMessage = details.errorMessage;
6686
+ upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
6599
6687
  logger$1.warn("Responses streaming error:", error);
6688
+ if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
6689
+ await writeResponsesStreamError(stream, getUserVisibleErrorMessage(details));
6600
6690
  } finally {
6601
6691
  const finishedAtMs = Date.now();
6602
6692
  await accountsManager.finalizeQuota(account, reservation);
@@ -6622,18 +6712,16 @@ async function streamResponsesAndLog(params) {
6622
6712
  httpStatus: errorStatus ?? (errorName ? 500 : 200),
6623
6713
  errorName,
6624
6714
  errorStatus,
6625
- errorMessage
6715
+ errorMessage,
6716
+ upstreamErrorMessageRaw
6626
6717
  });
6627
6718
  }
6628
6719
  }
6629
6720
  async function handleNonStreamingResponses(params) {
6630
6721
  const { c, store, request, payload, selection, clientModel, accountCtx, vision, initiator, premiumRemainingBefore, premiumUnlimitedBefore } = params;
6631
6722
  const { account, reservation, selectedModel, endpoint, costUnits } = selection;
6632
- let httpStatus = 200;
6633
6723
  let usage = {};
6634
- let errorName;
6635
- let errorStatus;
6636
- let errorMessage;
6724
+ let errorState = { httpStatus: 200 };
6637
6725
  let finishedAtMs;
6638
6726
  try {
6639
6727
  const response = await createResponses(payload, {
@@ -6642,10 +6730,9 @@ async function handleNonStreamingResponses(params) {
6642
6730
  upstreamRequestId: request.upstreamRequestId,
6643
6731
  sessionId: request.upstreamSessionId
6644
6732
  }, accountCtx);
6733
+ if (isAsyncIterable(response)) throw new Error("Upstream returned a stream unexpectedly");
6645
6734
  selection.confirmAffinity?.();
6646
6735
  finishedAtMs = Date.now();
6647
- const streamResponse = handleUnexpectedResponsesStream(c, response);
6648
- if (streamResponse) return streamResponse;
6649
6736
  const result = response;
6650
6737
  usage = extractResponsesUsageFromResult(result);
6651
6738
  debugJsonTail(logger$1, "Forwarding native Responses result:", {
@@ -6655,12 +6742,7 @@ async function handleNonStreamingResponses(params) {
6655
6742
  return c.json(result);
6656
6743
  } catch (error) {
6657
6744
  finishedAtMs = Date.now();
6658
- const details = extractErrorDetails(error);
6659
- httpStatus = details.httpStatus;
6660
- errorName = details.errorName;
6661
- errorStatus = details.errorStatus;
6662
- errorMessage = details.errorMessage;
6663
- if (details.unauthorized) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
6745
+ errorState = await observeRequestError(account.id, error);
6664
6746
  throw error;
6665
6747
  } finally {
6666
6748
  const finishedAtMsFinal = finishedAtMs ?? Date.now();
@@ -6683,61 +6765,14 @@ async function handleNonStreamingResponses(params) {
6683
6765
  premiumRemainingDiff: computeDiff(premiumRemainingBefore, premiumRemainingAfter),
6684
6766
  premiumUnlimitedBefore,
6685
6767
  premiumUnlimitedAfter,
6686
- httpStatus,
6687
- errorName,
6688
- errorStatus,
6689
- errorMessage
6768
+ httpStatus: errorState.httpStatus,
6769
+ errorName: errorState.errorName,
6770
+ errorStatus: errorState.errorStatus,
6771
+ errorMessage: errorState.errorMessage,
6772
+ upstreamErrorMessageRaw: errorState.upstreamErrorMessageRaw
6690
6773
  });
6691
6774
  }
6692
6775
  }
6693
- function handleUnexpectedResponsesStream(c, response) {
6694
- if (!isAsyncIterable(response)) return null;
6695
- logger$1.debug("Forwarding native Responses stream (unexpected)");
6696
- return streamSSE(c, async (stream) => {
6697
- const idTracker = createStreamIdTracker();
6698
- for await (const chunk of response) {
6699
- const { id, event, data } = getStreamChunkFields(chunk);
6700
- const processedData = fixStreamIds(data ?? "", event, idTracker);
6701
- debugJson(logger$1, "Responses stream chunk:", chunk);
6702
- await stream.writeSSE({
6703
- id,
6704
- event,
6705
- data: processedData
6706
- });
6707
- }
6708
- });
6709
- }
6710
- const isAsyncIterable = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
6711
- const useFunctionApplyPatch = (payload) => {
6712
- if (!(getConfig().useFunctionApplyPatch ?? true)) return;
6713
- logger$1.debug("Using function tool apply_patch for responses");
6714
- if (Array.isArray(payload.tools)) {
6715
- const toolsArr = payload.tools;
6716
- for (let i = 0; i < toolsArr.length; i++) {
6717
- const t = toolsArr[i];
6718
- if (t.type === "custom" && t.name === "apply_patch") toolsArr[i] = {
6719
- type: "function",
6720
- name: t.name,
6721
- description: "Use the `apply_patch` tool to edit files",
6722
- parameters: {
6723
- type: "object",
6724
- properties: { input: {
6725
- type: "string",
6726
- description: "The entire contents of the apply_patch command"
6727
- } },
6728
- required: ["input"]
6729
- },
6730
- strict: false
6731
- };
6732
- }
6733
- }
6734
- };
6735
- const removeWebSearchTool = (payload) => {
6736
- if (!Array.isArray(payload.tools) || payload.tools.length === 0) return;
6737
- payload.tools = payload.tools.filter((t) => {
6738
- return t.type !== "web_search";
6739
- });
6740
- };
6741
6776
 
6742
6777
  //#endregion
6743
6778
  //#region src/routes/responses/route.ts
@@ -6831,4 +6866,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
6831
6866
 
6832
6867
  //#endregion
6833
6868
  export { server };
6834
- //# sourceMappingURL=server-CuXJhEMC.js.map
6869
+ //# sourceMappingURL=server-DAxpfPde.js.map