@nick3/copilot-api 1.4.5 → 1.4.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 (37) hide show
  1. package/README.md +14 -6
  2. package/dist/{account-DhQb2A6q.js → account-CipKmikF.js} +2 -2
  3. package/dist/{account-DhQb2A6q.js.map → account-CipKmikF.js.map} +1 -1
  4. package/dist/{accounts-manager-BsGuQhKM.js → accounts-manager-Cjrd_el_.js} +249 -83
  5. package/dist/accounts-manager-Cjrd_el_.js.map +1 -0
  6. package/dist/{accounts-registry-c7rs5Ed9.js → accounts-registry-CQYvRe65.js} +3 -3
  7. package/dist/{accounts-registry-c7rs5Ed9.js.map → accounts-registry-CQYvRe65.js.map} +1 -1
  8. package/dist/admin/assets/index-BFvCJZIK.js +57 -0
  9. package/dist/admin/assets/index-CsAeel_7.css +1 -0
  10. package/dist/admin/index.html +2 -2
  11. package/dist/{auth-BAEHgP-a.js → auth-1gAffrpI.js} +6 -6
  12. package/dist/{auth-BAEHgP-a.js.map → auth-1gAffrpI.js.map} +1 -1
  13. package/dist/{check-usage-Dbthad7V.js → check-usage-CsRu467P.js} +5 -5
  14. package/dist/{check-usage-Dbthad7V.js.map → check-usage-CsRu467P.js.map} +1 -1
  15. package/dist/{debug-hQJWwXtC.js → debug-BzR5ZQUk.js} +3 -3
  16. package/dist/{debug-hQJWwXtC.js.map → debug-BzR5ZQUk.js.map} +1 -1
  17. package/dist/{get-copilot-token-BySQCue6.js → get-copilot-token-BbpphnmV.js} +3 -3
  18. package/dist/{get-copilot-token-BySQCue6.js.map → get-copilot-token-BbpphnmV.js.map} +1 -1
  19. package/dist/main.js +6 -7
  20. package/dist/main.js.map +1 -1
  21. package/dist/{paths-DoT4SZ8f.js → paths-Cvzy-eLX.js} +2 -2
  22. package/dist/{paths-DoT4SZ8f.js.map → paths-Cvzy-eLX.js.map} +1 -1
  23. package/dist/{poll-access-token-CKc0_m42.js → poll-access-token-CGfLFzMq.js} +3 -3
  24. package/dist/{poll-access-token-CKc0_m42.js.map → poll-access-token-CGfLFzMq.js.map} +1 -1
  25. package/dist/{server-D_7gI9hx.js → server-DqwhClJ-.js} +187 -152
  26. package/dist/server-DqwhClJ-.js.map +1 -0
  27. package/dist/{start-DItwCYda.js → start-B1_Ols5Z.js} +16 -18
  28. package/dist/start-B1_Ols5Z.js.map +1 -0
  29. package/dist/{utils-BIK3ym34.js → utils-DY-jLXwO.js} +34 -10
  30. package/dist/utils-DY-jLXwO.js.map +1 -0
  31. package/package.json +3 -1
  32. package/dist/accounts-manager-BsGuQhKM.js.map +0 -1
  33. package/dist/admin/assets/index-Y2SvOXge.js +0 -57
  34. package/dist/admin/assets/index-geiCIixE.css +0 -1
  35. package/dist/server-D_7gI9hx.js.map +0 -1
  36. package/dist/start-DItwCYda.js.map +0 -1
  37. package/dist/utils-BIK3ym34.js.map +0 -1
@@ -1,8 +1,8 @@
1
- import { PATHS } from "./paths-DoT4SZ8f.js";
2
- import { listAccountsFromRegistry } from "./accounts-registry-c7rs5Ed9.js";
3
- import { HTTPError, accountFromState, cacheModels, copilotBaseUrl, copilotHeaders, forwardError, generateRequestIdFromPayload, getCopilotUsage, getRootSessionId, getUUID, isNullish, parseUserIdMetadata, prepareForCompact, prepareInteractionHeaders, sleep, state } from "./utils-BIK3ym34.js";
4
- import "./get-copilot-token-BySQCue6.js";
5
- import { PROVIDER_TYPE_ANTHROPIC, accountsManager, getAliasTargetSet, getAnthropicApiKey, getConfig, getExtraPromptForModel, getModelAliases, getModelAliasesInfo, getModelRefreshIntervalMs, getProviderConfig, getReasoningEffortForModel, getSmallModel, isForceAgentEnabled, isFreeModelLoadBalancingEnabled, isMessageStartInputTokensFallbackEnabled, isMessagesApiEnabled, isResponsesApiContextManagementModel, mergeConfigWithDefaults, shouldCompactUseSmallModel } from "./accounts-manager-BsGuQhKM.js";
1
+ import { t as PATHS } from "./paths-Cvzy-eLX.js";
2
+ import { i as listAccountsFromRegistry } from "./accounts-registry-CQYvRe65.js";
3
+ import { C as prepareInteractionHeaders, D as state, E as accountFromState, S as prepareForCompact, T as resolveTraceId, _ as copilotHeaders, a as generateRequestIdFromPayload, c as isNullish, g as copilotBaseUrl, h as forwardError, l as parseUserIdMetadata, m as HTTPError, n as cacheModels, o as getRootSessionId, p as getCopilotUsage, s as getUUID, u as sleep, w as requestContext } from "./utils-DY-jLXwO.js";
4
+ import "./get-copilot-token-BbpphnmV.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-Cjrd_el_.js";
6
6
  import consola from "consola";
7
7
  import fs, { readFile } from "node:fs/promises";
8
8
  import * as path$1 from "node:path";
@@ -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 { AsyncLocalStorage } from "node:async_hooks";
16
15
  import { Database } from "bun:sqlite";
17
16
  import { fileURLToPath } from "node:url";
18
17
  import { streamSSE } from "hono/streaming";
@@ -105,26 +104,6 @@ function createAuthMiddleware(options = {}) {
105
104
  };
106
105
  }
107
106
 
108
- //#endregion
109
- //#region src/lib/request-context.ts
110
- const TRACE_ID_MAX_LENGTH = 64;
111
- const TRACE_ID_PATTERN = /^\w[\w.-]*$/;
112
- const asyncLocalStorage = new AsyncLocalStorage();
113
- const requestContext = {
114
- getStore: () => asyncLocalStorage.getStore(),
115
- run: (context, callback) => asyncLocalStorage.run(context, callback)
116
- };
117
- function generateTraceId() {
118
- const timestamp = Date.now().toString(36);
119
- const random = Math.random().toString(36).slice(2, 8);
120
- return `${timestamp}-${random}`;
121
- }
122
- function resolveTraceId(traceId) {
123
- const candidate = traceId?.trim();
124
- if (!candidate || candidate.length > TRACE_ID_MAX_LENGTH || !TRACE_ID_PATTERN.test(candidate)) return generateTraceId();
125
- return candidate;
126
- }
127
-
128
107
  //#endregion
129
108
  //#region src/lib/trace.ts
130
109
  const traceIdMiddleware = async (c, next) => {
@@ -132,7 +111,8 @@ const traceIdMiddleware = async (c, next) => {
132
111
  c.header("x-trace-id", traceId);
133
112
  const context = {
134
113
  traceId,
135
- startTime: Date.now()
114
+ startTime: Date.now(),
115
+ userAgent: c.req.header("user-agent") || ""
136
116
  };
137
117
  await requestContext.run(context, async () => {
138
118
  await next();
@@ -189,66 +169,69 @@ function getAdminDbUserVersion(db = getAdminDb()) {
189
169
  return 0;
190
170
  }
191
171
  }
192
- function migrateAdminDb(db) {
193
- const current = db.query("PRAGMA user_version;").get()?.user_version ?? 0;
194
- if (current >= 4) return;
195
- if (current < 1) db.run(`
196
- CREATE TABLE IF NOT EXISTS request_log (
197
- id INTEGER PRIMARY KEY AUTOINCREMENT,
198
- request_id TEXT NOT NULL UNIQUE,
172
+ function migrateV1(db) {
173
+ db.run(`
174
+ CREATE TABLE IF NOT EXISTS request_log (
175
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
176
+ request_id TEXT NOT NULL UNIQUE,
199
177
 
200
- started_at_ms INTEGER NOT NULL,
201
- finished_at_ms INTEGER,
202
- duration_ms INTEGER,
203
- ttfb_ms INTEGER,
178
+ started_at_ms INTEGER NOT NULL,
179
+ finished_at_ms INTEGER,
180
+ duration_ms INTEGER,
181
+ ttfb_ms INTEGER,
204
182
 
205
- method TEXT NOT NULL,
206
- path TEXT NOT NULL,
207
- upstream_endpoint TEXT,
208
- stream INTEGER NOT NULL DEFAULT 0,
183
+ method TEXT NOT NULL,
184
+ path TEXT NOT NULL,
185
+ upstream_endpoint TEXT,
186
+ stream INTEGER NOT NULL DEFAULT 0,
209
187
 
210
- account_id TEXT,
211
- account_type TEXT,
212
- cost_units REAL,
213
- client_model TEXT,
214
- upstream_model TEXT,
188
+ account_id TEXT,
189
+ account_type TEXT,
190
+ cost_units REAL,
191
+ client_model TEXT,
192
+ upstream_model TEXT,
215
193
 
216
- client_ip TEXT,
217
- client_ip_source TEXT,
218
- user_agent TEXT,
194
+ client_ip TEXT,
195
+ client_ip_source TEXT,
196
+ user_agent TEXT,
219
197
 
220
- tokens_input INTEGER,
221
- tokens_output INTEGER,
222
- tokens_total INTEGER,
223
- tokens_cached_input INTEGER,
224
- usage_json TEXT,
198
+ tokens_input INTEGER,
199
+ tokens_output INTEGER,
200
+ tokens_total INTEGER,
201
+ tokens_cached_input INTEGER,
202
+ usage_json TEXT,
225
203
 
226
- premium_remaining_before REAL,
227
- premium_remaining_after REAL,
228
- premium_remaining_diff REAL,
229
- premium_unlimited_before INTEGER,
230
- premium_unlimited_after INTEGER,
204
+ premium_remaining_before REAL,
205
+ premium_remaining_after REAL,
206
+ premium_remaining_diff REAL,
207
+ premium_unlimited_before INTEGER,
208
+ premium_unlimited_after INTEGER,
231
209
 
232
- http_status INTEGER,
233
- error_name TEXT,
234
- error_status INTEGER,
235
- error_message TEXT,
236
- selection_failure_reason TEXT
237
- );
210
+ http_status INTEGER,
211
+ error_name TEXT,
212
+ error_status INTEGER,
213
+ error_message TEXT,
214
+ selection_failure_reason TEXT
215
+ );
238
216
 
239
- CREATE INDEX IF NOT EXISTS idx_request_log_started_at
240
- ON request_log(started_at_ms DESC);
241
- CREATE INDEX IF NOT EXISTS idx_request_log_account_started_at
242
- ON request_log(account_id, started_at_ms DESC);
243
- CREATE INDEX IF NOT EXISTS idx_request_log_model_started_at
244
- ON request_log(upstream_model, started_at_ms DESC);
245
- CREATE INDEX IF NOT EXISTS idx_request_log_endpoint_started_at
246
- ON request_log(upstream_endpoint, started_at_ms DESC);
247
- CREATE INDEX IF NOT EXISTS idx_request_log_status_started_at
248
- ON request_log(http_status, started_at_ms DESC);
217
+ CREATE INDEX IF NOT EXISTS idx_request_log_started_at
218
+ ON request_log(started_at_ms DESC);
219
+ CREATE INDEX IF NOT EXISTS idx_request_log_account_started_at
220
+ ON request_log(account_id, started_at_ms DESC);
221
+ CREATE INDEX IF NOT EXISTS idx_request_log_model_started_at
222
+ ON request_log(upstream_model, started_at_ms DESC);
223
+ CREATE INDEX IF NOT EXISTS idx_request_log_endpoint_started_at
224
+ ON request_log(upstream_endpoint, started_at_ms DESC);
225
+ CREATE INDEX IF NOT EXISTS idx_request_log_status_started_at
226
+ ON request_log(http_status, started_at_ms DESC);
249
227
 
250
- PRAGMA user_version = 1;
251
- `);
228
+ PRAGMA user_version = 1;
229
+ `);
230
+ }
231
+ function migrateAdminDb(db) {
232
+ const current = db.query("PRAGMA user_version;").get()?.user_version ?? 0;
233
+ if (current >= 5) return;
234
+ if (current < 1) migrateV1(db);
252
235
  if (current < 2) db.run(`
253
236
  ALTER TABLE request_log ADD COLUMN user_id TEXT;
254
237
  ALTER TABLE request_log ADD COLUMN safety_identifier TEXT;
@@ -283,6 +266,12 @@ function migrateAdminDb(db) {
283
266
 
284
267
  PRAGMA user_version = 4;
285
268
  `);
269
+ if (current < 5) db.run(`
270
+ ALTER TABLE request_log ADD COLUMN affinity_hit INTEGER;
271
+ ALTER TABLE request_log ADD COLUMN affinity_cache_key TEXT;
272
+
273
+ PRAGMA user_version = 5;
274
+ `);
286
275
  }
287
276
 
288
277
  //#endregion
@@ -368,14 +357,11 @@ function normalizeMessagesUsage(usage) {
368
357
  const output = usage.output_tokens;
369
358
  const hasInput = typeof input === "number";
370
359
  const hasOutput = typeof output === "number";
371
- const tokensInput = hasInput ? Math.max(0, input - cached) : void 0;
372
- const tokensOutput = hasOutput ? output : void 0;
373
- const tokensTotal = hasInput || hasOutput ? (input ?? 0) + (output ?? 0) : void 0;
374
360
  return {
375
361
  tokensCachedInput: cached,
376
- tokensInput,
377
- tokensOutput,
378
- tokensTotal,
362
+ tokensInput: hasInput ? Math.max(0, input - cached) : void 0,
363
+ tokensOutput: hasOutput ? output : void 0,
364
+ tokensTotal: hasInput || hasOutput ? (input ?? 0) + (output ?? 0) : void 0,
379
365
  usageJson: JSON.stringify(usage)
380
366
  };
381
367
  }
@@ -434,13 +420,15 @@ var RequestHistoryStore = class {
434
420
  error_name,
435
421
  error_status,
436
422
  error_message,
437
- selection_failure_reason
423
+ selection_failure_reason,
424
+ affinity_hit,
425
+ affinity_cache_key
438
426
  ) VALUES (
439
427
  ?,?,?,?,?,?,?,?,
440
428
  ?,?,?,?,?,?,?,?,
441
429
  ?,?,?,?,?,?,?,?,
442
430
  ?,?,?,?,?,?,?,?,
443
- ?,?,?,?,?
431
+ ?,?,?,?,?,?,?
444
432
  );
445
433
  `);
446
434
  this.getByRequestIdStmt = db.query("SELECT * FROM request_log WHERE request_id = ? LIMIT 1;");
@@ -499,7 +487,9 @@ var RequestHistoryStore = class {
499
487
  toDbNull(record.errorName),
500
488
  toDbNull(record.errorStatus),
501
489
  toDbNull(record.errorMessage),
502
- toDbNull(record.selectionFailureReason)
490
+ toDbNull(record.selectionFailureReason),
491
+ toDbBool(record.affinityHit),
492
+ toDbNull(record.affinityCacheKey)
503
493
  ];
504
494
  this.insertStmt.run(...args);
505
495
  } catch (error) {
@@ -585,10 +575,9 @@ var RequestHistoryStore = class {
585
575
  const rows = this.db.query(sql).all(...values, limit + 1);
586
576
  const items = rows.slice(0, limit);
587
577
  const hasMore = rows.length > limit;
588
- const nextCursorId = hasMore ? items.at(-1)?.id : void 0;
589
578
  return {
590
579
  items,
591
- nextCursorId,
580
+ nextCursorId: hasMore ? items.at(-1)?.id : void 0,
592
581
  hasMore
593
582
  };
594
583
  }
@@ -763,7 +752,7 @@ const CONFIG_KEYS = new Set([
763
752
  "auth",
764
753
  "extraPrompts",
765
754
  "smallModel",
766
- "freeModelLoadBalancing",
755
+ "accountAffinity",
767
756
  "apiKey",
768
757
  "anthropicApiKey",
769
758
  "providers",
@@ -776,7 +765,8 @@ const CONFIG_KEYS = new Set([
776
765
  "compactUseSmallModel",
777
766
  "messageStartInputTokensFallback",
778
767
  "modelRefreshIntervalHours",
779
- "useMessagesApi"
768
+ "useMessagesApi",
769
+ "useResponsesApiWebSearch"
780
770
  ]);
781
771
  const REASONING_EFFORTS = new Set([
782
772
  "none",
@@ -1124,7 +1114,7 @@ const CONFIG_PATCH_HANDLERS = {
1124
1114
  auth: applyAuthConfig,
1125
1115
  extraPrompts: applyExtraPrompts,
1126
1116
  smallModel: (next, value) => applyOptionalString(next, "smallModel", value),
1127
- freeModelLoadBalancing: (next, value) => applyOptionalBoolean(next, "freeModelLoadBalancing", value),
1117
+ accountAffinity: (next, value) => applyOptionalBoolean(next, "accountAffinity", value),
1128
1118
  apiKey: (next, value) => applyOptionalString(next, "apiKey", value),
1129
1119
  anthropicApiKey: (next, value) => applyOptionalString(next, "anthropicApiKey", value),
1130
1120
  providers: applyProvidersConfig,
@@ -1137,7 +1127,8 @@ const CONFIG_PATCH_HANDLERS = {
1137
1127
  compactUseSmallModel: (next, value) => applyOptionalBoolean(next, "compactUseSmallModel", value),
1138
1128
  messageStartInputTokensFallback: (next, value) => applyOptionalBoolean(next, "messageStartInputTokensFallback", value),
1139
1129
  modelRefreshIntervalHours: (next, value) => applyOptionalNumber(next, "modelRefreshIntervalHours", value),
1140
- useMessagesApi: (next, value) => applyOptionalBoolean(next, "useMessagesApi", value)
1130
+ useMessagesApi: (next, value) => applyOptionalBoolean(next, "useMessagesApi", value),
1131
+ useResponsesApiWebSearch: (next, value) => applyOptionalBoolean(next, "useResponsesApiWebSearch", value)
1141
1132
  };
1142
1133
  function applyConfigPatch(base, input) {
1143
1134
  const next = { ...base };
@@ -1215,7 +1206,7 @@ adminApiRoutes.post("/config", async (c) => {
1215
1206
  try {
1216
1207
  await writeConfigFile(result.config);
1217
1208
  const merged = mergeConfigWithDefaults();
1218
- accountsManager.setFreeModelLoadBalancingEnabled(isFreeModelLoadBalancingEnabled());
1209
+ accountsManager.setAccountAffinityEnabled(isAccountAffinityEnabled());
1219
1210
  accountsManager.setModelsRefreshIntervalMs(getModelRefreshIntervalMs());
1220
1211
  return c.json({
1221
1212
  ...merged,
@@ -1294,12 +1285,10 @@ function parseAdminModelDetailsItem(raw, aliasesByTarget) {
1294
1285
  if (!isPlainObject(raw)) return null;
1295
1286
  const id = parseNonEmptyString(raw.id);
1296
1287
  if (!id) return null;
1297
- const name = parseNonEmptyString(raw.name) ?? id;
1298
- const preview = toBooleanOrUndefined(raw.preview) ?? false;
1299
1288
  return {
1300
1289
  id,
1301
- name,
1302
- preview,
1290
+ name: parseNonEmptyString(raw.name) ?? id,
1291
+ preview: toBooleanOrUndefined(raw.preview) ?? false,
1303
1292
  billing: parseBilling(raw.billing),
1304
1293
  supported_endpoints: parseStringArray(raw.supported_endpoints),
1305
1294
  capabilities: parseCapabilities(raw.capabilities),
@@ -2192,8 +2181,7 @@ const createHandlerLogger = (name) => {
2192
2181
  const filePath = path.join(LOG_DIR, `${sanitizedName}-${dateKey}.log`);
2193
2182
  const message = formatArgs(logObj.args);
2194
2183
  const traceIdStr = traceId ? ` [${traceId}]` : "";
2195
- const line = `[${timestamp}] [${logObj.type}] [${logObj.tag || name}]${traceIdStr}${message ? ` ${message}` : ""}`;
2196
- appendLine(filePath, line);
2184
+ appendLine(filePath, `[${timestamp}] [${logObj.type}] [${logObj.tag || name}]${traceIdStr}${message ? ` ${message}` : ""}`);
2197
2185
  } });
2198
2186
  return instance;
2199
2187
  };
@@ -2425,8 +2413,7 @@ const numTokensForTools = (tools, encoder, constants) => {
2425
2413
  * Calculate the token count of messages, supporting multiple GPT encoders
2426
2414
  */
2427
2415
  const getTokenCount = async (payload, model) => {
2428
- const tokenizer = getTokenizerFromModel(model);
2429
- const encoder = await getEncodeChatFunction(tokenizer);
2416
+ const encoder = await getEncodeChatFunction(getTokenizerFromModel(model));
2430
2417
  const simplifiedMessages = payload.messages;
2431
2418
  const inputMessages = simplifiedMessages.filter((msg) => msg.role !== "assistant");
2432
2419
  const outputMessages = simplifiedMessages.filter((msg) => msg.role === "assistant");
@@ -2517,10 +2504,11 @@ async function handleCompletion$1(c) {
2517
2504
  });
2518
2505
  }
2519
2506
  logger$6.debug("Request payload:", JSON.stringify(payload).slice(-400));
2507
+ const upstreamRequestId = generateRequestIdFromPayload(payload, normalizedPromptCacheKey);
2520
2508
  const selection = await accountsManager.selectAccountForRequest([{
2521
2509
  modelId: clientModel,
2522
2510
  endpoint: CHAT_COMPLETIONS_ENDPOINT$1
2523
- }]);
2511
+ }], { requestId: upstreamRequestId });
2524
2512
  if (!selection.ok) {
2525
2513
  recordSelectionFailure$2(store, {
2526
2514
  request,
@@ -2534,6 +2522,8 @@ async function handleCompletion$1(c) {
2534
2522
  });
2535
2523
  }
2536
2524
  const { account, selectedModel } = selection;
2525
+ request.affinityHit = selection.affinityHit;
2526
+ request.affinityCacheKey = selection.affinityCacheKey;
2537
2527
  const upstreamPayload = {
2538
2528
  ...payload,
2539
2529
  model: selectedModel.id
@@ -2547,7 +2537,6 @@ async function handleCompletion$1(c) {
2547
2537
  if (state.manualApprove) await awaitApproval();
2548
2538
  const payloadWithMaxTokens = applyDefaultMaxTokens(upstreamPayload, selectedModel);
2549
2539
  const accountCtx = toAccountContext(account);
2550
- const upstreamRequestId = generateRequestIdFromPayload(payloadWithMaxTokens);
2551
2540
  const upstreamSessionId = getUUID(upstreamRequestId);
2552
2541
  request.upstreamRequestId = upstreamRequestId;
2553
2542
  request.upstreamSessionId = upstreamSessionId;
@@ -2580,7 +2569,6 @@ function buildRequestContext$1(c) {
2580
2569
  const method = c.req.raw.method;
2581
2570
  const path$2 = new URL(c.req.url, "http://local").pathname;
2582
2571
  const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
2583
- const userAgent = c.req.header("user-agent") ?? void 0;
2584
2572
  return {
2585
2573
  requestId,
2586
2574
  startedAtMs,
@@ -2588,7 +2576,7 @@ function buildRequestContext$1(c) {
2588
2576
  path: path$2,
2589
2577
  clientIp,
2590
2578
  clientIpSource,
2591
- userAgent
2579
+ userAgent: c.req.header("user-agent") ?? void 0
2592
2580
  };
2593
2581
  }
2594
2582
  function insertRequestLog$2(store, request, record) {
@@ -2605,6 +2593,8 @@ function insertRequestLog$2(store, request, record) {
2605
2593
  promptCacheKey: request.promptCacheKey,
2606
2594
  initiator: request.initiator,
2607
2595
  upstreamRequestId: request.upstreamRequestId,
2596
+ affinityHit: request.affinityHit,
2597
+ affinityCacheKey: request.affinityCacheKey,
2608
2598
  ...record
2609
2599
  });
2610
2600
  }
@@ -2657,6 +2647,7 @@ async function handleStreamingRequest(params) {
2657
2647
  upstreamRequestId: request.upstreamRequestId,
2658
2648
  sessionId: request.upstreamSessionId
2659
2649
  });
2650
+ selection.confirmAffinity?.();
2660
2651
  } catch (error) {
2661
2652
  return handleUpstreamCreateError$1({
2662
2653
  store,
@@ -2844,6 +2835,7 @@ async function handleNonStreamingRequest(params) {
2844
2835
  upstreamRequestId: request.upstreamRequestId,
2845
2836
  sessionId: request.upstreamSessionId
2846
2837
  });
2838
+ selection.confirmAffinity?.();
2847
2839
  finishedAtMs = Date.now();
2848
2840
  if (!isNonStreaming$1(response)) {
2849
2841
  logger$6.debug("Unexpected streaming response");
@@ -2930,7 +2922,6 @@ embeddingRoutes.post("/", async (c) => {
2930
2922
  const method = c.req.raw.method;
2931
2923
  const path$2 = new URL(c.req.url, "http://local").pathname;
2932
2924
  const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
2933
- const userAgent = c.req.header("user-agent") ?? void 0;
2934
2925
  const ctx = {
2935
2926
  requestId,
2936
2927
  startedAtMs,
@@ -2938,7 +2929,7 @@ embeddingRoutes.post("/", async (c) => {
2938
2929
  path: path$2,
2939
2930
  clientIp,
2940
2931
  clientIpSource,
2941
- userAgent
2932
+ userAgent: c.req.header("user-agent") ?? void 0
2942
2933
  };
2943
2934
  const payload = await c.req.json();
2944
2935
  const clientModel = payload.model;
@@ -2962,15 +2953,14 @@ embeddingRoutes.post("/", async (c) => {
2962
2953
  });
2963
2954
  return selectionFailureResponse$1(c, clientModel, selection.reason);
2964
2955
  }
2965
- const upstreamPayload = {
2966
- ...payload,
2967
- model: selection.selectedModel.id
2968
- };
2969
2956
  return await runEmbeddingsWithAccount({
2970
2957
  c,
2971
2958
  store,
2972
2959
  ctx,
2973
- payload: upstreamPayload,
2960
+ payload: {
2961
+ ...payload,
2962
+ model: selection.selectedModel.id
2963
+ },
2974
2964
  clientModel,
2975
2965
  selection
2976
2966
  });
@@ -3019,8 +3009,7 @@ async function runEmbeddingsWithAccount({ c, store, ctx, payload, clientModel, s
3019
3009
  let errorMessage;
3020
3010
  let finishedAtMs;
3021
3011
  try {
3022
- const accountCtx = toAccountContext(account);
3023
- const response = await createEmbeddings(payload, accountCtx);
3012
+ const response = await createEmbeddings(payload, toAccountContext(account));
3024
3013
  usage = normalizeEmbeddingsUsage(response.usage);
3025
3014
  finishedAtMs = Date.now();
3026
3015
  return c.json(response);
@@ -3175,6 +3164,32 @@ const mergeToolResultForClaude = (anthropicPayload) => {
3175
3164
  msg.content = mergeToolResult(toolResults, textBlocks);
3176
3165
  }
3177
3166
  };
3167
+ const stripUnsupportedCacheControl = (block) => {
3168
+ const cacheControl = block.cache_control;
3169
+ if (!cacheControl || typeof cacheControl !== "object" || Array.isArray(cacheControl)) return;
3170
+ const type = cacheControl.type;
3171
+ if (typeof type === "string") {
3172
+ block.cache_control = { type };
3173
+ return;
3174
+ }
3175
+ delete block.cache_control;
3176
+ };
3177
+ const stripTextBlockCacheControl = (block) => {
3178
+ if (!block || typeof block !== "object" || Array.isArray(block)) return;
3179
+ const record = block;
3180
+ if (record.type !== "text") return;
3181
+ stripUnsupportedCacheControl(record);
3182
+ };
3183
+ const stripCacheControl = (anthropicPayload) => {
3184
+ if (Array.isArray(anthropicPayload.system)) for (const block of anthropicPayload.system) stripTextBlockCacheControl(block);
3185
+ for (const msg of anthropicPayload.messages) {
3186
+ if (!Array.isArray(msg.content)) continue;
3187
+ for (const block of msg.content) {
3188
+ stripTextBlockCacheControl(block);
3189
+ if (block.type === "tool_result" && Array.isArray(block.content)) for (const nestedBlock of block.content) stripTextBlockCacheControl(nestedBlock);
3190
+ }
3191
+ }
3192
+ };
3178
3193
  const estimateInputTokens = async (payload, selectedModel, logger$7) => {
3179
3194
  try {
3180
3195
  return (await getTokenCount(payload, selectedModel)).input;
@@ -3239,6 +3254,21 @@ const maybeBlockOriginalModelName = (context) => {
3239
3254
  }
3240
3255
  });
3241
3256
  };
3257
+ const compactSystemPromptStart = "You are a helpful AI assistant tasked with summarizing conversations";
3258
+ const compactUserMessageStart = "CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.";
3259
+ const hasCompactUserMessage = (messages) => {
3260
+ const lastMsg = messages.at(-1);
3261
+ if (!lastMsg || lastMsg.role !== "user") return false;
3262
+ if (typeof lastMsg.content === "string") return lastMsg.content.startsWith(compactUserMessageStart);
3263
+ if (!Array.isArray(lastMsg.content)) return false;
3264
+ return lastMsg.content.some((block) => block.type === "text" && typeof block.text === "string" && block.text.startsWith(compactUserMessageStart));
3265
+ };
3266
+ const isCompactRequest = (anthropicPayload) => {
3267
+ const system = anthropicPayload.system;
3268
+ if (typeof system === "string" && system.startsWith(compactSystemPromptStart)) return true;
3269
+ if (Array.isArray(system) && system.some((msg) => typeof msg.text === "string" && msg.text.startsWith(compactSystemPromptStart))) return true;
3270
+ return hasCompactUserMessage(anthropicPayload.messages);
3271
+ };
3242
3272
 
3243
3273
  //#endregion
3244
3274
  //#region src/routes/messages/non-stream-translation.ts
@@ -3523,7 +3553,7 @@ async function handleCountTokens(c) {
3523
3553
  }
3524
3554
  }
3525
3555
  let finalTokenCount = tokenCount.input + tokenCount.output;
3526
- if (anthropicPayload.model.startsWith("claude")) finalTokenCount = Math.round(finalTokenCount * 1.15);
3556
+ if (anthropicPayload.model.startsWith("claude")) finalTokenCount = Math.round(finalTokenCount * getClaudeTokenMultiplier());
3527
3557
  consola.info("Token count:", finalTokenCount);
3528
3558
  return c.json({ input_tokens: finalTokenCount });
3529
3559
  } catch (error) {
@@ -3952,9 +3982,8 @@ const mapResponsesStopReason = (response) => {
3952
3982
  const mapResponsesUsage = (response) => {
3953
3983
  const inputTokens = response.usage?.input_tokens ?? 0;
3954
3984
  const outputTokens = response.usage?.output_tokens ?? 0;
3955
- const inputCachedTokens = response.usage?.input_tokens_details?.cached_tokens;
3956
3985
  return {
3957
- input_tokens: inputTokens - (inputCachedTokens ?? 0),
3986
+ input_tokens: inputTokens - (response.usage?.input_tokens_details?.cached_tokens ?? 0),
3958
3987
  output_tokens: outputTokens,
3959
3988
  ...response.usage?.input_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: response.usage.input_tokens_details.cached_tokens }
3960
3989
  };
@@ -4374,10 +4403,9 @@ const openFunctionCallBlock = (state$1, params) => {
4374
4403
  if (!functionCallState) {
4375
4404
  const blockIndex$1 = state$1.nextContentBlockIndex;
4376
4405
  state$1.nextContentBlockIndex += 1;
4377
- const resolvedToolCallId = toolCallId ?? `tool_call_${blockIndex$1}`;
4378
4406
  functionCallState = {
4379
4407
  blockIndex: blockIndex$1,
4380
- toolCallId: resolvedToolCallId,
4408
+ toolCallId: toolCallId ?? `tool_call_${blockIndex$1}`,
4381
4409
  name: name ?? "function",
4382
4410
  consecutiveWhitespaceCount: 0
4383
4411
  };
@@ -4403,26 +4431,20 @@ const openFunctionCallBlock = (state$1, params) => {
4403
4431
  const extractFunctionCallDetails = (rawEvent) => {
4404
4432
  const item = rawEvent.item;
4405
4433
  if (item.type !== "function_call") return;
4406
- const outputIndex = rawEvent.output_index;
4407
- const toolCallId = item.call_id;
4408
- const name = item.name;
4409
- const initialArguments = item.arguments;
4410
4434
  return {
4411
- outputIndex,
4412
- toolCallId,
4413
- name,
4414
- initialArguments
4435
+ outputIndex: rawEvent.output_index,
4436
+ toolCallId: item.call_id,
4437
+ name: item.name,
4438
+ initialArguments: item.arguments
4415
4439
  };
4416
4440
  };
4417
4441
 
4418
4442
  //#endregion
4419
4443
  //#region src/routes/responses/utils.ts
4420
4444
  const getResponsesRequestOptions = (payload) => {
4421
- const vision = hasVisionInput(payload);
4422
- const initiator = hasAgentInitiator(payload) ? "agent" : "user";
4423
4445
  return {
4424
- vision,
4425
- initiator
4446
+ vision: hasVisionInput(payload),
4447
+ initiator: hasAgentInitiator(payload) ? "agent" : "user"
4426
4448
  };
4427
4449
  };
4428
4450
  const hasAgentInitiator = (payload) => {
@@ -4482,7 +4504,15 @@ const containsVisionContent = (value) => {
4482
4504
 
4483
4505
  //#endregion
4484
4506
  //#region src/services/copilot/create-messages.ts
4507
+ const isAgentMessage = (msg) => {
4508
+ if (msg.role === "assistant") return true;
4509
+ if (Array.isArray(msg.content)) {
4510
+ if (msg.content.every((block) => block.type === "tool_result") && msg.content.length > 0) return true;
4511
+ }
4512
+ return false;
4513
+ };
4485
4514
  const getMessagesInitiator = (payload) => {
4515
+ if (isForceAgentEnabled()) return payload.messages.some((msg) => isAgentMessage(msg)) ? "agent" : "user";
4486
4516
  const lastMessage = payload.messages.at(-1);
4487
4517
  if (!lastMessage || lastMessage.role !== "user") return "agent";
4488
4518
  if (!Array.isArray(lastMessage.content)) return "user";
@@ -4839,7 +4869,6 @@ const logger$5 = createHandlerLogger("messages-handler");
4839
4869
  const CHAT_COMPLETIONS_ENDPOINT = "/chat/completions";
4840
4870
  const RESPONSES_ENDPOINT$1 = "/responses";
4841
4871
  const MESSAGES_ENDPOINT = "/v1/messages";
4842
- const compactSystemPromptStart = "You are a helpful AI assistant tasked with summarizing conversations";
4843
4872
  async function handleCompletion(c) {
4844
4873
  await checkRateLimit(state);
4845
4874
  const store = getRequestHistoryStore();
@@ -4907,7 +4936,7 @@ async function handleCompletion(c) {
4907
4936
  modelId: endpointModel?.id ?? openAIPayload.model,
4908
4937
  endpoint: CHAT_COMPLETIONS_ENDPOINT
4909
4938
  });
4910
- const selection = await accountsManager.selectAccountForRequest(candidates);
4939
+ const selection = await accountsManager.selectAccountForRequest(candidates, { requestId: upstreamRequestId });
4911
4940
  if (!selection.ok) return handleSelectionFailure({
4912
4941
  c,
4913
4942
  store,
@@ -4952,7 +4981,10 @@ async function handleCompletion(c) {
4952
4981
  costUnits,
4953
4982
  upstreamRequestId,
4954
4983
  premiumRemainingBefore,
4955
- premiumUnlimitedBefore
4984
+ premiumUnlimitedBefore,
4985
+ confirmAffinity: selection.confirmAffinity,
4986
+ affinityHit: selection.affinityHit,
4987
+ affinityCacheKey: selection.affinityCacheKey
4956
4988
  };
4957
4989
  if (endpoint === MESSAGES_ENDPOINT) return await handleWithMessagesApi({
4958
4990
  c,
@@ -5002,6 +5034,7 @@ const handleWithChatCompletions = async (params) => {
5002
5034
  sessionId,
5003
5035
  isCompact
5004
5036
  });
5037
+ instr.confirmAffinity?.();
5005
5038
  } catch (error) {
5006
5039
  return await handleChatCompletionsCreateError({
5007
5040
  error,
@@ -5050,6 +5083,7 @@ const handleWithResponsesApi = async (params) => {
5050
5083
  sessionId,
5051
5084
  isCompact
5052
5085
  }, ctx);
5086
+ instr.confirmAffinity?.();
5053
5087
  } catch (error) {
5054
5088
  return await handleResponsesCreateError({
5055
5089
  error,
@@ -5095,6 +5129,8 @@ function insertRequestLog$1(instr, record) {
5095
5129
  promptCacheKey: instr.promptCacheKey,
5096
5130
  initiator: instr.initiator,
5097
5131
  upstreamRequestId: instr.upstreamRequestId,
5132
+ affinityHit: instr.affinityHit,
5133
+ affinityCacheKey: instr.affinityCacheKey,
5098
5134
  clientModel,
5099
5135
  upstreamEndpoint,
5100
5136
  accountId: account.id,
@@ -5109,10 +5145,9 @@ function insertRequestLog$1(instr, record) {
5109
5145
  async function finalizeQuotaAndGetPremiumSnapshot(instr) {
5110
5146
  await accountsManager.finalizeQuota(instr.account, instr.reservation);
5111
5147
  const premiumRemainingAfter = instr.account.premiumRemaining;
5112
- const premiumUnlimitedAfter = instr.account.unlimited;
5113
5148
  return {
5114
5149
  premiumRemainingAfter,
5115
- premiumUnlimitedAfter,
5150
+ premiumUnlimitedAfter: instr.account.unlimited,
5116
5151
  premiumRemainingDiff: computeDiff(instr.premiumRemainingBefore, premiumRemainingAfter)
5117
5152
  };
5118
5153
  }
@@ -5500,6 +5535,7 @@ async function streamMessagesAndLog(params) {
5500
5535
  }
5501
5536
  const handleWithMessagesApi = async (params) => {
5502
5537
  const { c, anthropicPayload, anthropicBetaHeader, initiatorOverride, subagentMarker, sessionId, instr, selectedModel, isCompact } = params;
5538
+ stripCacheControl(anthropicPayload);
5503
5539
  for (const msg of anthropicPayload.messages) if (msg.role === "assistant" && Array.isArray(msg.content)) msg.content = msg.content.filter((block) => {
5504
5540
  if (block.type !== "thinking") return true;
5505
5541
  return block.thinking && block.thinking !== "Thinking..." && block.signature && !block.signature.includes("@");
@@ -5526,6 +5562,7 @@ const handleWithMessagesApi = async (params) => {
5526
5562
  sessionId,
5527
5563
  isCompact
5528
5564
  });
5565
+ instr.confirmAffinity?.();
5529
5566
  } catch (error) {
5530
5567
  return await handleMessagesCreateError({
5531
5568
  error,
@@ -5555,12 +5592,6 @@ const getAnthropicEffortForModel = (model) => {
5555
5592
  if (reasoningEffort === "none" || reasoningEffort === "minimal") return "low";
5556
5593
  return reasoningEffort;
5557
5594
  };
5558
- const isCompactRequest = (anthropicPayload) => {
5559
- const system = anthropicPayload.system;
5560
- if (typeof system === "string") return system.startsWith(compactSystemPromptStart);
5561
- if (!Array.isArray(system)) return false;
5562
- return system.some((msg) => typeof msg.text === "string" && msg.text.startsWith(compactSystemPromptStart));
5563
- };
5564
5595
 
5565
5596
  //#endregion
5566
5597
  //#region src/routes/messages/route.ts
@@ -5729,7 +5760,7 @@ async function forwardProviderModels(providerConfig, requestHeaders) {
5729
5760
  //#region src/routes/provider/messages/handler.ts
5730
5761
  const logger$3 = createHandlerLogger("provider-messages-handler");
5731
5762
  async function handleProviderMessages(c) {
5732
- const provider = c.req.param("provider");
5763
+ const provider = c.req.param("provider") ?? "";
5733
5764
  const providerConfig = getProviderConfig(provider);
5734
5765
  if (!providerConfig) return c.json({ error: {
5735
5766
  message: `Provider '${provider}' not found or disabled`,
@@ -5896,7 +5927,7 @@ const handleResponses = async (c) => {
5896
5927
  const payload = await c.req.json();
5897
5928
  const clientModel = payload.model;
5898
5929
  logger$1.debug("Responses request payload:", JSON.stringify(payload));
5899
- removeWebSearchTool(payload);
5930
+ if (!isResponsesApiWebSearchEnabled()) removeWebSearchTool(payload);
5900
5931
  compactInputByLatestCompaction(payload);
5901
5932
  const streamRequested = Boolean(payload.stream);
5902
5933
  const { initiator: initialInitiator } = getResponsesRequestOptions(payload);
@@ -5920,10 +5951,11 @@ const handleResponses = async (c) => {
5920
5951
  message: "This model is only available via an alias. Please use the alias model name."
5921
5952
  });
5922
5953
  }
5954
+ const upstreamRequestId = generateRequestIdFromPayload({ messages: payload.input }, normalizedPromptCacheKey);
5923
5955
  const selection = await accountsManager.selectAccountForRequest([{
5924
5956
  modelId: clientModel,
5925
5957
  endpoint: RESPONSES_ENDPOINT
5926
- }]);
5958
+ }], { requestId: upstreamRequestId });
5927
5959
  if (!selection.ok) {
5928
5960
  recordSelectionFailure(store, {
5929
5961
  request,
@@ -5934,6 +5966,8 @@ const handleResponses = async (c) => {
5934
5966
  return selectionFailureResponse(c, { reason: selection.reason });
5935
5967
  }
5936
5968
  const { account, selectedModel } = selection;
5969
+ request.affinityHit = selection.affinityHit;
5970
+ request.affinityCacheKey = selection.affinityCacheKey;
5937
5971
  const upstreamPayload = {
5938
5972
  ...payload,
5939
5973
  model: selectedModel.id
@@ -5947,7 +5981,6 @@ const handleResponses = async (c) => {
5947
5981
  request.initiator = initiator;
5948
5982
  if (state.manualApprove) await awaitApproval();
5949
5983
  const accountCtx = toAccountContext(account);
5950
- const upstreamRequestId = generateRequestIdFromPayload({ messages: upstreamPayload.input });
5951
5984
  const upstreamSessionId = getUUID(upstreamRequestId);
5952
5985
  request.upstreamRequestId = upstreamRequestId;
5953
5986
  request.upstreamSessionId = upstreamSessionId;
@@ -5984,7 +6017,6 @@ function buildRequestContext(c) {
5984
6017
  const method = c.req.raw.method;
5985
6018
  const path$2 = new URL(c.req.url, "http://local").pathname;
5986
6019
  const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
5987
- const userAgent = c.req.header("user-agent") ?? void 0;
5988
6020
  return {
5989
6021
  requestId,
5990
6022
  startedAtMs,
@@ -5992,7 +6024,7 @@ function buildRequestContext(c) {
5992
6024
  path: path$2,
5993
6025
  clientIp,
5994
6026
  clientIpSource,
5995
- userAgent
6027
+ userAgent: c.req.header("user-agent") ?? void 0
5996
6028
  };
5997
6029
  }
5998
6030
  function insertRequestLog(store, request, record) {
@@ -6009,6 +6041,8 @@ function insertRequestLog(store, request, record) {
6009
6041
  promptCacheKey: request.promptCacheKey,
6010
6042
  initiator: request.initiator,
6011
6043
  upstreamRequestId: request.upstreamRequestId,
6044
+ affinityHit: request.affinityHit,
6045
+ affinityCacheKey: request.affinityCacheKey,
6012
6046
  ...record
6013
6047
  });
6014
6048
  }
@@ -6039,8 +6073,7 @@ function selectionFailureResponse(c, params) {
6039
6073
  function extractUsageFromChunkData(data) {
6040
6074
  if (!data) return void 0;
6041
6075
  try {
6042
- const event = JSON.parse(data);
6043
- const usage = extractResponsesUsageFromStreamEvent(event);
6076
+ const usage = extractResponsesUsageFromStreamEvent(JSON.parse(data));
6044
6077
  return usage.usageJson ? usage : void 0;
6045
6078
  } catch {
6046
6079
  return;
@@ -6064,6 +6097,7 @@ async function handleStreamingResponses(params) {
6064
6097
  upstreamRequestId: request.upstreamRequestId,
6065
6098
  sessionId: request.upstreamSessionId
6066
6099
  }, accountCtx);
6100
+ selection.confirmAffinity?.();
6067
6101
  } catch (error) {
6068
6102
  return handleUpstreamCreateError({
6069
6103
  store,
@@ -6250,6 +6284,7 @@ async function handleNonStreamingResponses(params) {
6250
6284
  upstreamRequestId: request.upstreamRequestId,
6251
6285
  sessionId: request.upstreamSessionId
6252
6286
  }, accountCtx);
6287
+ selection.confirmAffinity?.();
6253
6288
  finishedAtMs = Date.now();
6254
6289
  const streamResponse = handleUnexpectedResponsesStream(c, response);
6255
6290
  if (streamResponse) return streamResponse;
@@ -6434,4 +6469,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
6434
6469
 
6435
6470
  //#endregion
6436
6471
  export { server };
6437
- //# sourceMappingURL=server-D_7gI9hx.js.map
6472
+ //# sourceMappingURL=server-DqwhClJ-.js.map