@nick3/copilot-api 1.5.6 → 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.
- package/README.md +8 -1
- package/dist/{account-AacnHem5.js → account-CbYMFuS4.js} +12 -4
- package/dist/account-CbYMFuS4.js.map +1 -0
- package/dist/accounts-manager-BKG9aZEL.js +2899 -0
- package/dist/accounts-manager-BKG9aZEL.js.map +1 -0
- package/dist/admin/assets/index-BFN8rXmt.css +1 -0
- package/dist/admin/assets/index-HnEqzcKv.js +101 -0
- package/dist/admin/index.html +2 -2
- package/dist/{auth-B7x3wjry.js → auth-Ckj1wD43.js} +3 -3
- package/dist/{auth-B7x3wjry.js.map → auth-Ckj1wD43.js.map} +1 -1
- package/dist/{check-usage-B1cbDEOI.js → check-usage-bIbj_1Q_.js} +3 -3
- package/dist/check-usage-bIbj_1Q_.js.map +1 -0
- package/dist/{get-copilot-token-cha9rQwA.js → get-copilot-token-MAZsr5Vu.js} +2 -2
- package/dist/{get-copilot-token-cha9rQwA.js.map → get-copilot-token-MAZsr5Vu.js.map} +1 -1
- package/dist/main.js +3 -3
- package/dist/{poll-access-token-DFooFWhY.js → poll-access-token-DiwBJNtK.js} +58 -33
- package/dist/poll-access-token-DiwBJNtK.js.map +1 -0
- package/dist/{server-DVpkQrk2.js → server-DAxpfPde.js} +866 -894
- package/dist/server-DAxpfPde.js.map +1 -0
- package/dist/{start-fPbCDj4c.js → start-8dkfsQqd.js} +7 -6
- package/dist/start-8dkfsQqd.js.map +1 -0
- package/package.json +1 -1
- package/dist/account-AacnHem5.js.map +0 -1
- package/dist/accounts-manager-BE-Dq5Wn.js +0 -1494
- package/dist/accounts-manager-BE-Dq5Wn.js.map +0 -1
- package/dist/admin/assets/index-CdoHTemy.css +0 -1
- package/dist/admin/assets/index-wcoGQpIM.js +0 -66
- package/dist/check-usage-B1cbDEOI.js.map +0 -1
- package/dist/poll-access-token-DFooFWhY.js.map +0 -1
- package/dist/server-DVpkQrk2.js.map +0 -1
- package/dist/start-fPbCDj4c.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import {
|
|
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-
|
|
5
|
-
import {
|
|
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,583 +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 >= 6) 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
|
-
if (current < 6) {
|
|
278
|
-
if (!db.query("PRAGMA table_info(request_log);").all().some((row) => row.name === "is_subagent")) db.run("ALTER TABLE request_log ADD COLUMN is_subagent INTEGER;");
|
|
279
|
-
db.run("PRAGMA user_version = 6;");
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
//#endregion
|
|
284
|
-
//#region src/lib/request-history.ts
|
|
285
|
-
const DEFAULT_RETENTION_DAYS = 14;
|
|
286
|
-
const DEFAULT_MAX_ROWS = 2e5;
|
|
287
|
-
const INSERT_WARN_THROTTLE_MS = 3e4;
|
|
288
|
-
let lastInsertWarnAtMs = 0;
|
|
289
|
-
let suppressedInsertWarnCount = 0;
|
|
290
|
-
function warnInsertFailure(error) {
|
|
291
|
-
const now = Date.now();
|
|
292
|
-
if (now - lastInsertWarnAtMs < INSERT_WARN_THROTTLE_MS) {
|
|
293
|
-
suppressedInsertWarnCount++;
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
const suppressed = suppressedInsertWarnCount;
|
|
297
|
-
suppressedInsertWarnCount = 0;
|
|
298
|
-
lastInsertWarnAtMs = now;
|
|
299
|
-
const suffix = suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : "";
|
|
300
|
-
consola.warn(`Failed to insert request log${suffix}`, error);
|
|
301
|
-
}
|
|
302
|
-
function toDbNull(value) {
|
|
303
|
-
return value === void 0 ? null : value;
|
|
304
|
-
}
|
|
305
|
-
function toDbBool(value) {
|
|
306
|
-
if (value === true) return 1;
|
|
307
|
-
if (value === false) return 0;
|
|
308
|
-
return null;
|
|
309
|
-
}
|
|
310
|
-
function getClientIpInfo(c) {
|
|
311
|
-
const cf = c.req.header("cf-connecting-ip");
|
|
312
|
-
if (cf) return {
|
|
313
|
-
ip: cf.trim(),
|
|
314
|
-
source: "cf-connecting-ip"
|
|
315
|
-
};
|
|
316
|
-
const xff = c.req.header("x-forwarded-for");
|
|
317
|
-
if (xff) {
|
|
318
|
-
const first = xff.split(",")[0]?.trim();
|
|
319
|
-
if (first) return {
|
|
320
|
-
ip: first,
|
|
321
|
-
source: "x-forwarded-for"
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
const xri = c.req.header("x-real-ip");
|
|
325
|
-
if (xri) return {
|
|
326
|
-
ip: xri.trim(),
|
|
327
|
-
source: "x-real-ip"
|
|
328
|
-
};
|
|
329
|
-
return {};
|
|
330
|
-
}
|
|
331
|
-
function normalizeChatCompletionsUsage(usage) {
|
|
332
|
-
if (!usage) return {};
|
|
333
|
-
const cached = usage.prompt_tokens_details?.cached_tokens ?? 0;
|
|
334
|
-
const prompt = usage.prompt_tokens;
|
|
335
|
-
const completion = usage.completion_tokens;
|
|
336
|
-
const total = usage.total_tokens;
|
|
337
|
-
return {
|
|
338
|
-
tokensCachedInput: cached,
|
|
339
|
-
tokensInput: Math.max(0, prompt - cached),
|
|
340
|
-
tokensOutput: completion,
|
|
341
|
-
tokensTotal: total,
|
|
342
|
-
usageJson: JSON.stringify(usage)
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
function normalizeResponsesUsage(usage) {
|
|
346
|
-
if (!usage) return {};
|
|
347
|
-
const cached = usage.input_tokens_details?.cached_tokens ?? 0;
|
|
348
|
-
const input = usage.input_tokens;
|
|
349
|
-
const output = usage.output_tokens ?? 0;
|
|
350
|
-
const total = usage.total_tokens;
|
|
351
|
-
return {
|
|
352
|
-
tokensCachedInput: cached,
|
|
353
|
-
tokensInput: Math.max(0, input - cached),
|
|
354
|
-
tokensOutput: output,
|
|
355
|
-
tokensTotal: total,
|
|
356
|
-
usageJson: JSON.stringify(usage)
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
function normalizeMessagesUsage(usage) {
|
|
360
|
-
if (!usage) return {};
|
|
361
|
-
const cached = usage.cache_read_input_tokens ?? 0;
|
|
362
|
-
const input = usage.input_tokens;
|
|
363
|
-
const output = usage.output_tokens;
|
|
364
|
-
const hasInput = typeof input === "number";
|
|
365
|
-
const hasOutput = typeof output === "number";
|
|
366
|
-
return {
|
|
367
|
-
tokensCachedInput: cached,
|
|
368
|
-
tokensInput: hasInput ? Math.max(0, input - cached) : void 0,
|
|
369
|
-
tokensOutput: hasOutput ? output : void 0,
|
|
370
|
-
tokensTotal: hasInput || hasOutput ? (input ?? 0) + (output ?? 0) : void 0,
|
|
371
|
-
usageJson: JSON.stringify(usage)
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
function normalizeEmbeddingsUsage(usage) {
|
|
375
|
-
if (!usage) return {};
|
|
376
|
-
return {
|
|
377
|
-
tokensCachedInput: 0,
|
|
378
|
-
tokensInput: usage.prompt_tokens,
|
|
379
|
-
tokensOutput: 0,
|
|
380
|
-
tokensTotal: usage.total_tokens,
|
|
381
|
-
usageJson: JSON.stringify(usage)
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
var RequestHistoryStore = class {
|
|
385
|
-
db;
|
|
386
|
-
insertStmt;
|
|
387
|
-
getByRequestIdStmt;
|
|
388
|
-
getLastCompletedUsageBySessionStmt;
|
|
389
|
-
constructor(db) {
|
|
390
|
-
this.db = db;
|
|
391
|
-
this.insertStmt = db.query(`
|
|
392
|
-
INSERT INTO request_log (
|
|
393
|
-
request_id,
|
|
394
|
-
started_at_ms,
|
|
395
|
-
finished_at_ms,
|
|
396
|
-
duration_ms,
|
|
397
|
-
ttfb_ms,
|
|
398
|
-
method,
|
|
399
|
-
path,
|
|
400
|
-
upstream_endpoint,
|
|
401
|
-
stream,
|
|
402
|
-
account_id,
|
|
403
|
-
account_type,
|
|
404
|
-
cost_units,
|
|
405
|
-
client_model,
|
|
406
|
-
upstream_model,
|
|
407
|
-
client_ip,
|
|
408
|
-
client_ip_source,
|
|
409
|
-
user_agent,
|
|
410
|
-
user_id,
|
|
411
|
-
safety_identifier,
|
|
412
|
-
prompt_cache_key,
|
|
413
|
-
initiator,
|
|
414
|
-
is_subagent,
|
|
415
|
-
upstream_request_id,
|
|
416
|
-
tokens_input,
|
|
417
|
-
tokens_output,
|
|
418
|
-
tokens_total,
|
|
419
|
-
tokens_cached_input,
|
|
420
|
-
usage_json,
|
|
421
|
-
premium_remaining_before,
|
|
422
|
-
premium_remaining_after,
|
|
423
|
-
premium_remaining_diff,
|
|
424
|
-
premium_unlimited_before,
|
|
425
|
-
premium_unlimited_after,
|
|
426
|
-
http_status,
|
|
427
|
-
error_name,
|
|
428
|
-
error_status,
|
|
429
|
-
error_message,
|
|
430
|
-
selection_failure_reason,
|
|
431
|
-
affinity_hit,
|
|
432
|
-
affinity_cache_key
|
|
433
|
-
) VALUES (
|
|
434
|
-
?,?,?,?,?,?,?,?,
|
|
435
|
-
?,?,?,?,?,?,?,?,
|
|
436
|
-
?,?,?,?,?,?,?,?,
|
|
437
|
-
?,?,?,?,?,?,?,?,
|
|
438
|
-
?,?,?,?,?,?,?,?
|
|
439
|
-
);
|
|
440
|
-
`);
|
|
441
|
-
this.getByRequestIdStmt = db.query("SELECT * FROM request_log WHERE request_id = ? LIMIT 1;");
|
|
442
|
-
this.getLastCompletedUsageBySessionStmt = db.query(`
|
|
443
|
-
SELECT
|
|
444
|
-
tokens_input,
|
|
445
|
-
tokens_output,
|
|
446
|
-
tokens_total,
|
|
447
|
-
tokens_cached_input
|
|
448
|
-
FROM request_log
|
|
449
|
-
WHERE prompt_cache_key = ?
|
|
450
|
-
AND safety_identifier = ?
|
|
451
|
-
AND client_model = ?
|
|
452
|
-
AND finished_at_ms IS NOT NULL
|
|
453
|
-
AND tokens_input IS NOT NULL
|
|
454
|
-
ORDER BY finished_at_ms DESC
|
|
455
|
-
LIMIT 1;
|
|
456
|
-
`);
|
|
457
|
-
}
|
|
458
|
-
insert(record) {
|
|
459
|
-
try {
|
|
460
|
-
const args = [
|
|
461
|
-
record.requestId,
|
|
462
|
-
record.startedAtMs,
|
|
463
|
-
toDbNull(record.finishedAtMs),
|
|
464
|
-
toDbNull(record.durationMs),
|
|
465
|
-
toDbNull(record.ttfbMs),
|
|
466
|
-
record.method,
|
|
467
|
-
record.path,
|
|
468
|
-
toDbNull(record.upstreamEndpoint),
|
|
469
|
-
record.stream ? 1 : 0,
|
|
470
|
-
toDbNull(record.accountId),
|
|
471
|
-
toDbNull(record.accountType),
|
|
472
|
-
toDbNull(record.costUnits),
|
|
473
|
-
toDbNull(record.clientModel),
|
|
474
|
-
toDbNull(record.upstreamModel),
|
|
475
|
-
toDbNull(record.clientIp),
|
|
476
|
-
toDbNull(record.clientIpSource),
|
|
477
|
-
toDbNull(record.userAgent),
|
|
478
|
-
toDbNull(record.userId),
|
|
479
|
-
toDbNull(record.safetyIdentifier),
|
|
480
|
-
toDbNull(record.promptCacheKey),
|
|
481
|
-
toDbNull(record.initiator),
|
|
482
|
-
toDbBool(record.isSubagent),
|
|
483
|
-
toDbNull(record.upstreamRequestId),
|
|
484
|
-
toDbNull(record.tokensInput),
|
|
485
|
-
toDbNull(record.tokensOutput),
|
|
486
|
-
toDbNull(record.tokensTotal),
|
|
487
|
-
toDbNull(record.tokensCachedInput),
|
|
488
|
-
toDbNull(record.usageJson),
|
|
489
|
-
toDbNull(record.premiumRemainingBefore),
|
|
490
|
-
toDbNull(record.premiumRemainingAfter),
|
|
491
|
-
toDbNull(record.premiumRemainingDiff),
|
|
492
|
-
toDbBool(record.premiumUnlimitedBefore),
|
|
493
|
-
toDbBool(record.premiumUnlimitedAfter),
|
|
494
|
-
toDbNull(record.httpStatus),
|
|
495
|
-
toDbNull(record.errorName),
|
|
496
|
-
toDbNull(record.errorStatus),
|
|
497
|
-
toDbNull(record.errorMessage),
|
|
498
|
-
toDbNull(record.selectionFailureReason),
|
|
499
|
-
toDbBool(record.affinityHit),
|
|
500
|
-
toDbNull(record.affinityCacheKey)
|
|
501
|
-
];
|
|
502
|
-
this.insertStmt.run(...args);
|
|
503
|
-
} catch (error) {
|
|
504
|
-
warnInsertFailure(error);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
getByRequestId(requestId) {
|
|
508
|
-
try {
|
|
509
|
-
return this.getByRequestIdStmt.get(requestId) ?? null;
|
|
510
|
-
} catch (error) {
|
|
511
|
-
consola.debug("Failed to fetch request log by request_id", error);
|
|
512
|
-
return null;
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
getLastCompletedUsageBySession(session) {
|
|
516
|
-
if (!session.promptCacheKey || !session.safetyIdentifier || !session.clientModel) return null;
|
|
517
|
-
try {
|
|
518
|
-
const row = this.getLastCompletedUsageBySessionStmt.get(session.promptCacheKey, session.safetyIdentifier, session.clientModel);
|
|
519
|
-
if (!row || row.tokens_input === null) return null;
|
|
520
|
-
const tokensOutput = row.tokens_output === null ? void 0 : row.tokens_output;
|
|
521
|
-
const tokensTotal = row.tokens_total === null ? void 0 : row.tokens_total;
|
|
522
|
-
const tokensCachedInput = row.tokens_cached_input === null ? void 0 : row.tokens_cached_input;
|
|
523
|
-
return {
|
|
524
|
-
tokensInput: row.tokens_input,
|
|
525
|
-
tokensOutput,
|
|
526
|
-
tokensTotal,
|
|
527
|
-
tokensCachedInput
|
|
528
|
-
};
|
|
529
|
-
} catch (error) {
|
|
530
|
-
consola.debug("Failed to fetch last completed usage by session", error);
|
|
531
|
-
return null;
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
query(params) {
|
|
535
|
-
const limit = Math.max(1, Math.min(params.limit, 200));
|
|
536
|
-
const where = [];
|
|
537
|
-
const values = [];
|
|
538
|
-
if (params.cursorId !== void 0) {
|
|
539
|
-
where.push("id < ?");
|
|
540
|
-
values.push(params.cursorId);
|
|
541
|
-
}
|
|
542
|
-
if (params.accountId) {
|
|
543
|
-
where.push("account_id = ?");
|
|
544
|
-
values.push(params.accountId);
|
|
545
|
-
}
|
|
546
|
-
if (params.upstreamModel) {
|
|
547
|
-
where.push("upstream_model = ?");
|
|
548
|
-
values.push(params.upstreamModel);
|
|
549
|
-
}
|
|
550
|
-
if (params.clientModel) {
|
|
551
|
-
where.push("client_model = ?");
|
|
552
|
-
values.push(params.clientModel);
|
|
553
|
-
}
|
|
554
|
-
if (params.upstreamEndpoint) {
|
|
555
|
-
where.push("upstream_endpoint = ?");
|
|
556
|
-
values.push(params.upstreamEndpoint);
|
|
557
|
-
}
|
|
558
|
-
if (params.path) {
|
|
559
|
-
where.push("path = ?");
|
|
560
|
-
values.push(params.path);
|
|
561
|
-
}
|
|
562
|
-
if (params.status !== void 0) {
|
|
563
|
-
where.push("http_status = ?");
|
|
564
|
-
values.push(params.status);
|
|
565
|
-
}
|
|
566
|
-
if (params.hasError === true) where.push("http_status >= 400");
|
|
567
|
-
if (params.hasError === false) where.push("http_status < 400");
|
|
568
|
-
if (params.fromMs !== void 0) {
|
|
569
|
-
where.push("started_at_ms >= ?");
|
|
570
|
-
values.push(params.fromMs);
|
|
571
|
-
}
|
|
572
|
-
if (params.toMs !== void 0) {
|
|
573
|
-
where.push("started_at_ms <= ?");
|
|
574
|
-
values.push(params.toMs);
|
|
575
|
-
}
|
|
576
|
-
const sql = `
|
|
577
|
-
SELECT *
|
|
578
|
-
FROM request_log
|
|
579
|
-
${where.length > 0 ? `WHERE ${where.join(" AND ")}` : ""}
|
|
580
|
-
ORDER BY id DESC
|
|
581
|
-
LIMIT ?;
|
|
582
|
-
`;
|
|
583
|
-
const rows = this.db.query(sql).all(...values, limit + 1);
|
|
584
|
-
const items = rows.slice(0, limit);
|
|
585
|
-
const hasMore = rows.length > limit;
|
|
586
|
-
return {
|
|
587
|
-
items,
|
|
588
|
-
nextCursorId: hasMore ? items.at(-1)?.id : void 0,
|
|
589
|
-
hasMore
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
getAccountStatsSince(sinceMs) {
|
|
593
|
-
try {
|
|
594
|
-
const rows = this.db.query(`
|
|
595
|
-
SELECT
|
|
596
|
-
account_id,
|
|
597
|
-
COUNT(*) AS request_count,
|
|
598
|
-
SUM(CASE WHEN http_status >= 400 THEN 1 ELSE 0 END) AS error_count,
|
|
599
|
-
COALESCE(SUM(tokens_total), 0) AS tokens_total,
|
|
600
|
-
COALESCE(AVG(duration_ms), 0) AS avg_duration_ms,
|
|
601
|
-
COALESCE(MAX(started_at_ms), 0) AS last_request_at_ms
|
|
602
|
-
FROM request_log
|
|
603
|
-
WHERE started_at_ms >= ? AND account_id IS NOT NULL
|
|
604
|
-
GROUP BY account_id;
|
|
605
|
-
`).all(sinceMs);
|
|
606
|
-
const map = {};
|
|
607
|
-
for (const row of rows) map[row.account_id] = row;
|
|
608
|
-
return map;
|
|
609
|
-
} catch (error) {
|
|
610
|
-
consola.debug("Failed to fetch account stats", error);
|
|
611
|
-
return {};
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
cleanupRetention(retentionDays = DEFAULT_RETENTION_DAYS, maxRows = DEFAULT_MAX_ROWS) {
|
|
615
|
-
try {
|
|
616
|
-
const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
|
|
617
|
-
this.db.query("DELETE FROM request_log WHERE started_at_ms < ?;").run(cutoffMs);
|
|
618
|
-
if (this.db.query("SELECT COUNT(*) AS c FROM request_log;").get().c <= maxRows) return;
|
|
619
|
-
const offset = maxRows - 1;
|
|
620
|
-
const thresholdId = this.db.query("SELECT id FROM request_log ORDER BY id DESC LIMIT 1 OFFSET ?;").get(offset)?.id;
|
|
621
|
-
if (!thresholdId) return;
|
|
622
|
-
this.db.query("DELETE FROM request_log WHERE id < ?;").run(thresholdId);
|
|
623
|
-
} catch (error) {
|
|
624
|
-
consola.debug("Failed to cleanup request_log retention", error);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
meta() {
|
|
628
|
-
return {
|
|
629
|
-
dbPath: getAdminDbPath(),
|
|
630
|
-
userVersion: getAdminDbUserVersion(this.db),
|
|
631
|
-
retentionDays: DEFAULT_RETENTION_DAYS,
|
|
632
|
-
maxRows: DEFAULT_MAX_ROWS
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
};
|
|
636
|
-
const STORE_INIT_WARN_THROTTLE_MS = 3e4;
|
|
637
|
-
const STORE_INIT_RETRY_DELAY_MS = 3e4;
|
|
638
|
-
let lastStoreInitWarnAtMs = 0;
|
|
639
|
-
let suppressedStoreInitWarnCount = 0;
|
|
640
|
-
let nextStoreRetryAtMs = 0;
|
|
641
|
-
function warnStoreInitFailure(error) {
|
|
642
|
-
const now = Date.now();
|
|
643
|
-
if (now - lastStoreInitWarnAtMs < STORE_INIT_WARN_THROTTLE_MS) {
|
|
644
|
-
suppressedStoreInitWarnCount++;
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
const suppressed = suppressedStoreInitWarnCount;
|
|
648
|
-
suppressedStoreInitWarnCount = 0;
|
|
649
|
-
lastStoreInitWarnAtMs = now;
|
|
650
|
-
const suffix = suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : "";
|
|
651
|
-
consola.warn(`Request history store is disabled${suffix}`, error);
|
|
652
|
-
}
|
|
653
|
-
const disabledStore = {
|
|
654
|
-
insert: () => {},
|
|
655
|
-
getByRequestId: () => null,
|
|
656
|
-
getLastCompletedUsageBySession: () => null,
|
|
657
|
-
query: () => ({
|
|
658
|
-
items: [],
|
|
659
|
-
hasMore: false
|
|
660
|
-
}),
|
|
661
|
-
getAccountStatsSince: () => ({}),
|
|
662
|
-
cleanupRetention: () => {},
|
|
663
|
-
meta: () => ({
|
|
664
|
-
dbPath: getAdminDbPath(),
|
|
665
|
-
userVersion: 0,
|
|
666
|
-
retentionDays: DEFAULT_RETENTION_DAYS,
|
|
667
|
-
maxRows: DEFAULT_MAX_ROWS
|
|
668
|
-
})
|
|
669
|
-
};
|
|
670
|
-
let sharedStore = null;
|
|
671
|
-
let maintenanceStarted = false;
|
|
672
|
-
function getRequestHistoryStore() {
|
|
673
|
-
if (sharedStore) return sharedStore;
|
|
674
|
-
const now = Date.now();
|
|
675
|
-
if (now < nextStoreRetryAtMs) return disabledStore;
|
|
676
|
-
try {
|
|
677
|
-
sharedStore = new RequestHistoryStore(getAdminDb());
|
|
678
|
-
if (!maintenanceStarted) {
|
|
679
|
-
maintenanceStarted = true;
|
|
680
|
-
sharedStore.cleanupRetention();
|
|
681
|
-
setInterval(() => {
|
|
682
|
-
sharedStore?.cleanupRetention();
|
|
683
|
-
}, 1440 * 60 * 1e3);
|
|
684
|
-
}
|
|
685
|
-
return sharedStore;
|
|
686
|
-
} catch (error) {
|
|
687
|
-
nextStoreRetryAtMs = now + STORE_INIT_RETRY_DELAY_MS;
|
|
688
|
-
warnStoreInitFailure(error);
|
|
689
|
-
return disabledStore;
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
function extractResponsesUsageFromStreamEvent(event) {
|
|
693
|
-
if (event.type === "response.completed" || event.type === "response.incomplete") return normalizeResponsesUsage(event.response.usage);
|
|
694
|
-
if (event.type === "response.failed") return normalizeResponsesUsage(event.response.usage);
|
|
695
|
-
return {};
|
|
696
|
-
}
|
|
697
|
-
function extractResponsesUsageFromResult(result) {
|
|
698
|
-
return normalizeResponsesUsage(result.usage);
|
|
699
|
-
}
|
|
700
|
-
|
|
701
123
|
//#endregion
|
|
702
124
|
//#region src/routes/admin-api/auth-sessions.ts
|
|
703
125
|
function buildOauthUrls(enterpriseDomain) {
|
|
@@ -917,6 +339,7 @@ const CONFIG_KEYS = new Set([
|
|
|
917
339
|
"auth",
|
|
918
340
|
"extraPrompts",
|
|
919
341
|
"smallModel",
|
|
342
|
+
"logLevel",
|
|
920
343
|
"accountAffinity",
|
|
921
344
|
"apiKey",
|
|
922
345
|
"anthropicApiKey",
|
|
@@ -930,6 +353,7 @@ const CONFIG_KEYS = new Set([
|
|
|
930
353
|
"compactUseSmallModel",
|
|
931
354
|
"messageStartInputTokensFallback",
|
|
932
355
|
"modelRefreshIntervalHours",
|
|
356
|
+
"sessionAffinityRetentionDays",
|
|
933
357
|
"useMessagesApi",
|
|
934
358
|
"useResponsesApiWebSearch"
|
|
935
359
|
]);
|
|
@@ -941,6 +365,12 @@ const REASONING_EFFORTS = new Set([
|
|
|
941
365
|
"high",
|
|
942
366
|
"xhigh"
|
|
943
367
|
]);
|
|
368
|
+
const LOG_LEVELS = new Set([
|
|
369
|
+
"error",
|
|
370
|
+
"warn",
|
|
371
|
+
"info",
|
|
372
|
+
"debug"
|
|
373
|
+
]);
|
|
944
374
|
const BLOCKED_KEYS = new Set([
|
|
945
375
|
"__proto__",
|
|
946
376
|
"constructor",
|
|
@@ -959,6 +389,13 @@ function parseOptionalString(value, field) {
|
|
|
959
389
|
if (!trimmed) return { clear: true };
|
|
960
390
|
return { value: trimmed };
|
|
961
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
|
+
}
|
|
962
399
|
function parseOptionalBoolean(value, field) {
|
|
963
400
|
if (value === null || value === void 0) return { clear: true };
|
|
964
401
|
if (typeof value !== "boolean") return { error: `${field} must be a boolean` };
|
|
@@ -1238,6 +675,15 @@ function applyAuthConfig(next, value) {
|
|
|
1238
675
|
}
|
|
1239
676
|
next.auth = parsed.value;
|
|
1240
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
|
+
}
|
|
1241
687
|
function applyOptionalBoolean(next, key, value) {
|
|
1242
688
|
const parsed = parseOptionalBoolean(value, key);
|
|
1243
689
|
if ("error" in parsed) return parsed.error;
|
|
@@ -1305,6 +751,7 @@ const CONFIG_PATCH_HANDLERS = {
|
|
|
1305
751
|
auth: applyAuthConfig,
|
|
1306
752
|
extraPrompts: applyExtraPrompts,
|
|
1307
753
|
smallModel: (next, value) => applyOptionalString(next, "smallModel", value),
|
|
754
|
+
logLevel: applyLogLevel,
|
|
1308
755
|
accountAffinity: (next, value) => applyOptionalBoolean(next, "accountAffinity", value),
|
|
1309
756
|
apiKey: (next, value) => applyOptionalString(next, "apiKey", value),
|
|
1310
757
|
anthropicApiKey: (next, value) => applyOptionalString(next, "anthropicApiKey", value),
|
|
@@ -1318,6 +765,7 @@ const CONFIG_PATCH_HANDLERS = {
|
|
|
1318
765
|
compactUseSmallModel: (next, value) => applyOptionalBoolean(next, "compactUseSmallModel", value),
|
|
1319
766
|
messageStartInputTokensFallback: (next, value) => applyOptionalBoolean(next, "messageStartInputTokensFallback", value),
|
|
1320
767
|
modelRefreshIntervalHours: (next, value) => applyOptionalNumber(next, "modelRefreshIntervalHours", value),
|
|
768
|
+
sessionAffinityRetentionDays: (next, value) => applyOptionalNumber(next, "sessionAffinityRetentionDays", value),
|
|
1321
769
|
useMessagesApi: (next, value) => applyOptionalBoolean(next, "useMessagesApi", value),
|
|
1322
770
|
useResponsesApiWebSearch: (next, value) => applyOptionalBoolean(next, "useResponsesApiWebSearch", value)
|
|
1323
771
|
};
|
|
@@ -1400,6 +848,7 @@ adminApiRoutes.post("/config", async (c) => {
|
|
|
1400
848
|
const merged = mergeConfigWithDefaults();
|
|
1401
849
|
accountsManager.setAccountAffinityEnabled(isAccountAffinityEnabled());
|
|
1402
850
|
accountsManager.setModelsRefreshIntervalMs(getModelRefreshIntervalMs());
|
|
851
|
+
applySharedSessionAffinityRetention();
|
|
1403
852
|
return c.json({
|
|
1404
853
|
...merged,
|
|
1405
854
|
_configPath: PATHS.CONFIG_PATH
|
|
@@ -1548,7 +997,8 @@ adminApiRoutes.get("/accounts", async (c) => {
|
|
|
1548
997
|
remaining: s.remaining,
|
|
1549
998
|
unlimited: s.unlimited,
|
|
1550
999
|
failed: s.failed,
|
|
1551
|
-
failureReason: s.failureReason
|
|
1000
|
+
failureReason: s.failureReason,
|
|
1001
|
+
enabled: s.enabled
|
|
1552
1002
|
},
|
|
1553
1003
|
stats
|
|
1554
1004
|
};
|
|
@@ -1608,11 +1058,7 @@ adminApiRoutes.post("/accounts/auth/start", async (c) => {
|
|
|
1608
1058
|
});
|
|
1609
1059
|
const enterpriseDomainRaw = payload.enterpriseDomain;
|
|
1610
1060
|
let enterpriseDomain;
|
|
1611
|
-
if (accountType === "enterprise" && typeof enterpriseDomainRaw === "string") enterpriseDomain = enterpriseDomainRaw.trim();
|
|
1612
|
-
if (accountType === "enterprise" && !enterpriseDomain) return jsonError(c, 400, {
|
|
1613
|
-
message: "enterpriseDomain is required for enterprise accounts.",
|
|
1614
|
-
type: "bad_request"
|
|
1615
|
-
});
|
|
1061
|
+
if (accountType === "enterprise" && typeof enterpriseDomainRaw === "string") enterpriseDomain = enterpriseDomainRaw.trim() || void 0;
|
|
1616
1062
|
try {
|
|
1617
1063
|
const result = await authSessionManager.startAuth({
|
|
1618
1064
|
accountType,
|
|
@@ -1643,6 +1089,40 @@ adminApiRoutes.post("/accounts/auth/cancel/:sessionId", (c) => {
|
|
|
1643
1089
|
});
|
|
1644
1090
|
return c.json({ cancelled: true });
|
|
1645
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
|
+
});
|
|
1646
1126
|
adminApiRoutes.delete("/accounts/:id", async (c) => {
|
|
1647
1127
|
const accountId = c.req.param("id");
|
|
1648
1128
|
try {
|
|
@@ -1656,6 +1136,7 @@ adminApiRoutes.delete("/accounts/:id", async (c) => {
|
|
|
1656
1136
|
} catch (error) {
|
|
1657
1137
|
console.error(`Account ${accountId} deleted but token cleanup failed.`, error);
|
|
1658
1138
|
}
|
|
1139
|
+
await accountsManager.reloadRegistryNow();
|
|
1659
1140
|
return c.json({
|
|
1660
1141
|
deleted: true,
|
|
1661
1142
|
accountId
|
|
@@ -1679,10 +1160,6 @@ adminApiRoutes.post("/accounts/:id/reauth", async (c) => {
|
|
|
1679
1160
|
const resolvedEnterpriseDomain = (await getAccountClientIdentityByLoginAndApp(accountId, oauthApp))?.enterpriseDomain;
|
|
1680
1161
|
let enterpriseDomain;
|
|
1681
1162
|
if (resolvedEnterpriseDomain && resolvedEnterpriseDomain !== DEFAULT_IDENTITY_ENTERPRISE_DOMAIN) enterpriseDomain = resolvedEnterpriseDomain;
|
|
1682
|
-
if (account.accountType === "enterprise" && !enterpriseDomain) return jsonError(c, 400, {
|
|
1683
|
-
message: "Cannot re-authenticate enterprise account: enterprise domain could not be resolved from stored identity.",
|
|
1684
|
-
type: "bad_request"
|
|
1685
|
-
});
|
|
1686
1163
|
const result = await authSessionManager.startAuth({
|
|
1687
1164
|
accountType: account.accountType,
|
|
1688
1165
|
enterpriseDomain,
|
|
@@ -1696,6 +1173,70 @@ adminApiRoutes.post("/accounts/:id/reauth", async (c) => {
|
|
|
1696
1173
|
});
|
|
1697
1174
|
}
|
|
1698
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
|
+
});
|
|
1699
1240
|
|
|
1700
1241
|
//#endregion
|
|
1701
1242
|
//#region src/routes/admin/route.ts
|
|
@@ -2365,39 +1906,122 @@ function toAccountContext(account) {
|
|
|
2365
1906
|
clientSessionId: account.clientSessionId
|
|
2366
1907
|
};
|
|
2367
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
|
+
}
|
|
2368
1957
|
function extractErrorDetails(error) {
|
|
2369
1958
|
const errorName = error instanceof Error ? error.name : "Error";
|
|
2370
1959
|
const errorMessage = error instanceof Error ? truncate(error.message) : truncate(String(error));
|
|
2371
1960
|
const errorStatus = error instanceof HTTPError ? error.response.status : void 0;
|
|
1961
|
+
const httpStatus = errorStatus ?? 500;
|
|
1962
|
+
const unauthorized = errorStatus === 401;
|
|
2372
1963
|
return {
|
|
2373
|
-
httpStatus
|
|
1964
|
+
httpStatus,
|
|
2374
1965
|
errorName,
|
|
2375
1966
|
errorStatus,
|
|
2376
1967
|
errorMessage,
|
|
2377
|
-
unauthorized
|
|
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
|
|
2378
1981
|
};
|
|
2379
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
|
+
}
|
|
2380
1994
|
|
|
2381
1995
|
//#endregion
|
|
2382
1996
|
//#region src/lib/logger.ts
|
|
2383
1997
|
const LOG_RETENTION_MS = 10080 * 60 * 1e3;
|
|
2384
1998
|
const CLEANUP_INTERVAL_MS = 1440 * 60 * 1e3;
|
|
2385
|
-
const LOG_DIR = path.join(PATHS.APP_DIR, "logs");
|
|
2386
1999
|
const FLUSH_INTERVAL_MS = 1e3;
|
|
2387
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;
|
|
2388
2009
|
const logStreams = /* @__PURE__ */ new Map();
|
|
2389
2010
|
const logBuffers = /* @__PURE__ */ new Map();
|
|
2390
2011
|
let runtimeInitialized = false;
|
|
2391
2012
|
let flushInterval;
|
|
2392
2013
|
let cleanupInterval;
|
|
2014
|
+
let exitHandler;
|
|
2015
|
+
let sigintHandler;
|
|
2016
|
+
let sigtermHandler;
|
|
2393
2017
|
const ensureLogDirectory = () => {
|
|
2394
|
-
if (!fs$1.existsSync(
|
|
2018
|
+
if (!fs$1.existsSync(logDir)) fs$1.mkdirSync(logDir, { recursive: true });
|
|
2395
2019
|
};
|
|
2396
2020
|
const cleanupOldLogs = () => {
|
|
2397
|
-
if (!fs$1.existsSync(
|
|
2021
|
+
if (!fs$1.existsSync(logDir)) return;
|
|
2398
2022
|
const now = Date.now();
|
|
2399
|
-
for (const entry of fs$1.readdirSync(
|
|
2400
|
-
const filePath = path.join(
|
|
2023
|
+
for (const entry of fs$1.readdirSync(logDir)) {
|
|
2024
|
+
const filePath = path.join(logDir, entry);
|
|
2401
2025
|
let stats;
|
|
2402
2026
|
try {
|
|
2403
2027
|
stats = fs$1.statSync(filePath);
|
|
@@ -2420,6 +2044,14 @@ const sanitizeName = (name) => {
|
|
|
2420
2044
|
const normalized = name.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replaceAll(/^-+|-+$/g, "");
|
|
2421
2045
|
return normalized === "" ? "handler" : normalized;
|
|
2422
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
|
+
};
|
|
2423
2055
|
const maybeUnref = (timer) => {
|
|
2424
2056
|
timer.unref();
|
|
2425
2057
|
};
|
|
@@ -2459,15 +2091,18 @@ const initializeLoggerRuntime = () => {
|
|
|
2459
2091
|
maybeUnref(flushInterval);
|
|
2460
2092
|
cleanupInterval = setInterval(cleanupOldLogs, CLEANUP_INTERVAL_MS);
|
|
2461
2093
|
maybeUnref(cleanupInterval);
|
|
2462
|
-
|
|
2463
|
-
|
|
2094
|
+
exitHandler = cleanup;
|
|
2095
|
+
sigintHandler = () => {
|
|
2464
2096
|
cleanup();
|
|
2465
2097
|
process.exit(0);
|
|
2466
|
-
}
|
|
2467
|
-
|
|
2098
|
+
};
|
|
2099
|
+
sigtermHandler = () => {
|
|
2468
2100
|
cleanup();
|
|
2469
2101
|
process.exit(0);
|
|
2470
|
-
}
|
|
2102
|
+
};
|
|
2103
|
+
process.once("exit", exitHandler);
|
|
2104
|
+
process.once("SIGINT", sigintHandler);
|
|
2105
|
+
process.once("SIGTERM", sigtermHandler);
|
|
2471
2106
|
};
|
|
2472
2107
|
const getLogStream = (filePath) => {
|
|
2473
2108
|
initializeLoggerRuntime();
|
|
@@ -2491,8 +2126,21 @@ const appendLine = (filePath, line) => {
|
|
|
2491
2126
|
buffer.push(line);
|
|
2492
2127
|
if (buffer.length >= MAX_BUFFER_SIZE) flushBuffer(filePath);
|
|
2493
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";
|
|
2494
2142
|
const debugLazy = (logger$7, factory) => {
|
|
2495
|
-
if (!
|
|
2143
|
+
if (!isDebugFileLoggingEnabled()) return;
|
|
2496
2144
|
logger$7.debug(...factory());
|
|
2497
2145
|
};
|
|
2498
2146
|
const debugJson = (logger$7, label, value) => {
|
|
@@ -2501,18 +2149,31 @@ const debugJson = (logger$7, label, value) => {
|
|
|
2501
2149
|
const debugJsonTail = (logger$7, label, { value, tailLength = 400 }) => {
|
|
2502
2150
|
debugLazy(logger$7, () => [label, JSON.stringify(value).slice(-tailLength)]);
|
|
2503
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
|
+
};
|
|
2504
2162
|
const createHandlerLogger = (name) => {
|
|
2505
|
-
const sanitizedName = sanitizeName(name);
|
|
2506
2163
|
const instance = consola.withTag(name);
|
|
2507
|
-
|
|
2164
|
+
Object.defineProperty(instance, "level", {
|
|
2165
|
+
get: getConsolaLevel,
|
|
2166
|
+
configurable: true
|
|
2167
|
+
});
|
|
2508
2168
|
instance.setReporters([]);
|
|
2509
2169
|
instance.addReporter({ log(logObj) {
|
|
2170
|
+
const fileLogLevel = resolveLogLevel();
|
|
2171
|
+
if (!shouldWriteFileLog(logObj.type, fileLogLevel)) return;
|
|
2510
2172
|
initializeLoggerRuntime();
|
|
2511
2173
|
const traceId = requestContext.getStore()?.traceId;
|
|
2512
2174
|
const date = logObj.date;
|
|
2513
|
-
const dateKey = date.toLocaleDateString("sv-SE");
|
|
2514
2175
|
const timestamp = date.toLocaleString("sv-SE", { hour12: false });
|
|
2515
|
-
const filePath =
|
|
2176
|
+
const filePath = getHandlerLogFilePath(name, date);
|
|
2516
2177
|
const message = formatArgs(logObj.args);
|
|
2517
2178
|
const traceIdStr = traceId ? ` [${traceId}]` : "";
|
|
2518
2179
|
appendLine(filePath, `[${timestamp}] [${logObj.type}] [${logObj.tag || name}]${traceIdStr}${message ? ` ${message}` : ""}`);
|
|
@@ -2761,6 +2422,13 @@ const getTokenCount = async (payload, model) => {
|
|
|
2761
2422
|
};
|
|
2762
2423
|
};
|
|
2763
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
|
+
|
|
2764
2432
|
//#endregion
|
|
2765
2433
|
//#region src/services/copilot/create-chat-completions.ts
|
|
2766
2434
|
function isGpt5MiniFamily(modelId) {
|
|
@@ -2784,10 +2452,13 @@ const createChatCompletions = async (payload, account, options) => {
|
|
|
2784
2452
|
const ctx = account ?? accountFromState();
|
|
2785
2453
|
if (!ctx.copilotToken) throw new Error("Copilot token not found");
|
|
2786
2454
|
const enableVision = payload.messages.some((x) => typeof x.content !== "string" && x.content?.some((x$1) => x$1.type === "image_url"));
|
|
2787
|
-
const
|
|
2455
|
+
const effectiveInitiator = resolveEffectiveInitiator(options?.initiator ?? getChatInitiator(payload.messages), {
|
|
2456
|
+
isCompact: options?.isCompact,
|
|
2457
|
+
isSubagent: Boolean(options?.subagentMarker)
|
|
2458
|
+
});
|
|
2788
2459
|
const headers = {
|
|
2789
2460
|
...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
|
|
2790
|
-
"x-initiator":
|
|
2461
|
+
"x-initiator": effectiveInitiator
|
|
2791
2462
|
};
|
|
2792
2463
|
prepareInteractionHeaders(options?.sessionId, Boolean(options?.subagentMarker), headers);
|
|
2793
2464
|
const upstreamPayload = applyDefaultReasoningEffort(payload);
|
|
@@ -2805,26 +2476,136 @@ const createChatCompletions = async (payload, account, options) => {
|
|
|
2805
2476
|
return await response.json();
|
|
2806
2477
|
};
|
|
2807
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
|
+
|
|
2808
2587
|
//#endregion
|
|
2809
2588
|
//#region src/routes/chat-completions/handler.ts
|
|
2810
2589
|
const logger$6 = createHandlerLogger("chat-completions-handler");
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
const {
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
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
|
+
}
|
|
2828
2609
|
if (getAliasTargetSet().has(clientModel.toLowerCase())) {
|
|
2829
2610
|
recordSelectionFailure$2(store, {
|
|
2830
2611
|
request,
|
|
@@ -2837,36 +2618,60 @@ async function handleCompletion$1(c) {
|
|
|
2837
2618
|
reason: "MODEL_NOT_SUPPORTED"
|
|
2838
2619
|
});
|
|
2839
2620
|
}
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
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
|
|
2843
2635
|
});
|
|
2844
|
-
|
|
2845
|
-
const
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
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, {
|
|
2851
2657
|
request,
|
|
2852
2658
|
clientModel,
|
|
2853
2659
|
stream: streamRequested,
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
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
|
|
2859
2668
|
});
|
|
2669
|
+
return unsupportedChatCompletionsModelResponse(c);
|
|
2860
2670
|
}
|
|
2861
|
-
const { account, selectedModel } = selection;
|
|
2862
|
-
request.affinityHit = selection.affinityHit;
|
|
2863
|
-
request.affinityCacheKey = selection.affinityCacheKey;
|
|
2864
2671
|
const upstreamPayload = {
|
|
2865
2672
|
...payload,
|
|
2866
2673
|
model: selectedModel.id
|
|
2867
2674
|
};
|
|
2868
|
-
const premiumRemainingBefore = account.premiumRemaining;
|
|
2869
|
-
const premiumUnlimitedBefore = account.unlimited;
|
|
2870
2675
|
await logTokenCountForRequest({
|
|
2871
2676
|
payload: upstreamPayload,
|
|
2872
2677
|
selectedModel
|
|
@@ -2874,7 +2679,7 @@ async function handleCompletion$1(c) {
|
|
|
2874
2679
|
if (state.manualApprove) await awaitApproval();
|
|
2875
2680
|
const payloadWithMaxTokens = applyDefaultMaxTokens(upstreamPayload, selectedModel);
|
|
2876
2681
|
const accountCtx = toAccountContext(account);
|
|
2877
|
-
const upstreamSessionId = getUUID(upstreamRequestId);
|
|
2682
|
+
const upstreamSessionId = getUUID(normalizedPromptCacheKey ?? headerSessionId ?? upstreamRequestId);
|
|
2878
2683
|
request.upstreamRequestId = upstreamRequestId;
|
|
2879
2684
|
request.upstreamSessionId = upstreamSessionId;
|
|
2880
2685
|
if (streamRequested) return handleStreamingRequest({
|
|
@@ -2900,64 +2705,60 @@ async function handleCompletion$1(c) {
|
|
|
2900
2705
|
premiumUnlimitedBefore
|
|
2901
2706
|
});
|
|
2902
2707
|
}
|
|
2903
|
-
function
|
|
2904
|
-
const
|
|
2905
|
-
const
|
|
2906
|
-
const
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
method,
|
|
2913
|
-
path: path$2,
|
|
2914
|
-
clientIp,
|
|
2915
|
-
clientIpSource,
|
|
2916
|
-
userAgent: c.req.header("user-agent") ?? void 0
|
|
2917
|
-
};
|
|
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;
|
|
2918
2717
|
}
|
|
2919
|
-
function
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
safetyIdentifier: request.safetyIdentifier,
|
|
2930
|
-
promptCacheKey: request.promptCacheKey,
|
|
2931
|
-
initiator: request.initiator,
|
|
2932
|
-
upstreamRequestId: request.upstreamRequestId,
|
|
2933
|
-
affinityHit: request.affinityHit,
|
|
2934
|
-
affinityCacheKey: request.affinityCacheKey,
|
|
2935
|
-
...record
|
|
2936
|
-
});
|
|
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
|
+
}
|
|
2937
2728
|
}
|
|
2938
|
-
function
|
|
2939
|
-
const { request,
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
durationMs: finishedAtMs - request.startedAtMs,
|
|
2944
|
-
upstreamEndpoint: CHAT_COMPLETIONS_ENDPOINT$1,
|
|
2945
|
-
stream,
|
|
2946
|
-
clientModel,
|
|
2947
|
-
httpStatus: reason === "MODEL_NOT_SUPPORTED" ? 400 : 429,
|
|
2948
|
-
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
|
|
2949
2734
|
});
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
const
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
}
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
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
|
+
};
|
|
2961
2762
|
}
|
|
2962
2763
|
async function logTokenCountForRequest(params) {
|
|
2963
2764
|
try {
|
|
@@ -3022,8 +2823,8 @@ async function handleUpstreamCreateError$1(params) {
|
|
|
3022
2823
|
const { store, request, selection, clientModel, premiumRemainingBefore, premiumUnlimitedBefore, error } = params;
|
|
3023
2824
|
const { account, reservation, selectedModel, endpoint, costUnits } = selection;
|
|
3024
2825
|
const finishedAtMs = Date.now();
|
|
3025
|
-
const details =
|
|
3026
|
-
if (details
|
|
2826
|
+
const details = await extractErrorObservability(error);
|
|
2827
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
|
|
3027
2828
|
await accountsManager.finalizeQuota(account, reservation);
|
|
3028
2829
|
const premiumRemainingAfter = account.premiumRemaining;
|
|
3029
2830
|
const premiumUnlimitedAfter = account.unlimited;
|
|
@@ -3045,7 +2846,8 @@ async function handleUpstreamCreateError$1(params) {
|
|
|
3045
2846
|
httpStatus: details.httpStatus,
|
|
3046
2847
|
errorName: details.errorName,
|
|
3047
2848
|
errorStatus: details.errorStatus,
|
|
3048
|
-
errorMessage: details.errorMessage
|
|
2849
|
+
errorMessage: details.errorMessage,
|
|
2850
|
+
upstreamErrorMessageRaw: details.upstreamErrorMessageRaw
|
|
3049
2851
|
});
|
|
3050
2852
|
throw error;
|
|
3051
2853
|
}
|
|
@@ -3057,16 +2859,18 @@ async function handleNonStreamingUpstreamResponse(params) {
|
|
|
3057
2859
|
let errorName;
|
|
3058
2860
|
let errorStatus;
|
|
3059
2861
|
let errorMessage;
|
|
2862
|
+
let upstreamErrorMessageRaw;
|
|
3060
2863
|
const finishedAtMs = Date.now();
|
|
3061
2864
|
try {
|
|
3062
2865
|
debugJson(logger$6, "Non-streaming response:", response);
|
|
3063
2866
|
return c.json(response);
|
|
3064
2867
|
} catch (error) {
|
|
3065
|
-
const details =
|
|
2868
|
+
const details = await extractErrorObservability(error);
|
|
3066
2869
|
httpStatus = details.httpStatus;
|
|
3067
2870
|
errorName = details.errorName;
|
|
3068
2871
|
errorStatus = details.errorStatus;
|
|
3069
2872
|
errorMessage = details.errorMessage;
|
|
2873
|
+
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
3070
2874
|
throw error;
|
|
3071
2875
|
} finally {
|
|
3072
2876
|
await accountsManager.finalizeQuota(account, reservation);
|
|
@@ -3091,7 +2895,8 @@ async function handleNonStreamingUpstreamResponse(params) {
|
|
|
3091
2895
|
httpStatus,
|
|
3092
2896
|
errorName,
|
|
3093
2897
|
errorStatus,
|
|
3094
|
-
errorMessage
|
|
2898
|
+
errorMessage,
|
|
2899
|
+
upstreamErrorMessageRaw
|
|
3095
2900
|
});
|
|
3096
2901
|
}
|
|
3097
2902
|
}
|
|
@@ -3103,6 +2908,7 @@ async function streamChatCompletionsAndLog$1(params) {
|
|
|
3103
2908
|
let errorName;
|
|
3104
2909
|
let errorStatus;
|
|
3105
2910
|
let errorMessage;
|
|
2911
|
+
let upstreamErrorMessageRaw;
|
|
3106
2912
|
try {
|
|
3107
2913
|
for await (const rawChunk of response) {
|
|
3108
2914
|
const chunk = rawChunk;
|
|
@@ -3113,11 +2919,14 @@ async function streamChatCompletionsAndLog$1(params) {
|
|
|
3113
2919
|
await stream.writeSSE(chunk);
|
|
3114
2920
|
}
|
|
3115
2921
|
} catch (error) {
|
|
3116
|
-
const details =
|
|
2922
|
+
const details = await extractErrorObservability(error);
|
|
3117
2923
|
errorName = details.errorName;
|
|
3118
2924
|
errorStatus = details.errorStatus;
|
|
3119
2925
|
errorMessage = details.errorMessage;
|
|
2926
|
+
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
3120
2927
|
logger$6.warn("Streaming error:", error);
|
|
2928
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
|
|
2929
|
+
await writeChatCompletionsStreamError(stream, getUserVisibleErrorMessage(details));
|
|
3121
2930
|
} finally {
|
|
3122
2931
|
const finishedAtMs = Date.now();
|
|
3123
2932
|
await accountsManager.finalizeQuota(account, reservation);
|
|
@@ -3143,18 +2952,29 @@ async function streamChatCompletionsAndLog$1(params) {
|
|
|
3143
2952
|
httpStatus: errorStatus ?? (errorName ? 500 : 200),
|
|
3144
2953
|
errorName,
|
|
3145
2954
|
errorStatus,
|
|
3146
|
-
errorMessage
|
|
2955
|
+
errorMessage,
|
|
2956
|
+
upstreamErrorMessageRaw
|
|
3147
2957
|
});
|
|
3148
2958
|
}
|
|
3149
2959
|
}
|
|
3150
2960
|
async function extractUsageFromChunk(chunk) {
|
|
3151
|
-
|
|
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
|
+
}
|
|
3152
2968
|
if (!data || data === "[DONE]") return;
|
|
3153
2969
|
try {
|
|
3154
2970
|
const parsed = JSON.parse(data);
|
|
3155
2971
|
if (!parsed.usage) return void 0;
|
|
3156
2972
|
return normalizeChatCompletionsUsage(parsed.usage);
|
|
3157
|
-
} catch {
|
|
2973
|
+
} catch (error) {
|
|
2974
|
+
logger$6.warn("Failed to parse chat completions usage chunk:", {
|
|
2975
|
+
error,
|
|
2976
|
+
data
|
|
2977
|
+
});
|
|
3158
2978
|
return;
|
|
3159
2979
|
}
|
|
3160
2980
|
}
|
|
@@ -3166,31 +2986,28 @@ async function handleNonStreamingRequest(params) {
|
|
|
3166
2986
|
let errorName;
|
|
3167
2987
|
let errorStatus;
|
|
3168
2988
|
let errorMessage;
|
|
2989
|
+
let upstreamErrorMessageRaw;
|
|
3169
2990
|
let finishedAtMs;
|
|
3170
2991
|
try {
|
|
3171
2992
|
const response = await createChatCompletions(payload, accountCtx, {
|
|
3172
2993
|
upstreamRequestId: request.upstreamRequestId,
|
|
3173
2994
|
sessionId: request.upstreamSessionId
|
|
3174
2995
|
});
|
|
2996
|
+
if (!isNonStreaming$1(response)) throw new Error("Upstream returned a stream unexpectedly");
|
|
3175
2997
|
selection.confirmAffinity?.();
|
|
3176
2998
|
finishedAtMs = Date.now();
|
|
3177
|
-
if (!isNonStreaming$1(response)) {
|
|
3178
|
-
logger$6.debug("Unexpected streaming response");
|
|
3179
|
-
return streamSSE(c, async (stream) => {
|
|
3180
|
-
for await (const chunk of response) await stream.writeSSE(chunk);
|
|
3181
|
-
});
|
|
3182
|
-
}
|
|
3183
2999
|
usage = normalizeChatCompletionsUsage(response.usage);
|
|
3184
3000
|
debugJson(logger$6, "Non-streaming response:", response);
|
|
3185
3001
|
return c.json(response);
|
|
3186
3002
|
} catch (error) {
|
|
3187
3003
|
finishedAtMs = Date.now();
|
|
3188
|
-
const details =
|
|
3004
|
+
const details = await extractErrorObservability(error);
|
|
3189
3005
|
httpStatus = details.httpStatus;
|
|
3190
3006
|
errorName = details.errorName;
|
|
3191
3007
|
errorStatus = details.errorStatus;
|
|
3192
3008
|
errorMessage = details.errorMessage;
|
|
3193
|
-
|
|
3009
|
+
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
3010
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
|
|
3194
3011
|
throw error;
|
|
3195
3012
|
} finally {
|
|
3196
3013
|
const finishedAtMsFinal = finishedAtMs ?? Date.now();
|
|
@@ -3216,7 +3033,8 @@ async function handleNonStreamingRequest(params) {
|
|
|
3216
3033
|
httpStatus,
|
|
3217
3034
|
errorName,
|
|
3218
3035
|
errorStatus,
|
|
3219
|
-
errorMessage
|
|
3036
|
+
errorMessage,
|
|
3037
|
+
upstreamErrorMessageRaw
|
|
3220
3038
|
});
|
|
3221
3039
|
}
|
|
3222
3040
|
}
|
|
@@ -3344,6 +3162,7 @@ async function runEmbeddingsWithAccount({ c, store, ctx, payload, clientModel, s
|
|
|
3344
3162
|
let errorName;
|
|
3345
3163
|
let errorStatus;
|
|
3346
3164
|
let errorMessage;
|
|
3165
|
+
let upstreamErrorMessageRaw;
|
|
3347
3166
|
let finishedAtMs;
|
|
3348
3167
|
try {
|
|
3349
3168
|
const response = await createEmbeddings(payload, toAccountContext(account));
|
|
@@ -3352,12 +3171,13 @@ async function runEmbeddingsWithAccount({ c, store, ctx, payload, clientModel, s
|
|
|
3352
3171
|
return c.json(response);
|
|
3353
3172
|
} catch (error) {
|
|
3354
3173
|
finishedAtMs = Date.now();
|
|
3355
|
-
const details =
|
|
3174
|
+
const details = await extractErrorObservability(error);
|
|
3356
3175
|
httpStatus = details.httpStatus;
|
|
3357
3176
|
errorName = details.errorName;
|
|
3358
3177
|
errorStatus = details.errorStatus;
|
|
3359
3178
|
errorMessage = details.errorMessage;
|
|
3360
|
-
|
|
3179
|
+
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
3180
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
|
|
3361
3181
|
throw error;
|
|
3362
3182
|
} finally {
|
|
3363
3183
|
const finishedAtMsFinal = finishedAtMs ?? Date.now();
|
|
@@ -3390,22 +3210,23 @@ async function runEmbeddingsWithAccount({ c, store, ctx, payload, clientModel, s
|
|
|
3390
3210
|
httpStatus,
|
|
3391
3211
|
errorName,
|
|
3392
3212
|
errorStatus,
|
|
3393
|
-
errorMessage
|
|
3213
|
+
errorMessage,
|
|
3214
|
+
upstreamErrorMessageRaw
|
|
3394
3215
|
});
|
|
3395
3216
|
}
|
|
3396
3217
|
}
|
|
3397
3218
|
|
|
3398
3219
|
//#endregion
|
|
3399
3220
|
//#region src/lib/models.ts
|
|
3221
|
+
const getAvailableModels = () => (accountsManager.getFirstAccountModels()?.data ?? []).filter((model) => model.model_picker_enabled || model.capabilities.type === "embeddings");
|
|
3400
3222
|
const findEndpointModel = (sdkModelId) => {
|
|
3401
|
-
const models =
|
|
3223
|
+
const models = getAvailableModels();
|
|
3402
3224
|
const exactMatch = models.find((m) => m.id === sdkModelId);
|
|
3403
3225
|
if (exactMatch) return exactMatch;
|
|
3404
3226
|
const normalized = _normalizeSdkModelId(sdkModelId);
|
|
3405
3227
|
if (!normalized) return;
|
|
3406
3228
|
const modelName = `claude-${normalized.family}-${normalized.version}`;
|
|
3407
|
-
|
|
3408
|
-
if (model) return model;
|
|
3229
|
+
return models.find((m) => m.id === modelName);
|
|
3409
3230
|
};
|
|
3410
3231
|
/**
|
|
3411
3232
|
* Normalizes an SDK model ID to extract the model family and version.
|
|
@@ -3611,7 +3432,7 @@ const isWarmupProbeRequest = (payload) => {
|
|
|
3611
3432
|
return false;
|
|
3612
3433
|
};
|
|
3613
3434
|
const handleSelectionFailure = (context) => {
|
|
3614
|
-
const { c, store, requestId, startedAtMs, method, path: path$2, streamRequested, clientModel, clientIp, clientIpSource, userAgent, userId, safetyIdentifier, promptCacheKey, initiator, isSubagent, 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;
|
|
3615
3436
|
const finishedAtMs = Date.now();
|
|
3616
3437
|
store.insert({
|
|
3617
3438
|
requestId,
|
|
@@ -3630,7 +3451,10 @@ const handleSelectionFailure = (context) => {
|
|
|
3630
3451
|
promptCacheKey,
|
|
3631
3452
|
initiator,
|
|
3632
3453
|
isSubagent,
|
|
3454
|
+
affinityKeyUsed,
|
|
3455
|
+
affinityKeySource,
|
|
3633
3456
|
httpStatus: selection.reason === "MODEL_NOT_SUPPORTED" ? 400 : 429,
|
|
3457
|
+
selectionReason: selectionReason ?? selection.selectionReason,
|
|
3634
3458
|
selectionFailureReason: selection.reason
|
|
3635
3459
|
});
|
|
3636
3460
|
if (selection.reason === "MODEL_NOT_SUPPORTED") return c.json({ error: {
|
|
@@ -3658,8 +3482,7 @@ const maybeBlockOriginalModelName = (context) => {
|
|
|
3658
3482
|
const THINKING_TEXT = "Thinking...";
|
|
3659
3483
|
function translateToOpenAI(payload) {
|
|
3660
3484
|
const modelId = payload.model;
|
|
3661
|
-
const
|
|
3662
|
-
const thinkingBudget = getThinkingBudget(payload, model);
|
|
3485
|
+
const thinkingBudget = getThinkingBudget(payload, getAvailableModels().find((m) => m.id === modelId));
|
|
3663
3486
|
return {
|
|
3664
3487
|
model: modelId,
|
|
3665
3488
|
messages: translateAnthropicMessagesToOpenAI(payload, modelId, thinkingBudget),
|
|
@@ -3955,9 +3778,13 @@ async function handleCountTokens(c) {
|
|
|
3955
3778
|
const createResponses = async (payload, { vision, initiator, upstreamRequestId, subagentMarker, sessionId, isCompact }, account) => {
|
|
3956
3779
|
const ctx = account ?? accountFromState();
|
|
3957
3780
|
if (!ctx.copilotToken) throw new Error("Copilot token not found");
|
|
3781
|
+
const effectiveInitiator = resolveEffectiveInitiator(initiator, {
|
|
3782
|
+
isCompact,
|
|
3783
|
+
isSubagent: Boolean(subagentMarker)
|
|
3784
|
+
});
|
|
3958
3785
|
const headers = {
|
|
3959
3786
|
...copilotHeaders(ctx, vision, upstreamRequestId),
|
|
3960
|
-
"x-initiator":
|
|
3787
|
+
"x-initiator": effectiveInitiator
|
|
3961
3788
|
};
|
|
3962
3789
|
prepareInteractionHeaders(sessionId, Boolean(subagentMarker), headers);
|
|
3963
3790
|
prepareForCompact(headers, isCompact);
|
|
@@ -4882,6 +4709,44 @@ const getPayloadItems = (payload) => {
|
|
|
4882
4709
|
if (Array.isArray(input)) result.push(...input);
|
|
4883
4710
|
return result;
|
|
4884
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";
|
|
4885
4750
|
const containsVisionContent = (value) => {
|
|
4886
4751
|
if (!value) return false;
|
|
4887
4752
|
if (Array.isArray(value)) return value.some((entry) => containsVisionContent(entry));
|
|
@@ -4931,9 +4796,13 @@ const shouldUseMessageProxyHeaders = (payload) => {
|
|
|
4931
4796
|
return Boolean(safetyIdentifier && sessionId);
|
|
4932
4797
|
};
|
|
4933
4798
|
const buildMessagesHeaders = ({ ctx, enableVision, initiator, options, payload }) => {
|
|
4799
|
+
const effectiveInitiator = resolveEffectiveInitiator(initiator, {
|
|
4800
|
+
isCompact: options?.isCompact,
|
|
4801
|
+
isSubagent: Boolean(options?.subagentMarker)
|
|
4802
|
+
});
|
|
4934
4803
|
const headers = {
|
|
4935
4804
|
...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
|
|
4936
|
-
"x-initiator":
|
|
4805
|
+
"x-initiator": effectiveInitiator
|
|
4937
4806
|
};
|
|
4938
4807
|
prepareInteractionHeaders(options?.sessionId, Boolean(options?.subagentMarker), headers);
|
|
4939
4808
|
prepareForCompact(headers, options?.isCompact);
|
|
@@ -5225,34 +5094,73 @@ function closeThinkingBlockIfOpen(state$1, events$1) {
|
|
|
5225
5094
|
//#endregion
|
|
5226
5095
|
//#region src/routes/messages/subagent-marker.ts
|
|
5227
5096
|
const subagentMarkerPrefix = "__SUBAGENT_MARKER__";
|
|
5097
|
+
const subagentStartContextPrefix = "SubagentStart hook additional context:";
|
|
5228
5098
|
const REMINDER_RE = /<system-reminder>([\s\S]*?)<\/system-reminder>/g;
|
|
5229
|
-
const
|
|
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) => {
|
|
5230
5113
|
const firstUserMessage = payload.messages.find((msg) => msg.role === "user" && Array.isArray(msg.content));
|
|
5231
|
-
if (!firstUserMessage || !Array.isArray(firstUserMessage.content)) return
|
|
5114
|
+
if (!firstUserMessage || !Array.isArray(firstUserMessage.content)) return NONE_INSPECTION;
|
|
5115
|
+
let sawInvalidMarker = false;
|
|
5232
5116
|
for (const block of firstUserMessage.content) {
|
|
5233
5117
|
if (block.type !== "text") continue;
|
|
5234
|
-
const
|
|
5235
|
-
if (
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
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;
|
|
5240
5134
|
for (const [, content] of text.matchAll(REMINDER_RE)) {
|
|
5241
|
-
const
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
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
|
+
}
|
|
5253
5161
|
}
|
|
5254
5162
|
}
|
|
5255
|
-
return
|
|
5163
|
+
return sawInvalidMarker ? INVALID_INSPECTION : NONE_INSPECTION;
|
|
5256
5164
|
};
|
|
5257
5165
|
/** Extract the first balanced `{...}` object from text that starts with `{`. */
|
|
5258
5166
|
const extractBalancedJson = (text) => {
|
|
@@ -5306,13 +5214,18 @@ async function handleCompletion(c) {
|
|
|
5306
5214
|
const userAgent = c.req.header("user-agent") ?? void 0;
|
|
5307
5215
|
const anthropicPayload = await c.req.json();
|
|
5308
5216
|
debugJson(logger$5, "Anthropic request payload:", anthropicPayload);
|
|
5309
|
-
const
|
|
5310
|
-
const
|
|
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;
|
|
5311
5221
|
if (subagentMarker) debugJson(logger$5, "Detected Subagent marker:", subagentMarker);
|
|
5312
5222
|
const sessionId = getRootSessionId(anthropicPayload, c);
|
|
5313
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;
|
|
5314
5226
|
const anthropicBeta = c.req.header("anthropic-beta");
|
|
5315
5227
|
const isCompact = isCompactRequest(anthropicPayload);
|
|
5228
|
+
const originalRequestModel = anthropicPayload.model;
|
|
5316
5229
|
if (anthropicBeta && isWarmupProbeRequest(anthropicPayload)) anthropicPayload.model = getSmallModel();
|
|
5317
5230
|
if (isCompact) {
|
|
5318
5231
|
logger$5.debug("Is compact request:", isCompact);
|
|
@@ -5330,6 +5243,11 @@ async function handleCompletion(c) {
|
|
|
5330
5243
|
const { safetyIdentifier, sessionId: promptCacheKey } = parseUserIdMetadata(userId);
|
|
5331
5244
|
const normalizedSafetyIdentifier = safetyIdentifier ?? void 0;
|
|
5332
5245
|
const normalizedPromptCacheKey = promptCacheKey ?? void 0;
|
|
5246
|
+
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
5247
|
+
const fallbackInitiator = resolveEffectiveInitiator(getChatInitiator(openAIPayload.messages), {
|
|
5248
|
+
isCompact,
|
|
5249
|
+
isSubagent: isSubagentRequest
|
|
5250
|
+
});
|
|
5333
5251
|
const blockedResponse = maybeBlockOriginalModelName({
|
|
5334
5252
|
c,
|
|
5335
5253
|
store,
|
|
@@ -5345,14 +5263,14 @@ async function handleCompletion(c) {
|
|
|
5345
5263
|
userId,
|
|
5346
5264
|
safetyIdentifier: normalizedSafetyIdentifier,
|
|
5347
5265
|
promptCacheKey: normalizedPromptCacheKey,
|
|
5348
|
-
initiator:
|
|
5349
|
-
isSubagent:
|
|
5266
|
+
initiator: fallbackInitiator,
|
|
5267
|
+
isSubagent: isSubagentRequest,
|
|
5268
|
+
selectionReason: invalidSubagentMarkerSelectionReason
|
|
5350
5269
|
});
|
|
5351
5270
|
if (blockedResponse) return blockedResponse;
|
|
5352
|
-
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
5353
|
-
const fallbackInitiator = initiatorOverride ?? getChatInitiator(openAIPayload.messages);
|
|
5354
5271
|
const endpointModel = findEndpointModel(clientModel);
|
|
5355
5272
|
const resolvedClientModel = endpointModel?.id ?? clientModel;
|
|
5273
|
+
const affinityModelId = clientModel !== originalRequestModel ? findEndpointModel(originalRequestModel)?.id ?? originalRequestModel : void 0;
|
|
5356
5274
|
const useMessagesApi = isMessagesApiEnabled();
|
|
5357
5275
|
const candidates = [];
|
|
5358
5276
|
if (useMessagesApi) candidates.push({
|
|
@@ -5366,7 +5284,18 @@ async function handleCompletion(c) {
|
|
|
5366
5284
|
modelId: endpointModel?.id ?? openAIPayload.model,
|
|
5367
5285
|
endpoint: CHAT_COMPLETIONS_ENDPOINT
|
|
5368
5286
|
});
|
|
5369
|
-
const
|
|
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;
|
|
5370
5299
|
if (!selection.ok) return handleSelectionFailure({
|
|
5371
5300
|
c,
|
|
5372
5301
|
store,
|
|
@@ -5383,7 +5312,10 @@ async function handleCompletion(c) {
|
|
|
5383
5312
|
safetyIdentifier: normalizedSafetyIdentifier,
|
|
5384
5313
|
promptCacheKey: normalizedPromptCacheKey,
|
|
5385
5314
|
initiator: fallbackInitiator,
|
|
5386
|
-
isSubagent:
|
|
5315
|
+
isSubagent: isSubagentRequest,
|
|
5316
|
+
affinityKeyUsed: affinityKey.affinityKeyUsed,
|
|
5317
|
+
affinityKeySource: affinityKey.affinityKeySource,
|
|
5318
|
+
selectionReason,
|
|
5387
5319
|
selection
|
|
5388
5320
|
});
|
|
5389
5321
|
const { account, reservation, selectedModel, endpoint, costUnits } = selection;
|
|
@@ -5404,7 +5336,7 @@ async function handleCompletion(c) {
|
|
|
5404
5336
|
userId,
|
|
5405
5337
|
safetyIdentifier: normalizedSafetyIdentifier,
|
|
5406
5338
|
promptCacheKey: normalizedPromptCacheKey,
|
|
5407
|
-
isSubagent:
|
|
5339
|
+
isSubagent: isSubagentRequest,
|
|
5408
5340
|
clientModel,
|
|
5409
5341
|
account,
|
|
5410
5342
|
reservation,
|
|
@@ -5415,14 +5347,17 @@ async function handleCompletion(c) {
|
|
|
5415
5347
|
premiumRemainingBefore,
|
|
5416
5348
|
premiumUnlimitedBefore,
|
|
5417
5349
|
confirmAffinity: selection.confirmAffinity,
|
|
5350
|
+
confirmOwnership: selection.confirmOwnership,
|
|
5418
5351
|
affinityHit: selection.affinityHit,
|
|
5419
|
-
affinityCacheKey: selection.affinityCacheKey
|
|
5352
|
+
affinityCacheKey: selection.affinityCacheKey,
|
|
5353
|
+
affinityKeyUsed: affinityKey.affinityKeyUsed,
|
|
5354
|
+
affinityKeySource: affinityKey.affinityKeySource,
|
|
5355
|
+
selectionReason
|
|
5420
5356
|
};
|
|
5421
5357
|
if (endpoint === MESSAGES_ENDPOINT) return await handleWithMessagesApi({
|
|
5422
5358
|
c,
|
|
5423
5359
|
anthropicPayload,
|
|
5424
5360
|
anthropicBetaHeader: anthropicBeta ?? void 0,
|
|
5425
|
-
initiatorOverride,
|
|
5426
5361
|
subagentMarker,
|
|
5427
5362
|
sessionId,
|
|
5428
5363
|
instr,
|
|
@@ -5433,7 +5368,6 @@ async function handleCompletion(c) {
|
|
|
5433
5368
|
c,
|
|
5434
5369
|
anthropicPayload,
|
|
5435
5370
|
openAIPayload,
|
|
5436
|
-
initiatorOverride,
|
|
5437
5371
|
subagentMarker,
|
|
5438
5372
|
sessionId,
|
|
5439
5373
|
selectedModel,
|
|
@@ -5443,7 +5377,6 @@ async function handleCompletion(c) {
|
|
|
5443
5377
|
return await handleWithChatCompletions({
|
|
5444
5378
|
c,
|
|
5445
5379
|
openAIPayload,
|
|
5446
|
-
initiatorOverride,
|
|
5447
5380
|
subagentMarker,
|
|
5448
5381
|
sessionId,
|
|
5449
5382
|
selectedModel,
|
|
@@ -5452,21 +5385,25 @@ async function handleCompletion(c) {
|
|
|
5452
5385
|
});
|
|
5453
5386
|
}
|
|
5454
5387
|
const handleWithChatCompletions = async (params) => {
|
|
5455
|
-
const { c, openAIPayload,
|
|
5388
|
+
const { c, openAIPayload, subagentMarker, sessionId, selectedModel, instr, isCompact } = params;
|
|
5456
5389
|
debugJson(logger$5, "Translated OpenAI request payload:", openAIPayload);
|
|
5457
5390
|
const ctx = toAccountContext(instr.account);
|
|
5458
|
-
const
|
|
5459
|
-
|
|
5391
|
+
const effectiveInitiator = resolveEffectiveInitiator(getChatInitiator(openAIPayload.messages), {
|
|
5392
|
+
isCompact,
|
|
5393
|
+
isSubagent: Boolean(subagentMarker)
|
|
5394
|
+
});
|
|
5395
|
+
instr.initiator = effectiveInitiator;
|
|
5460
5396
|
let response;
|
|
5461
5397
|
try {
|
|
5462
5398
|
response = await createChatCompletions(openAIPayload, ctx, {
|
|
5463
5399
|
upstreamRequestId: instr.upstreamRequestId,
|
|
5464
|
-
initiator,
|
|
5400
|
+
initiator: effectiveInitiator,
|
|
5465
5401
|
subagentMarker,
|
|
5466
5402
|
sessionId,
|
|
5467
5403
|
isCompact
|
|
5468
5404
|
});
|
|
5469
5405
|
instr.confirmAffinity?.();
|
|
5406
|
+
instr.confirmOwnership?.();
|
|
5470
5407
|
} catch (error) {
|
|
5471
5408
|
return await handleChatCompletionsCreateError({
|
|
5472
5409
|
error,
|
|
@@ -5496,26 +5433,30 @@ const handleWithChatCompletions = async (params) => {
|
|
|
5496
5433
|
}));
|
|
5497
5434
|
};
|
|
5498
5435
|
const handleWithResponsesApi = async (params) => {
|
|
5499
|
-
const { c, anthropicPayload, openAIPayload,
|
|
5436
|
+
const { c, anthropicPayload, openAIPayload, subagentMarker, sessionId, selectedModel, instr, isCompact } = params;
|
|
5500
5437
|
const responsesPayload = translateAnthropicMessagesToResponsesPayload(anthropicPayload, selectedModel.id);
|
|
5501
5438
|
applyResponsesApiContextManagement(responsesPayload, selectedModel.capabilities.limits.max_prompt_tokens);
|
|
5502
5439
|
compactInputByLatestCompaction(responsesPayload);
|
|
5503
5440
|
debugJson(logger$5, "Translated Responses payload:", responsesPayload);
|
|
5504
5441
|
const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
|
|
5505
|
-
const
|
|
5442
|
+
const effectiveInitiator = resolveEffectiveInitiator(initiator, {
|
|
5443
|
+
isCompact,
|
|
5444
|
+
isSubagent: Boolean(subagentMarker)
|
|
5445
|
+
});
|
|
5506
5446
|
const ctx = toAccountContext(instr.account);
|
|
5507
|
-
instr.initiator =
|
|
5447
|
+
instr.initiator = effectiveInitiator;
|
|
5508
5448
|
let response;
|
|
5509
5449
|
try {
|
|
5510
5450
|
response = await createResponses(responsesPayload, {
|
|
5511
5451
|
vision,
|
|
5512
|
-
initiator:
|
|
5452
|
+
initiator: effectiveInitiator,
|
|
5513
5453
|
upstreamRequestId: instr.upstreamRequestId,
|
|
5514
5454
|
subagentMarker,
|
|
5515
5455
|
sessionId,
|
|
5516
5456
|
isCompact
|
|
5517
5457
|
}, ctx);
|
|
5518
5458
|
instr.confirmAffinity?.();
|
|
5459
|
+
instr.confirmOwnership?.();
|
|
5519
5460
|
} catch (error) {
|
|
5520
5461
|
return await handleResponsesCreateError({
|
|
5521
5462
|
error,
|
|
@@ -5564,6 +5505,9 @@ function insertRequestLog$1(instr, record) {
|
|
|
5564
5505
|
upstreamRequestId: instr.upstreamRequestId,
|
|
5565
5506
|
affinityHit: instr.affinityHit,
|
|
5566
5507
|
affinityCacheKey: instr.affinityCacheKey,
|
|
5508
|
+
affinityKeyUsed: instr.affinityKeyUsed,
|
|
5509
|
+
affinityKeySource: instr.affinityKeySource,
|
|
5510
|
+
selectionReason: instr.selectionReason,
|
|
5567
5511
|
clientModel,
|
|
5568
5512
|
upstreamEndpoint,
|
|
5569
5513
|
accountId: account.id,
|
|
@@ -5587,8 +5531,8 @@ async function finalizeQuotaAndGetPremiumSnapshot(instr) {
|
|
|
5587
5531
|
async function handleChatCompletionsCreateError(params) {
|
|
5588
5532
|
const { error, instr, stream } = params;
|
|
5589
5533
|
const finishedAtMs = Date.now();
|
|
5590
|
-
const details =
|
|
5591
|
-
if (details
|
|
5534
|
+
const details = await extractErrorObservability(error);
|
|
5535
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
5592
5536
|
const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
|
|
5593
5537
|
insertRequestLog$1(instr, {
|
|
5594
5538
|
finishedAtMs,
|
|
@@ -5600,7 +5544,8 @@ async function handleChatCompletionsCreateError(params) {
|
|
|
5600
5544
|
httpStatus: details.httpStatus,
|
|
5601
5545
|
errorName: details.errorName,
|
|
5602
5546
|
errorStatus: details.errorStatus,
|
|
5603
|
-
errorMessage: details.errorMessage
|
|
5547
|
+
errorMessage: details.errorMessage,
|
|
5548
|
+
upstreamErrorMessageRaw: details.upstreamErrorMessageRaw
|
|
5604
5549
|
});
|
|
5605
5550
|
throw error;
|
|
5606
5551
|
}
|
|
@@ -5611,6 +5556,7 @@ async function handleChatCompletionsNonStreaming(params) {
|
|
|
5611
5556
|
let errorName;
|
|
5612
5557
|
let errorStatus;
|
|
5613
5558
|
let errorMessage;
|
|
5559
|
+
let upstreamErrorMessageRaw;
|
|
5614
5560
|
const finishedAtMs = Date.now();
|
|
5615
5561
|
try {
|
|
5616
5562
|
logger$5.debug("Non-streaming response from Copilot:", JSON.stringify(response));
|
|
@@ -5618,12 +5564,13 @@ async function handleChatCompletionsNonStreaming(params) {
|
|
|
5618
5564
|
debugJson(logger$5, "Translated Anthropic response:", anthropicResponse);
|
|
5619
5565
|
return c.json(anthropicResponse);
|
|
5620
5566
|
} catch (error) {
|
|
5621
|
-
const details =
|
|
5567
|
+
const details = await extractErrorObservability(error);
|
|
5622
5568
|
httpStatus = details.httpStatus;
|
|
5623
5569
|
errorName = details.errorName;
|
|
5624
5570
|
errorStatus = details.errorStatus;
|
|
5625
5571
|
errorMessage = details.errorMessage;
|
|
5626
|
-
|
|
5572
|
+
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
5573
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
5627
5574
|
throw error;
|
|
5628
5575
|
} finally {
|
|
5629
5576
|
const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
|
|
@@ -5638,7 +5585,8 @@ async function handleChatCompletionsNonStreaming(params) {
|
|
|
5638
5585
|
httpStatus,
|
|
5639
5586
|
errorName,
|
|
5640
5587
|
errorStatus,
|
|
5641
|
-
errorMessage
|
|
5588
|
+
errorMessage,
|
|
5589
|
+
upstreamErrorMessageRaw
|
|
5642
5590
|
});
|
|
5643
5591
|
}
|
|
5644
5592
|
}
|
|
@@ -5649,6 +5597,7 @@ async function streamChatCompletionsAndLog(params) {
|
|
|
5649
5597
|
let errorName;
|
|
5650
5598
|
let errorStatus;
|
|
5651
5599
|
let errorMessage;
|
|
5600
|
+
let upstreamErrorMessageRaw;
|
|
5652
5601
|
const streamState = {
|
|
5653
5602
|
messageStartSent: false,
|
|
5654
5603
|
contentBlockIndex: 0,
|
|
@@ -5680,12 +5629,14 @@ async function streamChatCompletionsAndLog(params) {
|
|
|
5680
5629
|
}
|
|
5681
5630
|
}
|
|
5682
5631
|
} catch (error) {
|
|
5683
|
-
const details =
|
|
5632
|
+
const details = await extractErrorObservability(error);
|
|
5684
5633
|
errorName = details.errorName;
|
|
5685
5634
|
errorStatus = details.errorStatus;
|
|
5686
5635
|
errorMessage = details.errorMessage;
|
|
5636
|
+
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
5687
5637
|
logger$5.warn("Streaming error:", error);
|
|
5688
|
-
if (details
|
|
5638
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
5639
|
+
await writeAnthropicStreamError(stream, getUserVisibleErrorMessage(details));
|
|
5689
5640
|
} finally {
|
|
5690
5641
|
const finishedAtMs = Date.now();
|
|
5691
5642
|
const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
|
|
@@ -5701,15 +5652,16 @@ async function streamChatCompletionsAndLog(params) {
|
|
|
5701
5652
|
httpStatus: errorStatus ?? (errorName ? 500 : 200),
|
|
5702
5653
|
errorName,
|
|
5703
5654
|
errorStatus,
|
|
5704
|
-
errorMessage
|
|
5655
|
+
errorMessage,
|
|
5656
|
+
upstreamErrorMessageRaw
|
|
5705
5657
|
});
|
|
5706
5658
|
}
|
|
5707
5659
|
}
|
|
5708
5660
|
async function handleResponsesCreateError(params) {
|
|
5709
5661
|
const { error, instr, stream } = params;
|
|
5710
5662
|
const finishedAtMs = Date.now();
|
|
5711
|
-
const details =
|
|
5712
|
-
if (details
|
|
5663
|
+
const details = await extractErrorObservability(error);
|
|
5664
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
5713
5665
|
const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
|
|
5714
5666
|
insertRequestLog$1(instr, {
|
|
5715
5667
|
finishedAtMs,
|
|
@@ -5721,7 +5673,8 @@ async function handleResponsesCreateError(params) {
|
|
|
5721
5673
|
httpStatus: details.httpStatus,
|
|
5722
5674
|
errorName: details.errorName,
|
|
5723
5675
|
errorStatus: details.errorStatus,
|
|
5724
|
-
errorMessage: details.errorMessage
|
|
5676
|
+
errorMessage: details.errorMessage,
|
|
5677
|
+
upstreamErrorMessageRaw: details.upstreamErrorMessageRaw
|
|
5725
5678
|
});
|
|
5726
5679
|
throw error;
|
|
5727
5680
|
}
|
|
@@ -5732,6 +5685,7 @@ async function handleResponsesNonStreaming(params) {
|
|
|
5732
5685
|
let errorName;
|
|
5733
5686
|
let errorStatus;
|
|
5734
5687
|
let errorMessage;
|
|
5688
|
+
let upstreamErrorMessageRaw;
|
|
5735
5689
|
const finishedAtMs = Date.now();
|
|
5736
5690
|
try {
|
|
5737
5691
|
usage = extractResponsesUsageFromResult(result);
|
|
@@ -5740,12 +5694,13 @@ async function handleResponsesNonStreaming(params) {
|
|
|
5740
5694
|
debugJson(logger$5, "Translated Anthropic response:", anthropicResponse);
|
|
5741
5695
|
return c.json(anthropicResponse);
|
|
5742
5696
|
} catch (error) {
|
|
5743
|
-
const details =
|
|
5697
|
+
const details = await extractErrorObservability(error);
|
|
5744
5698
|
httpStatus = details.httpStatus;
|
|
5745
5699
|
errorName = details.errorName;
|
|
5746
5700
|
errorStatus = details.errorStatus;
|
|
5747
5701
|
errorMessage = details.errorMessage;
|
|
5748
|
-
|
|
5702
|
+
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
5703
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
5749
5704
|
throw error;
|
|
5750
5705
|
} finally {
|
|
5751
5706
|
const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
|
|
@@ -5760,7 +5715,8 @@ async function handleResponsesNonStreaming(params) {
|
|
|
5760
5715
|
httpStatus,
|
|
5761
5716
|
errorName,
|
|
5762
5717
|
errorStatus,
|
|
5763
|
-
errorMessage
|
|
5718
|
+
errorMessage,
|
|
5719
|
+
upstreamErrorMessageRaw
|
|
5764
5720
|
});
|
|
5765
5721
|
}
|
|
5766
5722
|
}
|
|
@@ -5776,6 +5732,17 @@ async function ensureResponsesStreamCompleted(params) {
|
|
|
5776
5732
|
data: JSON.stringify(errorEvent)
|
|
5777
5733
|
});
|
|
5778
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
|
+
}
|
|
5779
5746
|
async function streamResponsesAndLog$1(params) {
|
|
5780
5747
|
const { stream, response, instr, estimatedInputTokens, historicalUsage } = params;
|
|
5781
5748
|
let ttfbMs;
|
|
@@ -5783,6 +5750,7 @@ async function streamResponsesAndLog$1(params) {
|
|
|
5783
5750
|
let errorName;
|
|
5784
5751
|
let errorStatus;
|
|
5785
5752
|
let errorMessage;
|
|
5753
|
+
let upstreamErrorMessageRaw;
|
|
5786
5754
|
const streamState = createResponsesStreamState();
|
|
5787
5755
|
streamState.estimatedInputTokens = estimatedInputTokens;
|
|
5788
5756
|
streamState.historicalInputTokens = historicalUsage?.tokensInput;
|
|
@@ -5827,12 +5795,14 @@ async function streamResponsesAndLog$1(params) {
|
|
|
5827
5795
|
}
|
|
5828
5796
|
});
|
|
5829
5797
|
} catch (error) {
|
|
5830
|
-
const details =
|
|
5798
|
+
const details = await extractErrorObservability(error);
|
|
5831
5799
|
errorName = details.errorName;
|
|
5832
5800
|
errorStatus = details.errorStatus;
|
|
5833
5801
|
errorMessage = details.errorMessage;
|
|
5802
|
+
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
5834
5803
|
logger$5.warn("Streaming error:", error);
|
|
5835
|
-
if (details
|
|
5804
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
5805
|
+
await writeAnthropicStreamError(stream, getUserVisibleErrorMessage(details));
|
|
5836
5806
|
} finally {
|
|
5837
5807
|
const finishedAtMs = Date.now();
|
|
5838
5808
|
const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
|
|
@@ -5848,15 +5818,16 @@ async function streamResponsesAndLog$1(params) {
|
|
|
5848
5818
|
httpStatus: errorStatus ?? (errorName ? 500 : 200),
|
|
5849
5819
|
errorName,
|
|
5850
5820
|
errorStatus,
|
|
5851
|
-
errorMessage
|
|
5821
|
+
errorMessage,
|
|
5822
|
+
upstreamErrorMessageRaw
|
|
5852
5823
|
});
|
|
5853
5824
|
}
|
|
5854
5825
|
}
|
|
5855
5826
|
async function handleMessagesCreateError(params) {
|
|
5856
5827
|
const { error, instr, stream } = params;
|
|
5857
5828
|
const finishedAtMs = Date.now();
|
|
5858
|
-
const details =
|
|
5859
|
-
if (details
|
|
5829
|
+
const details = await extractErrorObservability(error);
|
|
5830
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
5860
5831
|
const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
|
|
5861
5832
|
insertRequestLog$1(instr, {
|
|
5862
5833
|
finishedAtMs,
|
|
@@ -5868,7 +5839,8 @@ async function handleMessagesCreateError(params) {
|
|
|
5868
5839
|
httpStatus: details.httpStatus,
|
|
5869
5840
|
errorName: details.errorName,
|
|
5870
5841
|
errorStatus: details.errorStatus,
|
|
5871
|
-
errorMessage: details.errorMessage
|
|
5842
|
+
errorMessage: details.errorMessage,
|
|
5843
|
+
upstreamErrorMessageRaw: details.upstreamErrorMessageRaw
|
|
5872
5844
|
});
|
|
5873
5845
|
throw error;
|
|
5874
5846
|
}
|
|
@@ -5879,17 +5851,19 @@ async function handleMessagesNonStreaming(params) {
|
|
|
5879
5851
|
let errorName;
|
|
5880
5852
|
let errorStatus;
|
|
5881
5853
|
let errorMessage;
|
|
5854
|
+
let upstreamErrorMessageRaw;
|
|
5882
5855
|
const finishedAtMs = Date.now();
|
|
5883
5856
|
try {
|
|
5884
5857
|
logger$5.debug("Non-streaming Messages result:", JSON.stringify(response).slice(-400));
|
|
5885
5858
|
return c.json(response);
|
|
5886
5859
|
} catch (error) {
|
|
5887
|
-
const details =
|
|
5860
|
+
const details = await extractErrorObservability(error);
|
|
5888
5861
|
httpStatus = details.httpStatus;
|
|
5889
5862
|
errorName = details.errorName;
|
|
5890
5863
|
errorStatus = details.errorStatus;
|
|
5891
5864
|
errorMessage = details.errorMessage;
|
|
5892
|
-
|
|
5865
|
+
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
5866
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
5893
5867
|
throw error;
|
|
5894
5868
|
} finally {
|
|
5895
5869
|
const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
|
|
@@ -5904,7 +5878,8 @@ async function handleMessagesNonStreaming(params) {
|
|
|
5904
5878
|
httpStatus,
|
|
5905
5879
|
errorName,
|
|
5906
5880
|
errorStatus,
|
|
5907
|
-
errorMessage
|
|
5881
|
+
errorMessage,
|
|
5882
|
+
upstreamErrorMessageRaw
|
|
5908
5883
|
});
|
|
5909
5884
|
}
|
|
5910
5885
|
}
|
|
@@ -5926,6 +5901,7 @@ async function streamMessagesAndLog(params) {
|
|
|
5926
5901
|
let errorName;
|
|
5927
5902
|
let errorStatus;
|
|
5928
5903
|
let errorMessage;
|
|
5904
|
+
let upstreamErrorMessageRaw;
|
|
5929
5905
|
try {
|
|
5930
5906
|
for await (const rawEvent of response) {
|
|
5931
5907
|
if (ttfbMs === void 0) ttfbMs = Date.now() - instr.startedAtMs;
|
|
@@ -5941,12 +5917,14 @@ async function streamMessagesAndLog(params) {
|
|
|
5941
5917
|
});
|
|
5942
5918
|
}
|
|
5943
5919
|
} catch (error) {
|
|
5944
|
-
const details =
|
|
5920
|
+
const details = await extractErrorObservability(error);
|
|
5945
5921
|
errorName = details.errorName;
|
|
5946
5922
|
errorStatus = details.errorStatus;
|
|
5947
5923
|
errorMessage = details.errorMessage;
|
|
5924
|
+
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
5948
5925
|
logger$5.warn("Streaming error:", error);
|
|
5949
|
-
if (details
|
|
5926
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
5927
|
+
await writeAnthropicStreamError(stream, getUserVisibleErrorMessage(details));
|
|
5950
5928
|
} finally {
|
|
5951
5929
|
const finishedAtMs = Date.now();
|
|
5952
5930
|
const { premiumRemainingAfter, premiumUnlimitedAfter, premiumRemainingDiff } = await finalizeQuotaAndGetPremiumSnapshot(instr);
|
|
@@ -5962,28 +5940,33 @@ async function streamMessagesAndLog(params) {
|
|
|
5962
5940
|
httpStatus: errorStatus ?? (errorName ? 500 : 200),
|
|
5963
5941
|
errorName,
|
|
5964
5942
|
errorStatus,
|
|
5965
|
-
errorMessage
|
|
5943
|
+
errorMessage,
|
|
5944
|
+
upstreamErrorMessageRaw
|
|
5966
5945
|
});
|
|
5967
5946
|
}
|
|
5968
5947
|
}
|
|
5969
5948
|
const handleWithMessagesApi = async (params) => {
|
|
5970
|
-
const { c, anthropicPayload, anthropicBetaHeader,
|
|
5949
|
+
const { c, anthropicPayload, anthropicBetaHeader, subagentMarker, sessionId, instr, selectedModel, isCompact } = params;
|
|
5971
5950
|
prepareMessagesApiPayload(anthropicPayload, selectedModel);
|
|
5972
5951
|
debugJson(logger$5, "Translated Messages payload:", anthropicPayload);
|
|
5973
5952
|
const ctx = toAccountContext(instr.account);
|
|
5974
|
-
const
|
|
5975
|
-
|
|
5953
|
+
const effectiveInitiator = resolveEffectiveInitiator(getMessagesInitiator(anthropicPayload), {
|
|
5954
|
+
isCompact,
|
|
5955
|
+
isSubagent: Boolean(subagentMarker)
|
|
5956
|
+
});
|
|
5957
|
+
instr.initiator = effectiveInitiator;
|
|
5976
5958
|
let response;
|
|
5977
5959
|
try {
|
|
5978
5960
|
response = await createMessages(anthropicPayload, ctx, {
|
|
5979
5961
|
anthropicBetaHeader,
|
|
5980
5962
|
upstreamRequestId: instr.upstreamRequestId,
|
|
5981
|
-
initiator,
|
|
5963
|
+
initiator: effectiveInitiator,
|
|
5982
5964
|
subagentMarker,
|
|
5983
5965
|
sessionId,
|
|
5984
5966
|
isCompact
|
|
5985
5967
|
});
|
|
5986
5968
|
instr.confirmAffinity?.();
|
|
5969
|
+
instr.confirmOwnership?.();
|
|
5987
5970
|
} catch (error) {
|
|
5988
5971
|
return await handleMessagesCreateError({
|
|
5989
5972
|
error,
|
|
@@ -6031,9 +6014,8 @@ messageRoutes.post("/count_tokens", async (c) => {
|
|
|
6031
6014
|
const modelRoutes = new Hono();
|
|
6032
6015
|
modelRoutes.get("/", async (c) => {
|
|
6033
6016
|
try {
|
|
6034
|
-
if (!state.models) await cacheModels();
|
|
6035
6017
|
const blockedTargets = getAliasTargetSet();
|
|
6036
|
-
const models =
|
|
6018
|
+
const models = getAvailableModels().filter((model) => !blockedTargets.has(model.id.toLowerCase())).map((model) => ({
|
|
6037
6019
|
id: model.id,
|
|
6038
6020
|
object: "model",
|
|
6039
6021
|
type: "model",
|
|
@@ -6041,7 +6023,7 @@ modelRoutes.get("/", async (c) => {
|
|
|
6041
6023
|
created_at: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
6042
6024
|
owned_by: model.vendor,
|
|
6043
6025
|
display_name: model.name
|
|
6044
|
-
}))
|
|
6026
|
+
}));
|
|
6045
6027
|
const aliasModels = Object.keys(getModelAliases()).map((alias) => ({
|
|
6046
6028
|
id: alias,
|
|
6047
6029
|
object: "model",
|
|
@@ -6090,7 +6072,7 @@ async function handleProviderCountTokens(c) {
|
|
|
6090
6072
|
const anthropicPayload = await c.req.json();
|
|
6091
6073
|
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
6092
6074
|
const modelId = anthropicPayload.model.trim();
|
|
6093
|
-
let selectedModel =
|
|
6075
|
+
let selectedModel = getAvailableModels().find((model) => model.id === modelId);
|
|
6094
6076
|
if (!selectedModel && modelId) selectedModel = createFallbackModel(modelId);
|
|
6095
6077
|
if (!selectedModel) {
|
|
6096
6078
|
logger$4.warn("provider.count_tokens.model_not_found", {
|
|
@@ -6350,9 +6332,10 @@ const handleResponses = async (c) => {
|
|
|
6350
6332
|
const streamRequested = Boolean(payload.stream);
|
|
6351
6333
|
const { initiator: initialInitiator } = getResponsesRequestOptions(payload);
|
|
6352
6334
|
const userId = payload.metadata?.user_id;
|
|
6353
|
-
const
|
|
6335
|
+
const requestBodyPromptCacheKey = typeof payload.prompt_cache_key === "string" ? payload.prompt_cache_key : null;
|
|
6336
|
+
const { safetyIdentifier, sessionId: metadataSessionId } = parseUserIdMetadata(userId);
|
|
6354
6337
|
const normalizedSafetyIdentifier = safetyIdentifier ?? void 0;
|
|
6355
|
-
const normalizedPromptCacheKey =
|
|
6338
|
+
const normalizedPromptCacheKey = requestBodyPromptCacheKey ?? metadataSessionId ?? void 0;
|
|
6356
6339
|
request.userId = userId;
|
|
6357
6340
|
request.safetyIdentifier = normalizedSafetyIdentifier;
|
|
6358
6341
|
request.promptCacheKey = normalizedPromptCacheKey;
|
|
@@ -6370,10 +6353,19 @@ const handleResponses = async (c) => {
|
|
|
6370
6353
|
});
|
|
6371
6354
|
}
|
|
6372
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;
|
|
6373
6365
|
const selection = await accountsManager.selectAccountForRequest([{
|
|
6374
6366
|
modelId: clientModel,
|
|
6375
6367
|
endpoint: RESPONSES_ENDPOINT
|
|
6376
|
-
}], { requestId:
|
|
6368
|
+
}], { requestId: affinityKey.requestId });
|
|
6377
6369
|
if (!selection.ok) {
|
|
6378
6370
|
recordSelectionFailure(store, {
|
|
6379
6371
|
request,
|
|
@@ -6386,6 +6378,7 @@ const handleResponses = async (c) => {
|
|
|
6386
6378
|
const { account, selectedModel } = selection;
|
|
6387
6379
|
request.affinityHit = selection.affinityHit;
|
|
6388
6380
|
request.affinityCacheKey = selection.affinityCacheKey;
|
|
6381
|
+
request.selectionReason = selection.selectionReason;
|
|
6389
6382
|
const upstreamPayload = {
|
|
6390
6383
|
...payload,
|
|
6391
6384
|
model: selectedModel.id
|
|
@@ -6399,7 +6392,7 @@ const handleResponses = async (c) => {
|
|
|
6399
6392
|
request.initiator = initiator;
|
|
6400
6393
|
if (state.manualApprove) await awaitApproval();
|
|
6401
6394
|
const accountCtx = toAccountContext(account);
|
|
6402
|
-
const upstreamSessionId = getUUID(upstreamRequestId);
|
|
6395
|
+
const upstreamSessionId = getUUID(normalizedPromptCacheKey ?? headerSessionId ?? upstreamRequestId);
|
|
6403
6396
|
request.upstreamRequestId = upstreamRequestId;
|
|
6404
6397
|
request.upstreamSessionId = upstreamSessionId;
|
|
6405
6398
|
if (streamRequested) return handleStreamingResponses({
|
|
@@ -6429,6 +6422,37 @@ const handleResponses = async (c) => {
|
|
|
6429
6422
|
premiumUnlimitedBefore
|
|
6430
6423
|
});
|
|
6431
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
|
+
}
|
|
6432
6456
|
function buildRequestContext(c) {
|
|
6433
6457
|
const requestId = randomUUID();
|
|
6434
6458
|
const startedAtMs = Date.now();
|
|
@@ -6459,6 +6483,9 @@ function insertRequestLog(store, request, record) {
|
|
|
6459
6483
|
promptCacheKey: request.promptCacheKey,
|
|
6460
6484
|
initiator: request.initiator,
|
|
6461
6485
|
upstreamRequestId: request.upstreamRequestId,
|
|
6486
|
+
affinityKeyUsed: request.affinityKeyUsed,
|
|
6487
|
+
affinityKeySource: request.affinityKeySource,
|
|
6488
|
+
selectionReason: request.selectionReason,
|
|
6462
6489
|
affinityHit: request.affinityHit,
|
|
6463
6490
|
affinityCacheKey: request.affinityCacheKey,
|
|
6464
6491
|
...record
|
|
@@ -6497,14 +6524,6 @@ function extractUsageFromChunkData(data) {
|
|
|
6497
6524
|
return;
|
|
6498
6525
|
}
|
|
6499
6526
|
}
|
|
6500
|
-
function getStreamChunkFields(chunk) {
|
|
6501
|
-
const c = chunk;
|
|
6502
|
-
return {
|
|
6503
|
-
id: c.id,
|
|
6504
|
-
event: c.event,
|
|
6505
|
-
data: c.data
|
|
6506
|
-
};
|
|
6507
|
-
}
|
|
6508
6527
|
async function handleStreamingResponses(params) {
|
|
6509
6528
|
const { c, store, request, payload, selection, clientModel, accountCtx, vision, initiator, premiumRemainingBefore, premiumUnlimitedBefore } = params;
|
|
6510
6529
|
let response;
|
|
@@ -6555,8 +6574,8 @@ async function handleUpstreamCreateError(params) {
|
|
|
6555
6574
|
const { store, request, selection, clientModel, premiumRemainingBefore, premiumUnlimitedBefore, error } = params;
|
|
6556
6575
|
const { account, reservation, selectedModel, endpoint, costUnits } = selection;
|
|
6557
6576
|
const finishedAtMs = Date.now();
|
|
6558
|
-
const details =
|
|
6559
|
-
if (details
|
|
6577
|
+
const details = await extractErrorObservability(error);
|
|
6578
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
|
|
6560
6579
|
await accountsManager.finalizeQuota(account, reservation);
|
|
6561
6580
|
const premiumRemainingAfter = account.premiumRemaining;
|
|
6562
6581
|
const premiumUnlimitedAfter = account.unlimited;
|
|
@@ -6578,7 +6597,8 @@ async function handleUpstreamCreateError(params) {
|
|
|
6578
6597
|
httpStatus: details.httpStatus,
|
|
6579
6598
|
errorName: details.errorName,
|
|
6580
6599
|
errorStatus: details.errorStatus,
|
|
6581
|
-
errorMessage: details.errorMessage
|
|
6600
|
+
errorMessage: details.errorMessage,
|
|
6601
|
+
upstreamErrorMessageRaw: details.upstreamErrorMessageRaw
|
|
6582
6602
|
});
|
|
6583
6603
|
throw error;
|
|
6584
6604
|
}
|
|
@@ -6590,6 +6610,7 @@ async function handleNonStreamingUpstreamResult(params) {
|
|
|
6590
6610
|
let errorName;
|
|
6591
6611
|
let errorStatus;
|
|
6592
6612
|
let errorMessage;
|
|
6613
|
+
let upstreamErrorMessageRaw;
|
|
6593
6614
|
const finishedAtMs = Date.now();
|
|
6594
6615
|
try {
|
|
6595
6616
|
debugJsonTail(logger$1, "Forwarding native Responses result:", {
|
|
@@ -6598,11 +6619,12 @@ async function handleNonStreamingUpstreamResult(params) {
|
|
|
6598
6619
|
});
|
|
6599
6620
|
return c.json(result);
|
|
6600
6621
|
} catch (error) {
|
|
6601
|
-
const details =
|
|
6622
|
+
const details = await extractErrorObservability(error);
|
|
6602
6623
|
httpStatus = details.httpStatus;
|
|
6603
6624
|
errorName = details.errorName;
|
|
6604
6625
|
errorStatus = details.errorStatus;
|
|
6605
6626
|
errorMessage = details.errorMessage;
|
|
6627
|
+
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
6606
6628
|
throw error;
|
|
6607
6629
|
} finally {
|
|
6608
6630
|
await accountsManager.finalizeQuota(account, reservation);
|
|
@@ -6627,7 +6649,8 @@ async function handleNonStreamingUpstreamResult(params) {
|
|
|
6627
6649
|
httpStatus,
|
|
6628
6650
|
errorName,
|
|
6629
6651
|
errorStatus,
|
|
6630
|
-
errorMessage
|
|
6652
|
+
errorMessage,
|
|
6653
|
+
upstreamErrorMessageRaw
|
|
6631
6654
|
});
|
|
6632
6655
|
}
|
|
6633
6656
|
}
|
|
@@ -6640,6 +6663,7 @@ async function streamResponsesAndLog(params) {
|
|
|
6640
6663
|
let errorName;
|
|
6641
6664
|
let errorStatus;
|
|
6642
6665
|
let errorMessage;
|
|
6666
|
+
let upstreamErrorMessageRaw;
|
|
6643
6667
|
try {
|
|
6644
6668
|
for await (const chunk of response) {
|
|
6645
6669
|
if (ttfbMs === void 0) ttfbMs = Date.now() - request.startedAtMs;
|
|
@@ -6655,11 +6679,14 @@ async function streamResponsesAndLog(params) {
|
|
|
6655
6679
|
});
|
|
6656
6680
|
}
|
|
6657
6681
|
} catch (error) {
|
|
6658
|
-
const details =
|
|
6682
|
+
const details = await extractErrorObservability(error);
|
|
6659
6683
|
errorName = details.errorName;
|
|
6660
6684
|
errorStatus = details.errorStatus;
|
|
6661
6685
|
errorMessage = details.errorMessage;
|
|
6686
|
+
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
6662
6687
|
logger$1.warn("Responses streaming error:", error);
|
|
6688
|
+
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
|
|
6689
|
+
await writeResponsesStreamError(stream, getUserVisibleErrorMessage(details));
|
|
6663
6690
|
} finally {
|
|
6664
6691
|
const finishedAtMs = Date.now();
|
|
6665
6692
|
await accountsManager.finalizeQuota(account, reservation);
|
|
@@ -6685,18 +6712,16 @@ async function streamResponsesAndLog(params) {
|
|
|
6685
6712
|
httpStatus: errorStatus ?? (errorName ? 500 : 200),
|
|
6686
6713
|
errorName,
|
|
6687
6714
|
errorStatus,
|
|
6688
|
-
errorMessage
|
|
6715
|
+
errorMessage,
|
|
6716
|
+
upstreamErrorMessageRaw
|
|
6689
6717
|
});
|
|
6690
6718
|
}
|
|
6691
6719
|
}
|
|
6692
6720
|
async function handleNonStreamingResponses(params) {
|
|
6693
6721
|
const { c, store, request, payload, selection, clientModel, accountCtx, vision, initiator, premiumRemainingBefore, premiumUnlimitedBefore } = params;
|
|
6694
6722
|
const { account, reservation, selectedModel, endpoint, costUnits } = selection;
|
|
6695
|
-
let httpStatus = 200;
|
|
6696
6723
|
let usage = {};
|
|
6697
|
-
let
|
|
6698
|
-
let errorStatus;
|
|
6699
|
-
let errorMessage;
|
|
6724
|
+
let errorState = { httpStatus: 200 };
|
|
6700
6725
|
let finishedAtMs;
|
|
6701
6726
|
try {
|
|
6702
6727
|
const response = await createResponses(payload, {
|
|
@@ -6705,10 +6730,9 @@ async function handleNonStreamingResponses(params) {
|
|
|
6705
6730
|
upstreamRequestId: request.upstreamRequestId,
|
|
6706
6731
|
sessionId: request.upstreamSessionId
|
|
6707
6732
|
}, accountCtx);
|
|
6733
|
+
if (isAsyncIterable(response)) throw new Error("Upstream returned a stream unexpectedly");
|
|
6708
6734
|
selection.confirmAffinity?.();
|
|
6709
6735
|
finishedAtMs = Date.now();
|
|
6710
|
-
const streamResponse = handleUnexpectedResponsesStream(c, response);
|
|
6711
|
-
if (streamResponse) return streamResponse;
|
|
6712
6736
|
const result = response;
|
|
6713
6737
|
usage = extractResponsesUsageFromResult(result);
|
|
6714
6738
|
debugJsonTail(logger$1, "Forwarding native Responses result:", {
|
|
@@ -6718,12 +6742,7 @@ async function handleNonStreamingResponses(params) {
|
|
|
6718
6742
|
return c.json(result);
|
|
6719
6743
|
} catch (error) {
|
|
6720
6744
|
finishedAtMs = Date.now();
|
|
6721
|
-
|
|
6722
|
-
httpStatus = details.httpStatus;
|
|
6723
|
-
errorName = details.errorName;
|
|
6724
|
-
errorStatus = details.errorStatus;
|
|
6725
|
-
errorMessage = details.errorMessage;
|
|
6726
|
-
if (details.unauthorized) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
|
|
6745
|
+
errorState = await observeRequestError(account.id, error);
|
|
6727
6746
|
throw error;
|
|
6728
6747
|
} finally {
|
|
6729
6748
|
const finishedAtMsFinal = finishedAtMs ?? Date.now();
|
|
@@ -6746,61 +6765,14 @@ async function handleNonStreamingResponses(params) {
|
|
|
6746
6765
|
premiumRemainingDiff: computeDiff(premiumRemainingBefore, premiumRemainingAfter),
|
|
6747
6766
|
premiumUnlimitedBefore,
|
|
6748
6767
|
premiumUnlimitedAfter,
|
|
6749
|
-
httpStatus,
|
|
6750
|
-
errorName,
|
|
6751
|
-
errorStatus,
|
|
6752
|
-
errorMessage
|
|
6768
|
+
httpStatus: errorState.httpStatus,
|
|
6769
|
+
errorName: errorState.errorName,
|
|
6770
|
+
errorStatus: errorState.errorStatus,
|
|
6771
|
+
errorMessage: errorState.errorMessage,
|
|
6772
|
+
upstreamErrorMessageRaw: errorState.upstreamErrorMessageRaw
|
|
6753
6773
|
});
|
|
6754
6774
|
}
|
|
6755
6775
|
}
|
|
6756
|
-
function handleUnexpectedResponsesStream(c, response) {
|
|
6757
|
-
if (!isAsyncIterable(response)) return null;
|
|
6758
|
-
logger$1.debug("Forwarding native Responses stream (unexpected)");
|
|
6759
|
-
return streamSSE(c, async (stream) => {
|
|
6760
|
-
const idTracker = createStreamIdTracker();
|
|
6761
|
-
for await (const chunk of response) {
|
|
6762
|
-
const { id, event, data } = getStreamChunkFields(chunk);
|
|
6763
|
-
const processedData = fixStreamIds(data ?? "", event, idTracker);
|
|
6764
|
-
debugJson(logger$1, "Responses stream chunk:", chunk);
|
|
6765
|
-
await stream.writeSSE({
|
|
6766
|
-
id,
|
|
6767
|
-
event,
|
|
6768
|
-
data: processedData
|
|
6769
|
-
});
|
|
6770
|
-
}
|
|
6771
|
-
});
|
|
6772
|
-
}
|
|
6773
|
-
const isAsyncIterable = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
|
|
6774
|
-
const useFunctionApplyPatch = (payload) => {
|
|
6775
|
-
if (!(getConfig().useFunctionApplyPatch ?? true)) return;
|
|
6776
|
-
logger$1.debug("Using function tool apply_patch for responses");
|
|
6777
|
-
if (Array.isArray(payload.tools)) {
|
|
6778
|
-
const toolsArr = payload.tools;
|
|
6779
|
-
for (let i = 0; i < toolsArr.length; i++) {
|
|
6780
|
-
const t = toolsArr[i];
|
|
6781
|
-
if (t.type === "custom" && t.name === "apply_patch") toolsArr[i] = {
|
|
6782
|
-
type: "function",
|
|
6783
|
-
name: t.name,
|
|
6784
|
-
description: "Use the `apply_patch` tool to edit files",
|
|
6785
|
-
parameters: {
|
|
6786
|
-
type: "object",
|
|
6787
|
-
properties: { input: {
|
|
6788
|
-
type: "string",
|
|
6789
|
-
description: "The entire contents of the apply_patch command"
|
|
6790
|
-
} },
|
|
6791
|
-
required: ["input"]
|
|
6792
|
-
},
|
|
6793
|
-
strict: false
|
|
6794
|
-
};
|
|
6795
|
-
}
|
|
6796
|
-
}
|
|
6797
|
-
};
|
|
6798
|
-
const removeWebSearchTool = (payload) => {
|
|
6799
|
-
if (!Array.isArray(payload.tools) || payload.tools.length === 0) return;
|
|
6800
|
-
payload.tools = payload.tools.filter((t) => {
|
|
6801
|
-
return t.type !== "web_search";
|
|
6802
|
-
});
|
|
6803
|
-
};
|
|
6804
6776
|
|
|
6805
6777
|
//#endregion
|
|
6806
6778
|
//#region src/routes/responses/route.ts
|
|
@@ -6894,4 +6866,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
|
|
|
6894
6866
|
|
|
6895
6867
|
//#endregion
|
|
6896
6868
|
export { server };
|
|
6897
|
-
//# sourceMappingURL=server-
|
|
6869
|
+
//# sourceMappingURL=server-DAxpfPde.js.map
|