@nick3/copilot-api 1.9.2 → 1.9.15
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 +111 -88
- package/README.zh-CN.md +111 -85
- package/dist/{account-MllYSdRC.js → account-DjCbqJ2Q.js} +20 -24
- package/dist/account-DjCbqJ2Q.js.map +1 -0
- package/dist/admin/assets/index-BRnD4-DB.js +110 -0
- package/dist/admin/assets/index-CBMFCvqO.css +1 -0
- package/dist/admin/index.html +2 -2
- package/dist/{auth-DZoQA-kn.js → auth--I1utaB6.js} +103 -112
- package/dist/auth--I1utaB6.js.map +1 -0
- package/dist/{check-usage-DEbsehjH.js → check-usage-DHvjdha4.js} +6 -7
- package/dist/{check-usage-DEbsehjH.js.map → check-usage-DHvjdha4.js.map} +1 -1
- package/dist/{debug-BJfZVBB7.js → debug-BMo6ltbp.js} +6 -6
- package/dist/debug-BMo6ltbp.js.map +1 -0
- package/dist/{get-copilot-token-4mCKt94e.js → get-copilot-token-ZbmbVF0I.js} +3 -4
- package/dist/{get-copilot-token-4mCKt94e.js.map → get-copilot-token-ZbmbVF0I.js.map} +1 -1
- package/dist/main.js +6 -7
- package/dist/main.js.map +1 -1
- package/dist/{paths-DGlr310R.js → paths-CclKwouX.js} +3 -5
- package/dist/{paths-DGlr310R.js.map → paths-CclKwouX.js.map} +1 -1
- package/dist/{poll-access-token-Dvk6Ho0R.js → poll-access-token-CIPDXrcm.js} +4 -16
- package/dist/poll-access-token-CIPDXrcm.js.map +1 -0
- package/dist/{accounts-manager-BM66oT38.js → quota-refresh-scheduler-runtime-XD2fDa2K.js} +434 -51
- package/dist/quota-refresh-scheduler-runtime-XD2fDa2K.js.map +1 -0
- package/dist/{request-outbound-qyTeXbzy.js → request-outbound-CxvpSkOn.js} +14 -9
- package/dist/request-outbound-CxvpSkOn.js.map +1 -0
- package/dist/request-outbound-Cy6huWjK.js +2 -0
- package/dist/{server-DR9ZR_MN.js → server-BDCnb3Ao.js} +1760 -975
- package/dist/server-BDCnb3Ao.js.map +1 -0
- package/dist/{start-DDhYUFQR.js → start-DkBnp9d8.js} +11 -13
- package/dist/start-DkBnp9d8.js.map +1 -0
- package/package.json +20 -7
- package/dist/account-MllYSdRC.js.map +0 -1
- package/dist/accounts-manager-BM66oT38.js.map +0 -1
- package/dist/admin/assets/index-8eGib92I.js +0 -107
- package/dist/admin/assets/index-B2qj1asn.css +0 -1
- package/dist/auth-DZoQA-kn.js.map +0 -1
- package/dist/debug-BJfZVBB7.js.map +0 -1
- package/dist/poll-access-token-Dvk6Ho0R.js.map +0 -1
- package/dist/request-outbound-DhI9-SrV.js +0 -4
- package/dist/request-outbound-qyTeXbzy.js.map +0 -1
- package/dist/server-DR9ZR_MN.js.map +0 -1
- package/dist/start-DDhYUFQR.js.map +0 -1
|
@@ -1,23 +1,21 @@
|
|
|
1
|
-
import { A as captureOutboundHeadersSnapshot, D as prepareMessageProxyHeaders, E as prepareInteractionHeaders, M as requestContext, N as resolveTraceId, 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, 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-
|
|
2
|
-
import {
|
|
3
|
-
import { r as ensurePaths, t as PATHS } from "./paths-
|
|
4
|
-
import "./
|
|
5
|
-
import { i as
|
|
6
|
-
import { A as isMessageStartInputTokensFallbackEnabled, C as getModelAliasesInfo, D as getSmallModel, E as getReasoningEffortForModel, F as resolveModelAlias, I as shouldCompactUseSmallModel, M as isResponsesApiContextManagementModel, N as isResponsesApiWebSearchEnabled, O as isAccountAffinityEnabled, P as mergeConfigWithDefaults, S as getModelAliases, T as getProviderConfig, _ as getAnthropicApiKey, a as getClientIpInfo, b as getExtraPromptForModel, c as normalizeChatCompletionsUsage, d as toLocalDateString, f as copilotFetch, g as getAliasTargetSet, h as PROVIDER_TYPE_ANTHROPIC, i as extractResponsesUsageFromStreamEvent, j as isMessagesApiEnabled, k as isForceAgentEnabled, l as normalizeEmbeddingsUsage, m as isDevModeEnabled, n as applySharedSessionAffinityRetention, o as getRequestHistoryStore, p as flushPendingCapture, r as extractResponsesUsageFromResult, s as getStatsStore, t as accountsManager, u as normalizeMessagesUsage, v as getClaudeTokenMultiplier, w as getModelRefreshIntervalMs, x as getLogLevel, y as getConfig } from "./accounts-manager-BM66oT38.js";
|
|
1
|
+
import { A as captureOutboundHeadersSnapshot, D as prepareMessageProxyHeaders, E as prepareInteractionHeaders, M as requestContext, N as resolveTraceId, 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, 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-CIPDXrcm.js";
|
|
2
|
+
import { 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-DjCbqJ2Q.js";
|
|
3
|
+
import { r as ensurePaths, t as PATHS } from "./paths-CclKwouX.js";
|
|
4
|
+
import { i as getRequestOutboundStore, r as getRedactedHeaderKeys } from "./request-outbound-CxvpSkOn.js";
|
|
5
|
+
import { A as getReasoningEffortForModel, B as shouldCompactUseSmallModel, C as getConfig, D as getModelAliasesInfo, E as getModelAliases, F as isMessagesApiEnabled, I as isResponsesApiContextManagementModel, L as isResponsesApiWebSearchEnabled, M as isAccountAffinityEnabled, N as isForceAgentEnabled, O as getModelRefreshIntervalMs, P as isMessageStartInputTokensFallbackEnabled, R as mergeConfigWithDefaults, S as getClaudeTokenMultiplier, T as getLogLevel, _ as flushPendingCapture, a as accountsManager, b as getAliasTargetSet, c as extractResponsesUsageFromStreamEvent, d as getStatsStore, f as normalizeChatCompletionsUsage, g as copilotFetch, h as toLocalDateString, i as updateQuotaRefreshSchedulerFromConfig, j as getSmallModel, k as getProviderConfig, l as getClientIpInfo, m as normalizeMessagesUsage, o as applySharedSessionAffinityRetention, p as normalizeEmbeddingsUsage, s as extractResponsesUsageFromResult, u as getRequestHistoryStore, v as isDevModeEnabled, w as getExtraPromptForModel, x as getAnthropicApiKey, y as PROVIDER_TYPE_ANTHROPIC, z as resolveModelAlias } from "./quota-refresh-scheduler-runtime-XD2fDa2K.js";
|
|
7
6
|
import consola from "consola";
|
|
8
7
|
import fs, { readFile } from "node:fs/promises";
|
|
9
|
-
import { randomUUID, timingSafeEqual } from "node:crypto";
|
|
8
|
+
import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
|
|
10
9
|
import * as path$1 from "node:path";
|
|
11
10
|
import path from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
12
|
import { Hono } from "hono";
|
|
13
13
|
import { cors } from "hono/cors";
|
|
14
14
|
import { logger } from "hono/logger";
|
|
15
15
|
import fs$1, { existsSync } from "node:fs";
|
|
16
16
|
import { streamSSE } from "hono/streaming";
|
|
17
17
|
import { events } from "fetch-event-stream";
|
|
18
|
-
import { fileURLToPath } from "node:url";
|
|
19
18
|
import util from "node:util";
|
|
20
|
-
|
|
21
19
|
//#region src/lib/request-auth.ts
|
|
22
20
|
const LEGACY_API_KEY_ENV_VAR = "COPILOT_API_KEY";
|
|
23
21
|
let warnedLegacyEnvFallback = false;
|
|
@@ -88,8 +86,8 @@ function timingSafeKeyCompare(a, b) {
|
|
|
88
86
|
}
|
|
89
87
|
function createAuthMiddleware(options = {}) {
|
|
90
88
|
const getApiKeys = options.getApiKeys ?? getConfiguredApiKeys;
|
|
91
|
-
const allowUnauthenticatedPaths = new Set((options.allowUnauthenticatedPaths ?? ["/"]).map((path
|
|
92
|
-
const allowUnauthenticatedPathPrefixes = (options.allowUnauthenticatedPathPrefixes ?? []).map((path
|
|
89
|
+
const allowUnauthenticatedPaths = new Set((options.allowUnauthenticatedPaths ?? ["/"]).map((path) => normalizePathname(path)));
|
|
90
|
+
const allowUnauthenticatedPathPrefixes = (options.allowUnauthenticatedPathPrefixes ?? []).map((path) => normalizePathname(path));
|
|
93
91
|
const allowOptionsBypass = options.allowOptionsBypass ?? true;
|
|
94
92
|
return async (c, next) => {
|
|
95
93
|
if (allowOptionsBypass && c.req.method === "OPTIONS") return next();
|
|
@@ -103,7 +101,6 @@ function createAuthMiddleware(options = {}) {
|
|
|
103
101
|
return next();
|
|
104
102
|
};
|
|
105
103
|
}
|
|
106
|
-
|
|
107
104
|
//#endregion
|
|
108
105
|
//#region src/lib/trace.ts
|
|
109
106
|
const traceIdMiddleware = async (c, next) => {
|
|
@@ -120,7 +117,6 @@ const traceIdMiddleware = async (c, next) => {
|
|
|
120
117
|
await next();
|
|
121
118
|
});
|
|
122
119
|
};
|
|
123
|
-
|
|
124
120
|
//#endregion
|
|
125
121
|
//#region src/routes/admin-api/auth-sessions.ts
|
|
126
122
|
function buildOauthUrls(enterpriseDomain) {
|
|
@@ -277,7 +273,6 @@ var AuthSessionManager = class {
|
|
|
277
273
|
}
|
|
278
274
|
};
|
|
279
275
|
const authSessionManager = new AuthSessionManager();
|
|
280
|
-
|
|
281
276
|
//#endregion
|
|
282
277
|
//#region src/routes/admin-api/config-writer.ts
|
|
283
278
|
async function writeConfigFile(config) {
|
|
@@ -298,7 +293,6 @@ async function writeConfigFile(config) {
|
|
|
298
293
|
throw error;
|
|
299
294
|
}
|
|
300
295
|
}
|
|
301
|
-
|
|
302
296
|
//#endregion
|
|
303
297
|
//#region src/lib/models.ts
|
|
304
298
|
const getAvailableModels = () => (accountsManager.getFirstAccountModels()?.data ?? []).filter((model) => model.model_picker_enabled || model.capabilities.type === "embeddings");
|
|
@@ -349,7 +343,6 @@ const _normalizeSdkModelId = (sdkModelId) => {
|
|
|
349
343
|
version: pattern5[1]
|
|
350
344
|
};
|
|
351
345
|
};
|
|
352
|
-
|
|
353
346
|
//#endregion
|
|
354
347
|
//#region src/lib/copilot-rate-limit.ts
|
|
355
348
|
const copilotRateLimitTypes = ["session", "weekly"];
|
|
@@ -395,14 +388,12 @@ const logCopilotRateLimits = (headers) => {
|
|
|
395
388
|
consola.info(`Copilot ${usage.type} quota remaining: ${usage.remaining}, resets at: ${dateStr}`);
|
|
396
389
|
}
|
|
397
390
|
};
|
|
398
|
-
|
|
399
391
|
//#endregion
|
|
400
392
|
//#region src/lib/request-initiator.ts
|
|
401
393
|
function resolveEffectiveInitiator(baseInitiator, options) {
|
|
402
394
|
if (options.isCompact || options.isSubagent) return "agent";
|
|
403
395
|
return baseInitiator;
|
|
404
396
|
}
|
|
405
|
-
|
|
406
397
|
//#endregion
|
|
407
398
|
//#region src/services/copilot/create-chat-completions.ts
|
|
408
399
|
function isGpt5MiniFamily(modelId) {
|
|
@@ -425,7 +416,7 @@ const getChatInitiator = (messages) => {
|
|
|
425
416
|
const createChatCompletions = async (payload, account, options) => {
|
|
426
417
|
const ctx = account ?? accountFromState();
|
|
427
418
|
if (!ctx.copilotToken) throw new Error("Copilot token not found");
|
|
428
|
-
const enableVision = payload.messages.some((x) => typeof x.content !== "string" && x.content?.some((x
|
|
419
|
+
const enableVision = payload.messages.some((x) => typeof x.content !== "string" && x.content?.some((x) => x.type === "image_url"));
|
|
429
420
|
const effectiveInitiator = resolveEffectiveInitiator(options?.initiator ?? getChatInitiator(payload.messages), {
|
|
430
421
|
isCompact: Boolean(options?.compactType),
|
|
431
422
|
isSubagent: Boolean(options?.subagentMarker)
|
|
@@ -444,7 +435,8 @@ const createChatCompletions = async (payload, account, options) => {
|
|
|
444
435
|
body: JSON.stringify(upstreamPayload)
|
|
445
436
|
}, {
|
|
446
437
|
requestId: options?.requestId,
|
|
447
|
-
callSite: "chat-completions"
|
|
438
|
+
callSite: "chat-completions",
|
|
439
|
+
fetchImpl: options?.fetchImpl
|
|
448
440
|
});
|
|
449
441
|
logCopilotRateLimits(response.headers);
|
|
450
442
|
if (!response.ok) {
|
|
@@ -454,7 +446,6 @@ const createChatCompletions = async (payload, account, options) => {
|
|
|
454
446
|
if (payload.stream) return events(response);
|
|
455
447
|
return await response.json();
|
|
456
448
|
};
|
|
457
|
-
|
|
458
449
|
//#endregion
|
|
459
450
|
//#region src/lib/tokenizer.ts
|
|
460
451
|
const ENCODING_MAP = {
|
|
@@ -485,7 +476,10 @@ const calculateToolCallsTokens = (toolCalls, encoder, constants) => {
|
|
|
485
476
|
const calculateContentPartsTokens = (contentParts, encoder) => {
|
|
486
477
|
let tokens = 0;
|
|
487
478
|
for (const part of contentParts) if (part.type === "image_url") tokens += encoder.encode(part.image_url.url).length + 85;
|
|
488
|
-
else if (part.
|
|
479
|
+
else if (part.type === "file") {
|
|
480
|
+
tokens += encoder.encode(part.file.file_data).length;
|
|
481
|
+
if (part.file.filename) tokens += encoder.encode(part.file.filename).length;
|
|
482
|
+
} else if (part.text) tokens += encoder.encode(part.text).length;
|
|
489
483
|
return tokens;
|
|
490
484
|
};
|
|
491
485
|
/**
|
|
@@ -669,29 +663,13 @@ const getTokenCount = async (payload, model) => {
|
|
|
669
663
|
output: outputTokens
|
|
670
664
|
};
|
|
671
665
|
};
|
|
672
|
-
|
|
673
|
-
//#endregion
|
|
674
|
-
//#region src/lib/compact.ts
|
|
675
|
-
const COMPACT_REQUEST = 1;
|
|
676
|
-
const COMPACT_AUTO_CONTINUE = 2;
|
|
677
|
-
const compactSystemPromptStart = "You are a helpful AI assistant tasked with summarizing conversations";
|
|
678
|
-
const compactOpenCodeSystemPromptStart = "You are an anchored context summarization assistant for coding sessions.";
|
|
679
|
-
const compactSystemPromptStarts = [compactSystemPromptStart, compactOpenCodeSystemPromptStart];
|
|
680
|
-
const compactTextOnlyGuard = "CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.";
|
|
681
|
-
const compactSummaryPromptStart = "Your task is to create a detailed summary of the conversation so far";
|
|
682
|
-
const compactAutoContinueClaudeCodePromptStart = "This session is being continued from a previous conversation that ran out of context. The summary below covers the earlier portion of the conversation.";
|
|
683
|
-
const compactAutoContinueOpenCodePromptStart = "Continue if you have next steps, or stop and ask for clarification if you are unsure how to proceed.";
|
|
684
|
-
const compactAutoContinueOpenCodePromptStart2 = "The previous request exceeded the provider's size limit due to large media attachments. The conversation was compacted and media files were removed from context.";
|
|
666
|
+
const compactSystemPromptStarts = ["You are a helpful AI assistant tasked with summarizing conversations", "You are an anchored context summarization assistant for coding sessions."];
|
|
685
667
|
const compactAutoContinuePromptStarts = [
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
668
|
+
"This session is being continued from a previous conversation that ran out of context. The summary below covers the earlier portion of the conversation.",
|
|
669
|
+
"Continue if you have next steps, or stop and ask for clarification if you are unsure how to proceed.",
|
|
670
|
+
"The previous request exceeded the provider's size limit due to large media attachments. The conversation was compacted and media files were removed from context."
|
|
689
671
|
];
|
|
690
672
|
const compactMessageSections = ["Pending Tasks:", "Current Work:"];
|
|
691
|
-
|
|
692
|
-
//#endregion
|
|
693
|
-
//#region src/routes/messages/preprocess.ts
|
|
694
|
-
const TOOL_REFERENCE_TURN_BOUNDARY = "Tool loaded.";
|
|
695
673
|
const IDE_EXECUTE_CODE_TOOL = "mcp__ide__executeCode";
|
|
696
674
|
const IDE_GET_DIAGNOSTICS_TOOL = "mcp__ide__getDiagnostics";
|
|
697
675
|
const IDE_GET_DIAGNOSTICS_DESCRIPTION = "Get language diagnostics from VS Code. Returns errors, warnings, information, and hints for files in the workspace.";
|
|
@@ -704,7 +682,7 @@ const getCompactCandidateText = (message) => {
|
|
|
704
682
|
const isCompactMessage = (lastMessage) => {
|
|
705
683
|
const text = getCompactCandidateText(lastMessage);
|
|
706
684
|
if (!text) return false;
|
|
707
|
-
return text.includes(
|
|
685
|
+
return text.includes("CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.") && text.includes("Your task is to create a detailed summary of the conversation so far") && compactMessageSections.some((section) => text.includes(section));
|
|
708
686
|
};
|
|
709
687
|
const isCompactAutoContinueMessage = (lastMessage) => {
|
|
710
688
|
const text = getCompactCandidateText(lastMessage);
|
|
@@ -712,12 +690,12 @@ const isCompactAutoContinueMessage = (lastMessage) => {
|
|
|
712
690
|
};
|
|
713
691
|
const getCompactType = (anthropicPayload) => {
|
|
714
692
|
const lastMessage = anthropicPayload.messages.at(-1);
|
|
715
|
-
if (lastMessage && isCompactMessage(lastMessage)) return
|
|
716
|
-
if (lastMessage && isCompactAutoContinueMessage(lastMessage)) return
|
|
693
|
+
if (lastMessage && isCompactMessage(lastMessage)) return 1;
|
|
694
|
+
if (lastMessage && isCompactAutoContinueMessage(lastMessage)) return 2;
|
|
717
695
|
const system = anthropicPayload.system;
|
|
718
|
-
if (typeof system === "string") return compactSystemPromptStarts.some((promptStart) => system.startsWith(promptStart)) ?
|
|
696
|
+
if (typeof system === "string") return compactSystemPromptStarts.some((promptStart) => system.startsWith(promptStart)) ? 1 : 0;
|
|
719
697
|
if (!Array.isArray(system)) return 0;
|
|
720
|
-
if (system.some((msg) => typeof msg.text === "string" && compactSystemPromptStarts.some((promptStart) => msg.text.startsWith(promptStart)))) return
|
|
698
|
+
if (system.some((msg) => typeof msg.text === "string" && compactSystemPromptStarts.some((promptStart) => msg.text.startsWith(promptStart)))) return 1;
|
|
721
699
|
return 0;
|
|
722
700
|
};
|
|
723
701
|
const mergeContentWithText = (tr, textBlock) => {
|
|
@@ -778,9 +756,9 @@ const assignAttachmentsToToolResults = (target, attachments, options) => {
|
|
|
778
756
|
if (attachments.length === 0) return;
|
|
779
757
|
if (toolResultIndices.length > 0 && toolResultIndices.length === attachments.length) {
|
|
780
758
|
for (const [index, toolResultIndex] of toolResultIndices.entries()) {
|
|
781
|
-
const currentAttachments
|
|
782
|
-
if (currentAttachments
|
|
783
|
-
currentAttachments
|
|
759
|
+
const currentAttachments = target.get(toolResultIndex);
|
|
760
|
+
if (currentAttachments) {
|
|
761
|
+
currentAttachments.push(attachments[index]);
|
|
784
762
|
continue;
|
|
785
763
|
}
|
|
786
764
|
target.set(toolResultIndex, [attachments[index]]);
|
|
@@ -872,7 +850,7 @@ const stripToolReferenceTurnBoundary = (anthropicPayload) => {
|
|
|
872
850
|
for (const msg of anthropicPayload.messages) {
|
|
873
851
|
if (msg.role !== "user" || !Array.isArray(msg.content)) continue;
|
|
874
852
|
if (!msg.content.some((block) => block.type === "tool_result" && hasToolRef(block))) continue;
|
|
875
|
-
msg.content = msg.content.filter((block) => block.type !== "text" || block.text.trim() !==
|
|
853
|
+
msg.content = msg.content.filter((block) => block.type !== "text" || block.text.trim() !== "Tool loaded.");
|
|
876
854
|
}
|
|
877
855
|
};
|
|
878
856
|
const mergeToolResultForClaude = (anthropicPayload, options) => {
|
|
@@ -947,7 +925,6 @@ const prepareMessagesApiPayload = (payload, selectedModel) => {
|
|
|
947
925
|
payload.output_config = { effort };
|
|
948
926
|
}
|
|
949
927
|
};
|
|
950
|
-
|
|
951
928
|
//#endregion
|
|
952
929
|
//#region src/routes/messages/utils.ts
|
|
953
930
|
function mapOpenAIStopReasonToAnthropic(finishReason) {
|
|
@@ -959,14 +936,17 @@ function mapOpenAIStopReasonToAnthropic(finishReason) {
|
|
|
959
936
|
content_filter: "end_turn"
|
|
960
937
|
}[finishReason];
|
|
961
938
|
}
|
|
962
|
-
const estimateInputTokens = async (payload, selectedModel, logger
|
|
939
|
+
const estimateInputTokens = async (payload, selectedModel, logger) => {
|
|
963
940
|
try {
|
|
964
941
|
return (await getTokenCount(payload, selectedModel)).input;
|
|
965
942
|
} catch (error) {
|
|
966
|
-
logger
|
|
943
|
+
logger.warn("Failed to estimate input tokens for message_start", error);
|
|
967
944
|
return;
|
|
968
945
|
}
|
|
969
946
|
};
|
|
947
|
+
function stringifyOwnerKeys$1(keys) {
|
|
948
|
+
return keys && keys.length > 0 ? JSON.stringify(keys) : void 0;
|
|
949
|
+
}
|
|
970
950
|
const isWarmupProbeRequest = (payload) => {
|
|
971
951
|
const lastMsg = payload.messages.at(-1);
|
|
972
952
|
if (!lastMsg || lastMsg.role !== "user" || !Array.isArray(lastMsg.content)) return false;
|
|
@@ -983,7 +963,7 @@ const isWarmupProbeRequest = (payload) => {
|
|
|
983
963
|
return false;
|
|
984
964
|
};
|
|
985
965
|
const handleSelectionFailure = (context) => {
|
|
986
|
-
const { c, store, requestId, startedAtMs, method, path
|
|
966
|
+
const { c, store, requestId, startedAtMs, method, path, streamRequested, clientModel, clientIp, clientIpSource, userAgent, userId, safetyIdentifier, promptCacheKey, initiator, isSubagent, affinityKeyUsed, affinityKeySource, selectionReason, responsesItemOwnerLookupKeys, selection } = context;
|
|
987
967
|
const finishedAtMs = Date.now();
|
|
988
968
|
store.insert({
|
|
989
969
|
requestId,
|
|
@@ -991,7 +971,7 @@ const handleSelectionFailure = (context) => {
|
|
|
991
971
|
finishedAtMs,
|
|
992
972
|
durationMs: finishedAtMs - startedAtMs,
|
|
993
973
|
method,
|
|
994
|
-
path
|
|
974
|
+
path,
|
|
995
975
|
stream: streamRequested,
|
|
996
976
|
clientModel,
|
|
997
977
|
clientIp,
|
|
@@ -1004,6 +984,7 @@ const handleSelectionFailure = (context) => {
|
|
|
1004
984
|
isSubagent,
|
|
1005
985
|
affinityKeyUsed,
|
|
1006
986
|
affinityKeySource,
|
|
987
|
+
responsesItemOwnerLookupKeysJson: stringifyOwnerKeys$1(responsesItemOwnerLookupKeys),
|
|
1007
988
|
httpStatus: selection.reason === "MODEL_NOT_SUPPORTED" ? 400 : 429,
|
|
1008
989
|
selectionReason: selectionReason ?? selection.selectionReason,
|
|
1009
990
|
selectionFailureReason: selection.reason
|
|
@@ -1027,16 +1008,19 @@ const maybeBlockOriginalModelName = (context) => {
|
|
|
1027
1008
|
}
|
|
1028
1009
|
});
|
|
1029
1010
|
};
|
|
1030
|
-
|
|
1031
1011
|
//#endregion
|
|
1032
1012
|
//#region src/routes/messages/non-stream-translation.ts
|
|
1033
|
-
const THINKING_TEXT = "Thinking...";
|
|
1034
|
-
|
|
1013
|
+
const THINKING_TEXT$1 = "Thinking...";
|
|
1014
|
+
const COPILOT_TOOL_CONTENT_SUPPORT_TYPE = ["array", "image"];
|
|
1015
|
+
function translateToOpenAI(payload, options = {}) {
|
|
1035
1016
|
const modelId = payload.model;
|
|
1036
1017
|
const thinkingBudget = getThinkingBudget(payload, getAvailableModels().find((m) => m.id === modelId));
|
|
1037
1018
|
return {
|
|
1038
1019
|
model: modelId,
|
|
1039
|
-
messages: translateAnthropicMessagesToOpenAI(payload, modelId,
|
|
1020
|
+
messages: translateAnthropicMessagesToOpenAI(payload, modelId, {
|
|
1021
|
+
supportPdf: options.supportPdf ?? false,
|
|
1022
|
+
toolContentSupportType: options.toolContentSupportType ?? COPILOT_TOOL_CONTENT_SUPPORT_TYPE
|
|
1023
|
+
}),
|
|
1040
1024
|
max_tokens: payload.max_tokens,
|
|
1041
1025
|
stop: payload.stop_sequences,
|
|
1042
1026
|
stream: payload.stream,
|
|
@@ -1059,9 +1043,9 @@ function getThinkingBudget(payload, model) {
|
|
|
1059
1043
|
}
|
|
1060
1044
|
}
|
|
1061
1045
|
}
|
|
1062
|
-
function translateAnthropicMessagesToOpenAI(payload, modelId,
|
|
1046
|
+
function translateAnthropicMessagesToOpenAI(payload, modelId, capabilities) {
|
|
1063
1047
|
const systemMessages = handleSystemPrompt(payload.system);
|
|
1064
|
-
const otherMessages = payload.messages.flatMap((message) => message.role === "user" ? handleUserMessage(message) : handleAssistantMessage(message, modelId));
|
|
1048
|
+
const otherMessages = payload.messages.flatMap((message) => message.role === "user" ? handleUserMessage(message, capabilities) : handleAssistantMessage(message, modelId, capabilities));
|
|
1065
1049
|
return [...systemMessages, ...otherMessages];
|
|
1066
1050
|
}
|
|
1067
1051
|
function handleSystemPrompt(system) {
|
|
@@ -1077,19 +1061,21 @@ function handleSystemPrompt(system) {
|
|
|
1077
1061
|
}).join("\n\n")
|
|
1078
1062
|
}];
|
|
1079
1063
|
}
|
|
1080
|
-
function handleUserMessage(message) {
|
|
1064
|
+
function handleUserMessage(message, capabilities) {
|
|
1081
1065
|
const newMessages = [];
|
|
1082
1066
|
if (Array.isArray(message.content)) {
|
|
1083
1067
|
const toolResultBlocks = message.content.filter((block) => block.type === "tool_result");
|
|
1084
1068
|
const otherBlocks = message.content.filter((block) => block.type !== "tool_result");
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1069
|
+
const movedToolResultUserMessages = [];
|
|
1070
|
+
for (const block of toolResultBlocks) {
|
|
1071
|
+
const result = handleToolResultBlock(block, capabilities);
|
|
1072
|
+
newMessages.push(result.toolMessage);
|
|
1073
|
+
if (result.movedUserMessage) movedToolResultUserMessages.push(result.movedUserMessage);
|
|
1074
|
+
}
|
|
1075
|
+
newMessages.push(...movedToolResultUserMessages);
|
|
1090
1076
|
if (otherBlocks.length > 0) newMessages.push({
|
|
1091
1077
|
role: "user",
|
|
1092
|
-
content: mapContent(otherBlocks)
|
|
1078
|
+
content: mapContent(otherBlocks, { supportPdf: capabilities.supportPdf })
|
|
1093
1079
|
});
|
|
1094
1080
|
} else newMessages.push({
|
|
1095
1081
|
role: "user",
|
|
@@ -1097,20 +1083,74 @@ function handleUserMessage(message) {
|
|
|
1097
1083
|
});
|
|
1098
1084
|
return newMessages;
|
|
1099
1085
|
}
|
|
1100
|
-
function
|
|
1086
|
+
function handleToolResultBlock(block, capabilities) {
|
|
1087
|
+
if (typeof block.content === "string") return { toolMessage: createToolMessage(block.tool_use_id, block.content) };
|
|
1088
|
+
if (!Array.isArray(block.content)) return { toolMessage: createToolMessage(block.tool_use_id, "") };
|
|
1089
|
+
const support = getToolContentSupport(capabilities);
|
|
1090
|
+
const hasImage = block.content.some((block) => block.type === "image");
|
|
1091
|
+
const hasDocument = block.content.some((block) => block.type === "document");
|
|
1092
|
+
const content = mapContent(block.content, { supportPdf: capabilities.supportPdf });
|
|
1093
|
+
const hasPdfFile = hasDocument && capabilities.supportPdf;
|
|
1094
|
+
const shouldMoveImageToUserMessage = hasImage && !support.image;
|
|
1095
|
+
const shouldMovePdfToUserMessage = hasPdfFile && !support.pdf;
|
|
1096
|
+
if (shouldMoveImageToUserMessage || shouldMovePdfToUserMessage) return {
|
|
1097
|
+
movedUserMessage: createToolResultUserMessage(block, capabilities.supportPdf),
|
|
1098
|
+
toolMessage: createToolMessage(block.tool_use_id, getTextToolContent(content) || "Rich tool result content was moved to a user message because this upstream does not support it in tool messages.")
|
|
1099
|
+
};
|
|
1100
|
+
const hasRichContent = hasImage || hasPdfFile;
|
|
1101
|
+
if (support.array || hasRichContent) return { toolMessage: createToolMessage(block.tool_use_id, content) };
|
|
1102
|
+
return { toolMessage: createToolMessage(block.tool_use_id, getTextToolContent(content)) };
|
|
1103
|
+
}
|
|
1104
|
+
function getTextToolContent(content) {
|
|
1105
|
+
if (!Array.isArray(content)) return content ?? "";
|
|
1106
|
+
return content.flatMap((part) => part.type === "text" && part.text.length > 0 ? [part.text] : []).join("\n");
|
|
1107
|
+
}
|
|
1108
|
+
function getToolContentSupport(capabilities) {
|
|
1109
|
+
return {
|
|
1110
|
+
array: capabilities.toolContentSupportType.includes("array"),
|
|
1111
|
+
image: capabilities.toolContentSupportType.includes("image"),
|
|
1112
|
+
pdf: capabilities.supportPdf && capabilities.toolContentSupportType.includes("pdf")
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
function createToolMessage(toolCallId, content) {
|
|
1116
|
+
return {
|
|
1117
|
+
role: "tool",
|
|
1118
|
+
tool_call_id: toolCallId,
|
|
1119
|
+
content
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
function createToolResultUserMessage(block, supportPdf) {
|
|
1123
|
+
const prefix = {
|
|
1124
|
+
type: "text",
|
|
1125
|
+
text: `Tool result for ${block.tool_use_id}:`
|
|
1126
|
+
};
|
|
1127
|
+
const content = mapContent(block.content, { supportPdf });
|
|
1128
|
+
if (Array.isArray(content)) return {
|
|
1129
|
+
role: "user",
|
|
1130
|
+
content: [prefix, ...content]
|
|
1131
|
+
};
|
|
1132
|
+
return {
|
|
1133
|
+
role: "user",
|
|
1134
|
+
content: [prefix, {
|
|
1135
|
+
type: "text",
|
|
1136
|
+
text: content ?? ""
|
|
1137
|
+
}]
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
function handleAssistantMessage(message, modelId, capabilities) {
|
|
1101
1141
|
if (!Array.isArray(message.content)) return [{
|
|
1102
1142
|
role: "assistant",
|
|
1103
1143
|
content: mapContent(message.content)
|
|
1104
1144
|
}];
|
|
1105
1145
|
const toolUseBlocks = message.content.filter((block) => block.type === "tool_use");
|
|
1106
1146
|
let thinkingBlocks = message.content.filter((block) => block.type === "thinking");
|
|
1107
|
-
if (modelId.startsWith("claude")) thinkingBlocks = thinkingBlocks.filter((b) => b.thinking && b.thinking !==
|
|
1108
|
-
const thinkingContents = thinkingBlocks.filter((b) => b.thinking && b.thinking !==
|
|
1147
|
+
if (modelId.startsWith("claude")) thinkingBlocks = thinkingBlocks.filter((b) => b.thinking && b.thinking !== "Thinking..." && b.signature && !b.signature.includes("@"));
|
|
1148
|
+
const thinkingContents = thinkingBlocks.filter((b) => b.thinking && b.thinking !== "Thinking...").map((b) => b.thinking);
|
|
1109
1149
|
const allThinkingContent = thinkingContents.length > 0 ? thinkingContents.join("\n\n") : void 0;
|
|
1110
1150
|
const signature = thinkingBlocks.find((b) => b.signature)?.signature;
|
|
1111
1151
|
return toolUseBlocks.length > 0 ? [{
|
|
1112
1152
|
role: "assistant",
|
|
1113
|
-
content: mapContent(message.content),
|
|
1153
|
+
content: mapContent(message.content, { supportPdf: capabilities.supportPdf }),
|
|
1114
1154
|
reasoning_text: allThinkingContent,
|
|
1115
1155
|
reasoning_opaque: signature,
|
|
1116
1156
|
tool_calls: toolUseBlocks.map((toolUse) => ({
|
|
@@ -1123,12 +1163,12 @@ function handleAssistantMessage(message, modelId) {
|
|
|
1123
1163
|
}))
|
|
1124
1164
|
}] : [{
|
|
1125
1165
|
role: "assistant",
|
|
1126
|
-
content: mapContent(message.content),
|
|
1166
|
+
content: mapContent(message.content, { supportPdf: capabilities.supportPdf }),
|
|
1127
1167
|
reasoning_text: allThinkingContent,
|
|
1128
1168
|
reasoning_opaque: signature
|
|
1129
1169
|
}];
|
|
1130
1170
|
}
|
|
1131
|
-
function mapContent(content) {
|
|
1171
|
+
function mapContent(content, options = {}) {
|
|
1132
1172
|
if (typeof content === "string") return content;
|
|
1133
1173
|
if (!Array.isArray(content)) return null;
|
|
1134
1174
|
const contentParts = [];
|
|
@@ -1146,7 +1186,7 @@ function mapContent(content) {
|
|
|
1146
1186
|
});
|
|
1147
1187
|
break;
|
|
1148
1188
|
case "document":
|
|
1149
|
-
contentParts.push(createDocumentTextPart());
|
|
1189
|
+
contentParts.push(options.supportPdf ? createDocumentFilePart(block) : createDocumentTextPart());
|
|
1150
1190
|
break;
|
|
1151
1191
|
case "tool_reference":
|
|
1152
1192
|
contentParts.push({
|
|
@@ -1155,12 +1195,22 @@ function mapContent(content) {
|
|
|
1155
1195
|
});
|
|
1156
1196
|
break;
|
|
1157
1197
|
}
|
|
1198
|
+
if (contentParts.length === 0) return "";
|
|
1158
1199
|
return contentParts;
|
|
1159
1200
|
}
|
|
1160
1201
|
function createDocumentTextPart() {
|
|
1161
1202
|
return {
|
|
1162
1203
|
type: "text",
|
|
1163
|
-
text: "
|
|
1204
|
+
text: "PDF/document content is not supported by this Chat Completions upstream. Use the available text extracted from the document."
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
function createDocumentFilePart(block) {
|
|
1208
|
+
return {
|
|
1209
|
+
type: "file",
|
|
1210
|
+
file: {
|
|
1211
|
+
file_data: `data:${block.source.media_type};base64,${block.source.data}`,
|
|
1212
|
+
filename: block.title ?? "document.pdf"
|
|
1213
|
+
}
|
|
1164
1214
|
};
|
|
1165
1215
|
}
|
|
1166
1216
|
function translateAnthropicToolsToOpenAI(anthropicTools) {
|
|
@@ -1205,7 +1255,7 @@ function translateToAnthropic(response) {
|
|
|
1205
1255
|
let stopReason = response.choices[0]?.finish_reason ?? null;
|
|
1206
1256
|
for (const choice of response.choices) {
|
|
1207
1257
|
const textBlocks = getAnthropicTextBlocks(choice.message.content);
|
|
1208
|
-
const thinkBlocks = getAnthropicThinkBlocks(choice.message
|
|
1258
|
+
const thinkBlocks = getAnthropicThinkBlocks(getOpenAIReasoningText(choice.message), choice.message.reasoning_opaque);
|
|
1209
1259
|
const toolUseBlocks = getAnthropicToolUseBlocks(choice.message.tool_calls);
|
|
1210
1260
|
assistantContentBlocks.push(...thinkBlocks, ...textBlocks, ...toolUseBlocks);
|
|
1211
1261
|
if (choice.finish_reason === "tool_calls" || stopReason === "stop") stopReason = choice.finish_reason;
|
|
@@ -1218,12 +1268,24 @@ function translateToAnthropic(response) {
|
|
|
1218
1268
|
content: assistantContentBlocks,
|
|
1219
1269
|
stop_reason: mapOpenAIStopReasonToAnthropic(stopReason),
|
|
1220
1270
|
stop_sequence: null,
|
|
1221
|
-
usage:
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1271
|
+
usage: mapOpenAIChatCompletionUsage(response)
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
function mapOpenAIChatCompletionUsage(response) {
|
|
1275
|
+
const promptDetails = response.usage?.prompt_tokens_details;
|
|
1276
|
+
const promptTokens = response.usage?.prompt_tokens ?? 0;
|
|
1277
|
+
const cachedTokens = promptDetails?.cached_tokens ?? 0;
|
|
1278
|
+
const cacheCreationTokens = promptDetails?.cache_creation_input_tokens ?? 0;
|
|
1279
|
+
const usage = {
|
|
1280
|
+
input_tokens: Math.max(0, promptTokens - cachedTokens - cacheCreationTokens),
|
|
1281
|
+
output_tokens: response.usage?.completion_tokens ?? 0
|
|
1226
1282
|
};
|
|
1283
|
+
if (promptDetails?.cache_creation_input_tokens !== void 0) usage.cache_creation_input_tokens = cacheCreationTokens;
|
|
1284
|
+
if (promptDetails?.cached_tokens !== void 0) usage.cache_read_input_tokens = cachedTokens;
|
|
1285
|
+
return usage;
|
|
1286
|
+
}
|
|
1287
|
+
function getOpenAIReasoningText(message) {
|
|
1288
|
+
return message.reasoning_text ?? message.reasoning_content;
|
|
1227
1289
|
}
|
|
1228
1290
|
function getAnthropicTextBlocks(messageContent) {
|
|
1229
1291
|
if (typeof messageContent === "string" && messageContent.length > 0) return [{
|
|
@@ -1244,7 +1306,7 @@ function getAnthropicThinkBlocks(reasoningText, reasoningOpaque) {
|
|
|
1244
1306
|
}];
|
|
1245
1307
|
if (reasoningOpaque && reasoningOpaque.length > 0) return [{
|
|
1246
1308
|
type: "thinking",
|
|
1247
|
-
thinking: THINKING_TEXT,
|
|
1309
|
+
thinking: THINKING_TEXT$1,
|
|
1248
1310
|
signature: reasoningOpaque
|
|
1249
1311
|
}];
|
|
1250
1312
|
return [];
|
|
@@ -1258,7 +1320,6 @@ function getAnthropicToolUseBlocks(toolCalls) {
|
|
|
1258
1320
|
input: JSON.parse(toolCall.function.arguments)
|
|
1259
1321
|
}));
|
|
1260
1322
|
}
|
|
1261
|
-
|
|
1262
1323
|
//#endregion
|
|
1263
1324
|
//#region src/routes/admin-api/replay-translation.ts
|
|
1264
1325
|
function translateForReplay(input) {
|
|
@@ -1276,7 +1337,6 @@ function translateForReplay(input) {
|
|
|
1276
1337
|
if (upstreamEndpoint.includes("/responses")) return rawText;
|
|
1277
1338
|
return null;
|
|
1278
1339
|
}
|
|
1279
|
-
|
|
1280
1340
|
//#endregion
|
|
1281
1341
|
//#region src/routes/admin-api/replay.ts
|
|
1282
1342
|
const replayRoutes = new Hono();
|
|
@@ -1596,7 +1656,6 @@ function requireDevMode(c) {
|
|
|
1596
1656
|
} }, 403);
|
|
1597
1657
|
return null;
|
|
1598
1658
|
}
|
|
1599
|
-
|
|
1600
1659
|
//#endregion
|
|
1601
1660
|
//#region src/routes/admin-api/route.ts
|
|
1602
1661
|
const ADMIN_TOKEN = process.env.ADMIN_TOKEN?.trim() || void 0;
|
|
@@ -1676,7 +1735,8 @@ const CONFIG_KEYS = new Set([
|
|
|
1676
1735
|
"sessionAffinityRetentionDays",
|
|
1677
1736
|
"useMessagesApi",
|
|
1678
1737
|
"useResponsesApiWebSearch",
|
|
1679
|
-
"devMode"
|
|
1738
|
+
"devMode",
|
|
1739
|
+
"quotaRefresh"
|
|
1680
1740
|
]);
|
|
1681
1741
|
const REASONING_EFFORTS = new Set([
|
|
1682
1742
|
"none",
|
|
@@ -1837,7 +1897,7 @@ function applyProviderType(provider, value, field) {
|
|
|
1837
1897
|
const parsed = parseOptionalString(value.type, `${field}.type`);
|
|
1838
1898
|
if ("error" in parsed) return parsed.error;
|
|
1839
1899
|
if ("value" in parsed) {
|
|
1840
|
-
if (parsed.value !==
|
|
1900
|
+
if (parsed.value !== "anthropic") return `${field}.type must be "${PROVIDER_TYPE_ANTHROPIC}"`;
|
|
1841
1901
|
provider.type = PROVIDER_TYPE_ANTHROPIC;
|
|
1842
1902
|
}
|
|
1843
1903
|
}
|
|
@@ -2103,6 +2163,48 @@ function applyDevModeConfig(next, value) {
|
|
|
2103
2163
|
}
|
|
2104
2164
|
next.devMode = parsed.value;
|
|
2105
2165
|
}
|
|
2166
|
+
const QUOTA_REFRESH_KEYS = new Set([
|
|
2167
|
+
"enabled",
|
|
2168
|
+
"intervalMinutes",
|
|
2169
|
+
"startupDelaySeconds",
|
|
2170
|
+
"staggerMinSeconds",
|
|
2171
|
+
"staggerMaxSeconds"
|
|
2172
|
+
]);
|
|
2173
|
+
function parseQuotaRefreshConfig(value) {
|
|
2174
|
+
if (value === null || value === void 0) return { clear: true };
|
|
2175
|
+
if (!isPlainObject(value)) return { error: "quotaRefresh must be an object" };
|
|
2176
|
+
for (const key of Object.keys(value)) if (!QUOTA_REFRESH_KEYS.has(key)) return { error: `quotaRefresh.${key} is not supported` };
|
|
2177
|
+
const out = {};
|
|
2178
|
+
if (Object.hasOwn(value, "enabled")) {
|
|
2179
|
+
const parsed = parseOptionalBoolean(value.enabled, "quotaRefresh.enabled");
|
|
2180
|
+
if ("error" in parsed) return parsed;
|
|
2181
|
+
if ("value" in parsed) out.enabled = parsed.value;
|
|
2182
|
+
}
|
|
2183
|
+
for (const key of [
|
|
2184
|
+
"intervalMinutes",
|
|
2185
|
+
"startupDelaySeconds",
|
|
2186
|
+
"staggerMinSeconds",
|
|
2187
|
+
"staggerMaxSeconds"
|
|
2188
|
+
]) {
|
|
2189
|
+
if (!Object.hasOwn(value, key)) continue;
|
|
2190
|
+
const parsed = parseOptionalNonNegativeNumber(value[key], `quotaRefresh.${key}`);
|
|
2191
|
+
if ("error" in parsed) return parsed;
|
|
2192
|
+
if ("value" in parsed) out[key] = parsed.value;
|
|
2193
|
+
}
|
|
2194
|
+
return { value: out };
|
|
2195
|
+
}
|
|
2196
|
+
function applyQuotaRefreshConfig(next, value) {
|
|
2197
|
+
const parsed = parseQuotaRefreshConfig(value);
|
|
2198
|
+
if ("error" in parsed) return parsed.error;
|
|
2199
|
+
if ("clear" in parsed) {
|
|
2200
|
+
delete next.quotaRefresh;
|
|
2201
|
+
return;
|
|
2202
|
+
}
|
|
2203
|
+
next.quotaRefresh = next.quotaRefresh === void 0 ? parsed.value : {
|
|
2204
|
+
...next.quotaRefresh,
|
|
2205
|
+
...parsed.value
|
|
2206
|
+
};
|
|
2207
|
+
}
|
|
2106
2208
|
const CONFIG_PATCH_HANDLERS = {
|
|
2107
2209
|
auth: applyAuthConfig,
|
|
2108
2210
|
extraPrompts: applyExtraPrompts,
|
|
@@ -2124,7 +2226,8 @@ const CONFIG_PATCH_HANDLERS = {
|
|
|
2124
2226
|
sessionAffinityRetentionDays: (next, value) => applyOptionalNumber(next, "sessionAffinityRetentionDays", value),
|
|
2125
2227
|
useMessagesApi: (next, value) => applyOptionalBoolean(next, "useMessagesApi", value),
|
|
2126
2228
|
useResponsesApiWebSearch: (next, value) => applyOptionalBoolean(next, "useResponsesApiWebSearch", value),
|
|
2127
|
-
devMode: applyDevModeConfig
|
|
2229
|
+
devMode: applyDevModeConfig,
|
|
2230
|
+
quotaRefresh: applyQuotaRefreshConfig
|
|
2128
2231
|
};
|
|
2129
2232
|
function applyConfigPatch(base, input) {
|
|
2130
2233
|
const next = { ...base };
|
|
@@ -2190,6 +2293,7 @@ adminApiRoutes.post("/config", async (c) => {
|
|
|
2190
2293
|
const merged = mergeConfigWithDefaults();
|
|
2191
2294
|
accountsManager.setAccountAffinityEnabled(isAccountAffinityEnabled());
|
|
2192
2295
|
accountsManager.setModelsRefreshIntervalMs(getModelRefreshIntervalMs());
|
|
2296
|
+
updateQuotaRefreshSchedulerFromConfig();
|
|
2193
2297
|
applySharedSessionAffinityRetention();
|
|
2194
2298
|
return c.json({
|
|
2195
2299
|
...merged,
|
|
@@ -2510,7 +2614,7 @@ adminApiRoutes.post("/accounts/:id/reauth", async (c) => {
|
|
|
2510
2614
|
const { oauthApp } = getCurrentIdentityEnvironment();
|
|
2511
2615
|
const resolvedEnterpriseDomain = (await getAccountClientIdentityByLoginAndApp(accountId, oauthApp))?.enterpriseDomain;
|
|
2512
2616
|
let enterpriseDomain;
|
|
2513
|
-
if (resolvedEnterpriseDomain && resolvedEnterpriseDomain !==
|
|
2617
|
+
if (resolvedEnterpriseDomain && resolvedEnterpriseDomain !== "public") enterpriseDomain = resolvedEnterpriseDomain;
|
|
2514
2618
|
const result = await authSessionManager.startAuth({
|
|
2515
2619
|
accountType: account.accountType,
|
|
2516
2620
|
enterpriseDomain,
|
|
@@ -2569,14 +2673,14 @@ adminApiRoutes.get("/stats/premium-daily", (c) => {
|
|
|
2569
2673
|
message: "Hourly granularity is only supported for ranges up to 35 days.",
|
|
2570
2674
|
type: "bad_request"
|
|
2571
2675
|
});
|
|
2572
|
-
const result
|
|
2676
|
+
const result = statsStore.getHourlyPremiumStats({
|
|
2573
2677
|
fromMs,
|
|
2574
2678
|
toMs,
|
|
2575
2679
|
accountId
|
|
2576
2680
|
});
|
|
2577
2681
|
return c.json({
|
|
2578
|
-
daily: result
|
|
2579
|
-
by_account: result
|
|
2682
|
+
daily: result.daily,
|
|
2683
|
+
by_account: result.byAccount,
|
|
2580
2684
|
range: {
|
|
2581
2685
|
from: resolvedFrom,
|
|
2582
2686
|
to: resolvedTo,
|
|
@@ -2600,7 +2704,6 @@ adminApiRoutes.get("/stats/premium-daily", (c) => {
|
|
|
2600
2704
|
});
|
|
2601
2705
|
});
|
|
2602
2706
|
adminApiRoutes.route("/", replayRoutes);
|
|
2603
|
-
|
|
2604
2707
|
//#endregion
|
|
2605
2708
|
//#region src/routes/admin/route.ts
|
|
2606
2709
|
function resolveAdminDistDir() {
|
|
@@ -3239,13 +3342,11 @@ adminRoutes.get("*", async (c) => {
|
|
|
3239
3342
|
return c.html(html);
|
|
3240
3343
|
}
|
|
3241
3344
|
});
|
|
3242
|
-
|
|
3243
3345
|
//#endregion
|
|
3244
3346
|
//#region src/lib/approval.ts
|
|
3245
3347
|
const awaitApproval = async () => {
|
|
3246
3348
|
if (!await consola.prompt(`Accept incoming request?`, { type: "confirm" })) throw new HTTPError("Request rejected", Response.json({ message: "Request rejected" }, { status: 403 }));
|
|
3247
3349
|
};
|
|
3248
|
-
|
|
3249
3350
|
//#endregion
|
|
3250
3351
|
//#region src/lib/handler-utils.ts
|
|
3251
3352
|
function truncate(value, max = 2e3) {
|
|
@@ -3354,7 +3455,57 @@ function getUserVisibleErrorMessage(details) {
|
|
|
3354
3455
|
function shouldMarkAccountFailed(details) {
|
|
3355
3456
|
return details.unauthorized && !details.ownershipMismatch && details.upstreamErrorMessageReadFailed !== true;
|
|
3356
3457
|
}
|
|
3357
|
-
|
|
3458
|
+
//#endregion
|
|
3459
|
+
//#region src/lib/process-cleanup.ts
|
|
3460
|
+
const cleanupHandlers = /* @__PURE__ */ new Set();
|
|
3461
|
+
let cleanupPromise = null;
|
|
3462
|
+
let cleanupState = "idle";
|
|
3463
|
+
let runtimeInitialized$1 = false;
|
|
3464
|
+
function initializeProcessCleanupRuntime() {
|
|
3465
|
+
if (runtimeInitialized$1) return;
|
|
3466
|
+
runtimeInitialized$1 = true;
|
|
3467
|
+
process.once("beforeExit", () => {
|
|
3468
|
+
runProcessCleanups();
|
|
3469
|
+
});
|
|
3470
|
+
process.once("exit", runProcessCleanupsSync);
|
|
3471
|
+
process.once("SIGINT", () => {
|
|
3472
|
+
shutdownProcess(0);
|
|
3473
|
+
});
|
|
3474
|
+
process.once("SIGTERM", () => {
|
|
3475
|
+
shutdownProcess(0);
|
|
3476
|
+
});
|
|
3477
|
+
}
|
|
3478
|
+
function runProcessCleanupsSync() {
|
|
3479
|
+
if (cleanupState !== "idle") return;
|
|
3480
|
+
cleanupState = "done";
|
|
3481
|
+
for (const handler of Array.from(cleanupHandlers)) try {
|
|
3482
|
+
handler();
|
|
3483
|
+
} catch {}
|
|
3484
|
+
}
|
|
3485
|
+
async function runProcessCleanups() {
|
|
3486
|
+
if (cleanupPromise) return cleanupPromise;
|
|
3487
|
+
if (cleanupState === "done") return;
|
|
3488
|
+
cleanupState = "running";
|
|
3489
|
+
cleanupPromise = (async () => {
|
|
3490
|
+
for (const handler of Array.from(cleanupHandlers)) await handler();
|
|
3491
|
+
cleanupState = "done";
|
|
3492
|
+
})();
|
|
3493
|
+
return cleanupPromise;
|
|
3494
|
+
}
|
|
3495
|
+
async function shutdownProcess(exitCode) {
|
|
3496
|
+
try {
|
|
3497
|
+
await runProcessCleanups();
|
|
3498
|
+
} finally {
|
|
3499
|
+
process.exit(exitCode);
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3502
|
+
function registerProcessCleanup(handler) {
|
|
3503
|
+
initializeProcessCleanupRuntime();
|
|
3504
|
+
cleanupHandlers.add(handler);
|
|
3505
|
+
return () => {
|
|
3506
|
+
cleanupHandlers.delete(handler);
|
|
3507
|
+
};
|
|
3508
|
+
}
|
|
3358
3509
|
//#endregion
|
|
3359
3510
|
//#region src/lib/logger.ts
|
|
3360
3511
|
const LOG_RETENTION_MS = 10080 * 60 * 1e3;
|
|
@@ -3374,9 +3525,6 @@ const logBuffers = /* @__PURE__ */ new Map();
|
|
|
3374
3525
|
let runtimeInitialized = false;
|
|
3375
3526
|
let flushInterval;
|
|
3376
3527
|
let cleanupInterval;
|
|
3377
|
-
let exitHandler;
|
|
3378
|
-
let sigintHandler;
|
|
3379
|
-
let sigtermHandler;
|
|
3380
3528
|
const ensureLogDirectory = () => {
|
|
3381
3529
|
if (!fs$1.existsSync(logDir)) fs$1.mkdirSync(logDir, { recursive: true });
|
|
3382
3530
|
};
|
|
@@ -3454,18 +3602,7 @@ const initializeLoggerRuntime = () => {
|
|
|
3454
3602
|
maybeUnref(flushInterval);
|
|
3455
3603
|
cleanupInterval = setInterval(cleanupOldLogs, CLEANUP_INTERVAL_MS);
|
|
3456
3604
|
maybeUnref(cleanupInterval);
|
|
3457
|
-
|
|
3458
|
-
sigintHandler = () => {
|
|
3459
|
-
cleanup();
|
|
3460
|
-
process.exit(0);
|
|
3461
|
-
};
|
|
3462
|
-
sigtermHandler = () => {
|
|
3463
|
-
cleanup();
|
|
3464
|
-
process.exit(0);
|
|
3465
|
-
};
|
|
3466
|
-
process.once("exit", exitHandler);
|
|
3467
|
-
process.once("SIGINT", sigintHandler);
|
|
3468
|
-
process.once("SIGTERM", sigtermHandler);
|
|
3605
|
+
registerProcessCleanup(cleanup);
|
|
3469
3606
|
};
|
|
3470
3607
|
const getLogStream = (filePath) => {
|
|
3471
3608
|
initializeLoggerRuntime();
|
|
@@ -3502,15 +3639,15 @@ const shouldWriteFileLog = (type, logLevel = resolveLogLevel()) => {
|
|
|
3502
3639
|
};
|
|
3503
3640
|
const resolveLogLevel = () => testLogLevelOverride ?? getLogLevel();
|
|
3504
3641
|
const isDebugFileLoggingEnabled = () => resolveLogLevel() === "debug";
|
|
3505
|
-
const debugLazy = (logger
|
|
3642
|
+
const debugLazy = (logger, factory) => {
|
|
3506
3643
|
if (!isDebugFileLoggingEnabled()) return;
|
|
3507
|
-
logger
|
|
3644
|
+
logger.debug(...factory());
|
|
3508
3645
|
};
|
|
3509
|
-
const debugJson = (logger
|
|
3510
|
-
debugLazy(logger
|
|
3646
|
+
const debugJson = (logger, label, value) => {
|
|
3647
|
+
debugLazy(logger, () => [label, JSON.stringify(value)]);
|
|
3511
3648
|
};
|
|
3512
|
-
const debugJsonTail = (logger
|
|
3513
|
-
debugLazy(logger
|
|
3649
|
+
const debugJsonTail = (logger, label, { value, tailLength = 400 }) => {
|
|
3650
|
+
debugLazy(logger, () => [label, JSON.stringify(value).slice(-tailLength)]);
|
|
3514
3651
|
};
|
|
3515
3652
|
const getConsolaLevel = () => {
|
|
3516
3653
|
const logLevel = resolveLogLevel();
|
|
@@ -3543,33 +3680,31 @@ const createHandlerLogger = (name) => {
|
|
|
3543
3680
|
} });
|
|
3544
3681
|
return instance;
|
|
3545
3682
|
};
|
|
3546
|
-
|
|
3547
3683
|
//#endregion
|
|
3548
3684
|
//#region src/lib/rate-limit.ts
|
|
3549
|
-
async function checkRateLimit(state
|
|
3550
|
-
if (state
|
|
3685
|
+
async function checkRateLimit(state) {
|
|
3686
|
+
if (state.rateLimitSeconds === void 0) return;
|
|
3551
3687
|
const now = Date.now();
|
|
3552
|
-
if (!state
|
|
3553
|
-
state
|
|
3688
|
+
if (!state.lastRequestTimestamp) {
|
|
3689
|
+
state.lastRequestTimestamp = now;
|
|
3554
3690
|
return;
|
|
3555
3691
|
}
|
|
3556
|
-
const elapsedSeconds = (now - state
|
|
3557
|
-
if (elapsedSeconds > state
|
|
3558
|
-
state
|
|
3692
|
+
const elapsedSeconds = (now - state.lastRequestTimestamp) / 1e3;
|
|
3693
|
+
if (elapsedSeconds > state.rateLimitSeconds) {
|
|
3694
|
+
state.lastRequestTimestamp = now;
|
|
3559
3695
|
return;
|
|
3560
3696
|
}
|
|
3561
|
-
const waitTimeSeconds = Math.ceil(state
|
|
3562
|
-
if (!state
|
|
3697
|
+
const waitTimeSeconds = Math.ceil(state.rateLimitSeconds - elapsedSeconds);
|
|
3698
|
+
if (!state.rateLimitWait) {
|
|
3563
3699
|
consola.warn(`Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`);
|
|
3564
3700
|
throw new HTTPError("Rate limit exceeded", Response.json({ message: "Rate limit exceeded" }, { status: 429 }));
|
|
3565
3701
|
}
|
|
3566
3702
|
const waitTimeMs = waitTimeSeconds * 1e3;
|
|
3567
3703
|
consola.warn(`Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`);
|
|
3568
3704
|
await sleep(waitTimeMs);
|
|
3569
|
-
state
|
|
3705
|
+
state.lastRequestTimestamp = now;
|
|
3570
3706
|
consola.info("Rate limit wait completed, proceeding with request");
|
|
3571
3707
|
}
|
|
3572
|
-
|
|
3573
3708
|
//#endregion
|
|
3574
3709
|
//#region src/routes/chat-completions/support.ts
|
|
3575
3710
|
const CHAT_COMPLETIONS_ENDPOINT$1 = "/chat/completions";
|
|
@@ -3579,13 +3714,13 @@ function buildRequestContext$1(c) {
|
|
|
3579
3714
|
const requestId = randomUUID();
|
|
3580
3715
|
const startedAtMs = Date.now();
|
|
3581
3716
|
const method = c.req.raw.method;
|
|
3582
|
-
const path
|
|
3717
|
+
const path = new URL(c.req.url, "http://local").pathname;
|
|
3583
3718
|
const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
|
|
3584
3719
|
return {
|
|
3585
3720
|
requestId,
|
|
3586
3721
|
startedAtMs,
|
|
3587
3722
|
method,
|
|
3588
|
-
path
|
|
3723
|
+
path,
|
|
3589
3724
|
clientIp,
|
|
3590
3725
|
clientIpSource,
|
|
3591
3726
|
userAgent: c.req.header("user-agent") ?? void 0
|
|
@@ -3678,7 +3813,6 @@ function selectionFailureResponse$2(c, params) {
|
|
|
3678
3813
|
type: "rate_limit_error"
|
|
3679
3814
|
} }, 429);
|
|
3680
3815
|
}
|
|
3681
|
-
|
|
3682
3816
|
//#endregion
|
|
3683
3817
|
//#region src/routes/chat-completions/handler.ts
|
|
3684
3818
|
const logger$6 = createHandlerLogger("chat-completions-handler");
|
|
@@ -3746,7 +3880,7 @@ async function handleCompletion$1(c) {
|
|
|
3746
3880
|
request.selectionReason = selection.selectionReason;
|
|
3747
3881
|
const premiumRemainingBefore = account.premiumRemaining;
|
|
3748
3882
|
const premiumUnlimitedBefore = account.unlimited;
|
|
3749
|
-
if (selectedModel.id ===
|
|
3883
|
+
if (selectedModel.id === "gpt-5.4") {
|
|
3750
3884
|
await accountsManager.finalizeQuota(account, reservation);
|
|
3751
3885
|
recordUnsupportedChatCompletionsModel(store, {
|
|
3752
3886
|
request,
|
|
@@ -4136,7 +4270,6 @@ async function handleNonStreamingRequest(params) {
|
|
|
4136
4270
|
}
|
|
4137
4271
|
}
|
|
4138
4272
|
const isNonStreaming$1 = (response) => Object.hasOwn(response, "choices");
|
|
4139
|
-
|
|
4140
4273
|
//#endregion
|
|
4141
4274
|
//#region src/routes/chat-completions/route.ts
|
|
4142
4275
|
const completionRoutes = new Hono();
|
|
@@ -4147,7 +4280,6 @@ completionRoutes.post("/", async (c) => {
|
|
|
4147
4280
|
return await forwardError(c, error);
|
|
4148
4281
|
}
|
|
4149
4282
|
});
|
|
4150
|
-
|
|
4151
4283
|
//#endregion
|
|
4152
4284
|
//#region src/services/copilot/create-embeddings.ts
|
|
4153
4285
|
const createEmbeddings = async (payload, account, options) => {
|
|
@@ -4167,7 +4299,6 @@ const createEmbeddings = async (payload, account, options) => {
|
|
|
4167
4299
|
if (!response.ok) throw new HTTPError("Failed to create embeddings", response);
|
|
4168
4300
|
return await response.json();
|
|
4169
4301
|
};
|
|
4170
|
-
|
|
4171
4302
|
//#endregion
|
|
4172
4303
|
//#region src/routes/embeddings/route.ts
|
|
4173
4304
|
const embeddingRoutes = new Hono();
|
|
@@ -4178,13 +4309,13 @@ embeddingRoutes.post("/", async (c) => {
|
|
|
4178
4309
|
const requestId = randomUUID();
|
|
4179
4310
|
const startedAtMs = Date.now();
|
|
4180
4311
|
const method = c.req.raw.method;
|
|
4181
|
-
const path
|
|
4312
|
+
const path = new URL(c.req.url, "http://local").pathname;
|
|
4182
4313
|
const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
|
|
4183
4314
|
const ctx = {
|
|
4184
4315
|
requestId,
|
|
4185
4316
|
startedAtMs,
|
|
4186
4317
|
method,
|
|
4187
|
-
path
|
|
4318
|
+
path,
|
|
4188
4319
|
clientIp,
|
|
4189
4320
|
clientIpSource,
|
|
4190
4321
|
userAgent: c.req.header("user-agent") ?? void 0
|
|
@@ -4318,9 +4449,99 @@ async function runEmbeddingsWithAccount({ c, store, ctx, payload, clientModel, s
|
|
|
4318
4449
|
});
|
|
4319
4450
|
}
|
|
4320
4451
|
}
|
|
4321
|
-
|
|
4452
|
+
//#endregion
|
|
4453
|
+
//#region src/lib/provider-model.ts
|
|
4454
|
+
const parseProviderModelAlias = (model) => {
|
|
4455
|
+
const separatorIndex = model.indexOf("/");
|
|
4456
|
+
if (separatorIndex <= 0 || separatorIndex === model.length - 1) return null;
|
|
4457
|
+
const provider = model.slice(0, separatorIndex).trim();
|
|
4458
|
+
const providerModel = model.slice(separatorIndex + 1).trim();
|
|
4459
|
+
if (!provider || !providerModel) return null;
|
|
4460
|
+
return {
|
|
4461
|
+
model: providerModel,
|
|
4462
|
+
provider
|
|
4463
|
+
};
|
|
4464
|
+
};
|
|
4465
|
+
const createFallbackModel = (modelId) => ({
|
|
4466
|
+
capabilities: {
|
|
4467
|
+
family: "provider",
|
|
4468
|
+
limits: {},
|
|
4469
|
+
object: "model_capabilities",
|
|
4470
|
+
supports: {},
|
|
4471
|
+
tokenizer: "o200k_base",
|
|
4472
|
+
type: "chat"
|
|
4473
|
+
},
|
|
4474
|
+
id: modelId,
|
|
4475
|
+
model_picker_enabled: false,
|
|
4476
|
+
name: modelId,
|
|
4477
|
+
object: "model",
|
|
4478
|
+
preview: false,
|
|
4479
|
+
vendor: "provider",
|
|
4480
|
+
version: "unknown"
|
|
4481
|
+
});
|
|
4482
|
+
//#endregion
|
|
4483
|
+
//#region src/routes/provider/messages/count-tokens-handler.ts
|
|
4484
|
+
const logger$5 = createHandlerLogger("provider-count-tokens-handler");
|
|
4485
|
+
const resolveProviderConfig$2 = (c, provider) => {
|
|
4486
|
+
return (c.get("providerConfigResolver") ?? getProviderConfig)(provider);
|
|
4487
|
+
};
|
|
4488
|
+
async function handleProviderCountTokens(c) {
|
|
4489
|
+
const provider = c.req.param("provider");
|
|
4490
|
+
return await handleProviderCountTokensForProvider(c, {
|
|
4491
|
+
payload: await c.req.json(),
|
|
4492
|
+
provider
|
|
4493
|
+
});
|
|
4494
|
+
}
|
|
4495
|
+
async function handleProviderCountTokensForProvider(c, options) {
|
|
4496
|
+
const { payload: anthropicPayload, provider } = options;
|
|
4497
|
+
const providerConfig = resolveProviderConfig$2(c, provider);
|
|
4498
|
+
if (!providerConfig) return c.json({ error: {
|
|
4499
|
+
message: `Provider '${provider}' not found or disabled`,
|
|
4500
|
+
type: "invalid_request_error"
|
|
4501
|
+
} }, 404);
|
|
4502
|
+
if (typeof anthropicPayload.model !== "string" || !Array.isArray(anthropicPayload.messages)) return c.json({ error: {
|
|
4503
|
+
message: "Invalid Anthropic messages count_tokens payload",
|
|
4504
|
+
type: "invalid_request_error"
|
|
4505
|
+
} }, 400);
|
|
4506
|
+
const modelId = anthropicPayload.model.trim();
|
|
4507
|
+
const modelConfig = providerConfig.models?.[modelId];
|
|
4508
|
+
const translationOptions = providerConfig.type === "openai-compatible" ? {
|
|
4509
|
+
supportPdf: modelConfig?.supportPdf,
|
|
4510
|
+
toolContentSupportType: modelConfig?.toolContentSupportType ?? []
|
|
4511
|
+
} : void 0;
|
|
4512
|
+
try {
|
|
4513
|
+
const tokenCount = await getTokenCount(translateToOpenAI(anthropicPayload, translationOptions), findEndpointModel(modelId) ?? createFallbackModel(modelId));
|
|
4514
|
+
const finalTokenCount = tokenCount.input + tokenCount.output;
|
|
4515
|
+
logger$5.debug("provider.count_tokens.success", {
|
|
4516
|
+
provider,
|
|
4517
|
+
model: anthropicPayload.model,
|
|
4518
|
+
input_tokens: finalTokenCount
|
|
4519
|
+
});
|
|
4520
|
+
return c.json({ input_tokens: finalTokenCount });
|
|
4521
|
+
} catch (error) {
|
|
4522
|
+
logger$5.error("provider.count_tokens.error", {
|
|
4523
|
+
provider,
|
|
4524
|
+
error
|
|
4525
|
+
});
|
|
4526
|
+
return c.json({ error: {
|
|
4527
|
+
message: "Failed to count provider tokens",
|
|
4528
|
+
type: "internal_server_error"
|
|
4529
|
+
} }, 500);
|
|
4530
|
+
}
|
|
4531
|
+
}
|
|
4322
4532
|
//#endregion
|
|
4323
4533
|
//#region src/routes/messages/count-tokens-handler.ts
|
|
4534
|
+
const resolveCountTokensModel = (modelId, findModel = findEndpointModel) => {
|
|
4535
|
+
const selectedModel = findModel(modelId);
|
|
4536
|
+
if (selectedModel) return {
|
|
4537
|
+
fallback: false,
|
|
4538
|
+
model: selectedModel
|
|
4539
|
+
};
|
|
4540
|
+
return {
|
|
4541
|
+
fallback: true,
|
|
4542
|
+
model: createFallbackModel(modelId.trim())
|
|
4543
|
+
};
|
|
4544
|
+
};
|
|
4324
4545
|
/**
|
|
4325
4546
|
* Forwards token counting to Anthropic's real /v1/messages/count_tokens endpoint.
|
|
4326
4547
|
* Returns the result on success, or null to fall through to estimation.
|
|
@@ -4359,43 +4580,44 @@ async function countTokensViaAnthropic(c, payload) {
|
|
|
4359
4580
|
* endpoint for accurate counts. Otherwise falls back to GPT tokenizer estimation.
|
|
4360
4581
|
*/
|
|
4361
4582
|
async function handleCountTokens(c) {
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4583
|
+
const anthropicPayload = await c.req.json();
|
|
4584
|
+
const providerModelAlias = parseProviderModelAlias(anthropicPayload.model);
|
|
4585
|
+
if (providerModelAlias) {
|
|
4586
|
+
anthropicPayload.model = providerModelAlias.model;
|
|
4587
|
+
return await handleProviderCountTokensForProvider(c, {
|
|
4588
|
+
payload: anthropicPayload,
|
|
4589
|
+
provider: providerModelAlias.provider
|
|
4590
|
+
});
|
|
4591
|
+
}
|
|
4592
|
+
const anthropicResult = await countTokensViaAnthropic(c, anthropicPayload);
|
|
4593
|
+
if (anthropicResult) return anthropicResult;
|
|
4594
|
+
const anthropicBeta = c.req.header("anthropic-beta");
|
|
4595
|
+
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
4596
|
+
const requestedModel = anthropicPayload.model;
|
|
4597
|
+
const resolve = resolveCountTokensModel(requestedModel);
|
|
4598
|
+
const selectedModel = resolve.model;
|
|
4599
|
+
anthropicPayload.model = selectedModel.id;
|
|
4600
|
+
if (resolve.fallback) consola.warn(`Model '${requestedModel}' not found, using o200k_base fallback tokenizer`);
|
|
4601
|
+
const tokenCount = await getTokenCount(openAIPayload, selectedModel);
|
|
4602
|
+
if (anthropicPayload.tools && anthropicPayload.tools.length > 0) {
|
|
4603
|
+
let addToolSystemPromptCount = false;
|
|
4604
|
+
if (anthropicBeta) {
|
|
4605
|
+
const toolsLength = anthropicPayload.tools.length;
|
|
4606
|
+
addToolSystemPromptCount = !anthropicPayload.tools.some((tool) => tool.name.startsWith("mcp__") || tool.name === "Skill" && toolsLength === 1);
|
|
4373
4607
|
}
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
if (anthropicBeta) {
|
|
4378
|
-
const toolsLength = anthropicPayload.tools.length;
|
|
4379
|
-
addToolSystemPromptCount = !anthropicPayload.tools.some((tool) => tool.name.startsWith("mcp__") || tool.name === "Skill" && toolsLength === 1);
|
|
4380
|
-
}
|
|
4381
|
-
if (addToolSystemPromptCount) {
|
|
4382
|
-
if (anthropicPayload.model.startsWith("claude")) tokenCount.input = tokenCount.input + 346;
|
|
4383
|
-
else if (anthropicPayload.model.startsWith("grok")) tokenCount.input = tokenCount.input + 120;
|
|
4384
|
-
}
|
|
4608
|
+
if (addToolSystemPromptCount) {
|
|
4609
|
+
if (anthropicPayload.model.startsWith("claude")) tokenCount.input = tokenCount.input + 346;
|
|
4610
|
+
else if (anthropicPayload.model.startsWith("grok")) tokenCount.input = tokenCount.input + 120;
|
|
4385
4611
|
}
|
|
4386
|
-
let finalTokenCount = tokenCount.input + tokenCount.output;
|
|
4387
|
-
if (anthropicPayload.model.startsWith("claude")) finalTokenCount = Math.round(finalTokenCount * getClaudeTokenMultiplier());
|
|
4388
|
-
consola.info("Token count:", finalTokenCount);
|
|
4389
|
-
return c.json({ input_tokens: finalTokenCount });
|
|
4390
|
-
} catch (error) {
|
|
4391
|
-
consola.error("Error counting tokens:", error);
|
|
4392
|
-
return c.json({ input_tokens: 1 });
|
|
4393
4612
|
}
|
|
4613
|
+
let finalTokenCount = tokenCount.input + tokenCount.output;
|
|
4614
|
+
if (anthropicPayload.model.startsWith("claude")) finalTokenCount = Math.round(finalTokenCount * getClaudeTokenMultiplier());
|
|
4615
|
+
consola.info("Token count:", finalTokenCount);
|
|
4616
|
+
return c.json({ input_tokens: finalTokenCount });
|
|
4394
4617
|
}
|
|
4395
|
-
|
|
4396
4618
|
//#endregion
|
|
4397
4619
|
//#region src/services/copilot/create-responses.ts
|
|
4398
|
-
const createResponses = async (payload, { vision, initiator, upstreamRequestId, subagentMarker, sessionId, compactType, requestId }, account) => {
|
|
4620
|
+
const createResponses = async (payload, { vision, initiator, upstreamRequestId, subagentMarker, sessionId, compactType, requestId, fetchImpl }, account) => {
|
|
4399
4621
|
const ctx = account ?? accountFromState();
|
|
4400
4622
|
if (!ctx.copilotToken) throw new Error("Copilot token not found");
|
|
4401
4623
|
const effectiveInitiator = resolveEffectiveInitiator(initiator, {
|
|
@@ -4416,7 +4638,8 @@ const createResponses = async (payload, { vision, initiator, upstreamRequestId,
|
|
|
4416
4638
|
body: JSON.stringify(payload)
|
|
4417
4639
|
}, {
|
|
4418
4640
|
requestId,
|
|
4419
|
-
callSite: "responses"
|
|
4641
|
+
callSite: "responses",
|
|
4642
|
+
fetchImpl
|
|
4420
4643
|
});
|
|
4421
4644
|
logCopilotRateLimits(response.headers);
|
|
4422
4645
|
if (!response.ok) {
|
|
@@ -4426,13 +4649,12 @@ const createResponses = async (payload, { vision, initiator, upstreamRequestId,
|
|
|
4426
4649
|
if (payload.stream) return events(response);
|
|
4427
4650
|
return await response.json();
|
|
4428
4651
|
};
|
|
4429
|
-
|
|
4430
4652
|
//#endregion
|
|
4431
4653
|
//#region src/routes/messages/responses-translation.ts
|
|
4432
4654
|
const MESSAGE_TYPE = "message";
|
|
4433
4655
|
const COMPACTION_SIGNATURE_PREFIX = "cm1#";
|
|
4434
4656
|
const COMPACTION_SIGNATURE_SEPARATOR = "@";
|
|
4435
|
-
const THINKING_TEXT
|
|
4657
|
+
const THINKING_TEXT = "Thinking...";
|
|
4436
4658
|
const translateAnthropicMessagesToResponsesPayload = (payload, modelOverride) => {
|
|
4437
4659
|
const model = modelOverride ?? payload.model;
|
|
4438
4660
|
const input = [];
|
|
@@ -4598,8 +4820,8 @@ const createFileContent = (block) => ({
|
|
|
4598
4820
|
filename: block.title ?? "document.pdf"
|
|
4599
4821
|
});
|
|
4600
4822
|
const createReasoningContent = (block) => {
|
|
4601
|
-
const { encryptedContent, id } = parseReasoningSignature(block.signature);
|
|
4602
|
-
const thinking = block.thinking ===
|
|
4823
|
+
const { encryptedContent, id } = parseReasoningSignature$1(block.signature);
|
|
4824
|
+
const thinking = block.thinking === "Thinking..." ? "" : block.thinking;
|
|
4603
4825
|
return {
|
|
4604
4826
|
id,
|
|
4605
4827
|
type: "reasoning",
|
|
@@ -4619,7 +4841,7 @@ const createCompactionContent = (block) => {
|
|
|
4619
4841
|
encrypted_content: compaction.encrypted_content
|
|
4620
4842
|
};
|
|
4621
4843
|
};
|
|
4622
|
-
const parseReasoningSignature = (signature) => {
|
|
4844
|
+
const parseReasoningSignature$1 = (signature) => {
|
|
4623
4845
|
const splitIndex = signature.lastIndexOf("@");
|
|
4624
4846
|
if (splitIndex <= 0 || splitIndex === signature.length - 1) return {
|
|
4625
4847
|
encryptedContent: signature,
|
|
@@ -4765,7 +4987,7 @@ const extractReasoningText = (item) => {
|
|
|
4765
4987
|
continue;
|
|
4766
4988
|
}
|
|
4767
4989
|
};
|
|
4768
|
-
if (!item.summary || item.summary.length === 0) return THINKING_TEXT
|
|
4990
|
+
if (!item.summary || item.summary.length === 0) return THINKING_TEXT;
|
|
4769
4991
|
collectFromBlocks(item.summary);
|
|
4770
4992
|
return segments.join("").trim();
|
|
4771
4993
|
};
|
|
@@ -4784,7 +5006,7 @@ const createCompactionThinkingBlock = (item) => {
|
|
|
4784
5006
|
if (!item.id || !item.encrypted_content) return null;
|
|
4785
5007
|
return {
|
|
4786
5008
|
type: "thinking",
|
|
4787
|
-
thinking: THINKING_TEXT
|
|
5009
|
+
thinking: THINKING_TEXT,
|
|
4788
5010
|
signature: encodeCompactionCarrierSignature({
|
|
4789
5011
|
id: item.id,
|
|
4790
5012
|
encrypted_content: item.encrypted_content
|
|
@@ -4859,107 +5081,969 @@ const convertToolResultContent = (content) => {
|
|
|
4859
5081
|
}
|
|
4860
5082
|
return "";
|
|
4861
5083
|
};
|
|
4862
|
-
|
|
4863
5084
|
//#endregion
|
|
4864
|
-
//#region src/routes/messages/responses-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
const
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
if (char === "\r" || char === "\n" || char === " ") {
|
|
4876
|
-
count += 1;
|
|
4877
|
-
if (count > MAX_CONSECUTIVE_FUNCTION_CALL_WHITESPACE) return {
|
|
4878
|
-
nextCount: count,
|
|
4879
|
-
exceeded: true
|
|
4880
|
-
};
|
|
4881
|
-
continue;
|
|
5085
|
+
//#region src/routes/messages/responses-item-ownership.ts
|
|
5086
|
+
function buildResponsesItemOwnershipKey(kind, value) {
|
|
5087
|
+
return `responses-item-owner:${kind}:${createHash("sha256").update(value).digest("hex")}`;
|
|
5088
|
+
}
|
|
5089
|
+
function extractAnthropicResponsesItemOwnerKeys(payload) {
|
|
5090
|
+
const keys = [];
|
|
5091
|
+
for (const message of payload.messages) {
|
|
5092
|
+
if (message.role !== "assistant" || !Array.isArray(message.content)) continue;
|
|
5093
|
+
for (const block of message.content) {
|
|
5094
|
+
if (block.type !== "thinking" || !block.signature) continue;
|
|
5095
|
+
addSignatureOwnerKeys(keys, block.signature);
|
|
4882
5096
|
}
|
|
4883
|
-
if (char !== " ") count = 0;
|
|
4884
5097
|
}
|
|
5098
|
+
return unique(keys);
|
|
5099
|
+
}
|
|
5100
|
+
function extractResponsesResultOwnerKeys(result) {
|
|
5101
|
+
const keys = [];
|
|
5102
|
+
for (const item of result.output) addOutputItemOwnerKeys(keys, item);
|
|
5103
|
+
return unique(keys);
|
|
5104
|
+
}
|
|
5105
|
+
function extractResponsesStreamEventOwnerKeys(event) {
|
|
5106
|
+
if (event.type === "response.output_item.done") {
|
|
5107
|
+
const keys = [];
|
|
5108
|
+
addOutputItemOwnerKeys(keys, event.item);
|
|
5109
|
+
return unique(keys);
|
|
5110
|
+
}
|
|
5111
|
+
if (event.type === "response.completed" || event.type === "response.incomplete") return extractResponsesResultOwnerKeys(event.response);
|
|
5112
|
+
return [];
|
|
5113
|
+
}
|
|
5114
|
+
function addSignatureOwnerKeys(keys, signature) {
|
|
5115
|
+
if (signature.startsWith("cm1#")) {
|
|
5116
|
+
const compaction = decodeCompactionCarrierSignature(signature);
|
|
5117
|
+
if (compaction) addRawOwnerKeys(keys, compaction.id, compaction.encrypted_content);
|
|
5118
|
+
return;
|
|
5119
|
+
}
|
|
5120
|
+
const reasoning = parseReasoningSignature(signature);
|
|
5121
|
+
if (!reasoning) return;
|
|
5122
|
+
addRawOwnerKeys(keys, reasoning.id, reasoning.encryptedContent);
|
|
5123
|
+
}
|
|
5124
|
+
function parseReasoningSignature(signature) {
|
|
5125
|
+
const splitIndex = signature.lastIndexOf("@");
|
|
5126
|
+
if (splitIndex <= 0 || splitIndex === signature.length - 1) return;
|
|
4885
5127
|
return {
|
|
4886
|
-
|
|
4887
|
-
|
|
5128
|
+
encryptedContent: signature.slice(0, splitIndex),
|
|
5129
|
+
id: signature.slice(splitIndex + 1)
|
|
4888
5130
|
};
|
|
4889
|
-
}
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
5131
|
+
}
|
|
5132
|
+
function addOutputItemOwnerKeys(keys, item) {
|
|
5133
|
+
if (!isOwnerBearingOutputItem(item)) return;
|
|
5134
|
+
addRawOwnerKeys(keys, item.id, item.encrypted_content);
|
|
5135
|
+
}
|
|
5136
|
+
function isOwnerBearingOutputItem(item) {
|
|
5137
|
+
return item.type === "reasoning" || item.type === "compaction";
|
|
5138
|
+
}
|
|
5139
|
+
function addRawOwnerKeys(keys, id, encryptedContent) {
|
|
5140
|
+
if (id) keys.push(buildResponsesItemOwnershipKey("id", id));
|
|
5141
|
+
if (encryptedContent) keys.push(buildResponsesItemOwnershipKey("encrypted_content", encryptedContent));
|
|
5142
|
+
}
|
|
5143
|
+
function unique(values) {
|
|
5144
|
+
return [...new Set(values)];
|
|
5145
|
+
}
|
|
5146
|
+
//#endregion
|
|
5147
|
+
//#region src/routes/messages/stream-translation.ts
|
|
5148
|
+
function isToolBlockOpen(state) {
|
|
5149
|
+
if (!state.contentBlockOpen) return false;
|
|
5150
|
+
return Object.values(state.toolCalls).some((tc) => tc.anthropicBlockIndex === state.contentBlockIndex);
|
|
5151
|
+
}
|
|
5152
|
+
function translateChunkToAnthropicEvents(chunk, state) {
|
|
5153
|
+
const events = [];
|
|
5154
|
+
if (chunk.choices.length === 0) {
|
|
5155
|
+
completePendingMessage(state, events, chunk);
|
|
5156
|
+
return events;
|
|
4915
5157
|
}
|
|
4916
|
-
|
|
4917
|
-
const
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
const blockIndex = openFunctionCallBlock(state$1, {
|
|
4926
|
-
outputIndex,
|
|
4927
|
-
toolCallId,
|
|
4928
|
-
name,
|
|
4929
|
-
events: events$1
|
|
5158
|
+
const choice = chunk.choices[0];
|
|
5159
|
+
const { delta } = choice;
|
|
5160
|
+
handleMessageStart(state, events, chunk);
|
|
5161
|
+
handleThinkingText(delta, state, events);
|
|
5162
|
+
handleContent(delta, state, events);
|
|
5163
|
+
handleToolCalls(delta, state, events);
|
|
5164
|
+
handleFinish(choice, state, {
|
|
5165
|
+
events,
|
|
5166
|
+
chunk
|
|
4930
5167
|
});
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
5168
|
+
return events;
|
|
5169
|
+
}
|
|
5170
|
+
function flushPendingAnthropicStreamEvents(state) {
|
|
5171
|
+
const events = [];
|
|
5172
|
+
completePendingMessage(state, events);
|
|
5173
|
+
return events;
|
|
5174
|
+
}
|
|
5175
|
+
function completePendingMessage(state, events, chunk) {
|
|
5176
|
+
if (!state.pendingMessageDelta) return;
|
|
5177
|
+
if (chunk?.usage) state.pendingMessageDelta.usage = getAnthropicUsageFromOpenAIChunk(chunk, state);
|
|
5178
|
+
events.push(state.pendingMessageDelta, { type: "message_stop" });
|
|
5179
|
+
state.pendingMessageDelta = void 0;
|
|
5180
|
+
}
|
|
5181
|
+
function handleFinish(choice, state, context) {
|
|
5182
|
+
const { events, chunk } = context;
|
|
5183
|
+
if (choice.finish_reason && choice.finish_reason.length > 0) {
|
|
5184
|
+
if (state.contentBlockOpen) {
|
|
5185
|
+
const toolBlockOpen = isToolBlockOpen(state);
|
|
5186
|
+
context.events.push({
|
|
5187
|
+
type: "content_block_stop",
|
|
5188
|
+
index: state.contentBlockIndex
|
|
5189
|
+
});
|
|
5190
|
+
state.contentBlockOpen = false;
|
|
5191
|
+
state.contentBlockIndex++;
|
|
5192
|
+
if (!toolBlockOpen) handleReasoningOpaque(choice.delta, events, state);
|
|
5193
|
+
}
|
|
5194
|
+
flushDeferredContent(state, events);
|
|
5195
|
+
state.pendingMessageDelta = {
|
|
5196
|
+
type: "message_delta",
|
|
4935
5197
|
delta: {
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
}
|
|
4939
|
-
|
|
4940
|
-
|
|
5198
|
+
stop_reason: mapOpenAIStopReasonToAnthropic(choice.finish_reason),
|
|
5199
|
+
stop_sequence: null
|
|
5200
|
+
},
|
|
5201
|
+
usage: getAnthropicUsageFromOpenAIChunk(chunk, state)
|
|
5202
|
+
};
|
|
5203
|
+
if (chunk.usage) completePendingMessage(state, events, chunk);
|
|
4941
5204
|
}
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
const
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
5205
|
+
}
|
|
5206
|
+
function getAnthropicUsageFromOpenAIChunk(chunk, state) {
|
|
5207
|
+
const { cacheCreationTokens, inputTokens, cacheReadTokens } = getOpenAIChunkUsageTokens(chunk, state);
|
|
5208
|
+
return {
|
|
5209
|
+
input_tokens: inputTokens,
|
|
5210
|
+
output_tokens: chunk.usage?.completion_tokens ?? 0,
|
|
5211
|
+
...chunk.usage?.prompt_tokens_details?.cache_creation_input_tokens !== void 0 && { cache_creation_input_tokens: cacheCreationTokens },
|
|
5212
|
+
...cacheReadTokens !== void 0 && { cache_read_input_tokens: cacheReadTokens }
|
|
5213
|
+
};
|
|
5214
|
+
}
|
|
5215
|
+
function getOpenAIChunkUsageTokens(chunk, state) {
|
|
5216
|
+
const promptTokens = chunk.usage?.prompt_tokens;
|
|
5217
|
+
const cachedTokens = chunk.usage?.prompt_tokens_details?.cached_tokens ?? 0;
|
|
5218
|
+
const cacheCreationTokens = chunk.usage?.prompt_tokens_details?.cache_creation_input_tokens ?? 0;
|
|
5219
|
+
if (promptTokens !== void 0) return {
|
|
5220
|
+
cacheCreationTokens,
|
|
5221
|
+
cachedTokens,
|
|
5222
|
+
inputTokens: Math.max(0, promptTokens - cachedTokens - cacheCreationTokens),
|
|
5223
|
+
cacheReadTokens: chunk.usage?.prompt_tokens_details?.cached_tokens
|
|
5224
|
+
};
|
|
5225
|
+
const historicalInputTokens = state?.historicalInputTokens;
|
|
5226
|
+
const historicalOutputTokens = state?.historicalOutputTokens ?? 0;
|
|
5227
|
+
return {
|
|
5228
|
+
cacheCreationTokens,
|
|
5229
|
+
cachedTokens,
|
|
5230
|
+
inputTokens: (historicalInputTokens !== void 0 ? historicalInputTokens + historicalOutputTokens : void 0) ?? state?.estimatedInputTokens ?? 0,
|
|
5231
|
+
cacheReadTokens: state?.historicalCachedInputTokens
|
|
5232
|
+
};
|
|
5233
|
+
}
|
|
5234
|
+
function handleToolCalls(delta, state, events) {
|
|
5235
|
+
if (delta.tool_calls && delta.tool_calls.length > 0) {
|
|
5236
|
+
closeThinkingBlockIfOpen(state, events);
|
|
5237
|
+
handleReasoningOpaqueInToolCalls(state, events, delta);
|
|
5238
|
+
for (const toolCall of delta.tool_calls) {
|
|
5239
|
+
if (toolCall.id && toolCall.function?.name) {
|
|
5240
|
+
if (state.contentBlockOpen) {
|
|
5241
|
+
events.push({
|
|
5242
|
+
type: "content_block_stop",
|
|
5243
|
+
index: state.contentBlockIndex
|
|
5244
|
+
});
|
|
5245
|
+
state.contentBlockIndex++;
|
|
5246
|
+
state.contentBlockOpen = false;
|
|
5247
|
+
}
|
|
5248
|
+
const anthropicBlockIndex = state.contentBlockIndex;
|
|
5249
|
+
state.toolCalls[toolCall.index] = {
|
|
5250
|
+
id: toolCall.id,
|
|
5251
|
+
name: toolCall.function.name,
|
|
5252
|
+
anthropicBlockIndex
|
|
5253
|
+
};
|
|
5254
|
+
events.push({
|
|
5255
|
+
type: "content_block_start",
|
|
5256
|
+
index: anthropicBlockIndex,
|
|
5257
|
+
content_block: {
|
|
5258
|
+
type: "tool_use",
|
|
5259
|
+
id: toolCall.id,
|
|
5260
|
+
name: toolCall.function.name,
|
|
5261
|
+
input: {}
|
|
5262
|
+
}
|
|
5263
|
+
});
|
|
5264
|
+
state.contentBlockOpen = true;
|
|
5265
|
+
}
|
|
5266
|
+
if (toolCall.function?.arguments) {
|
|
5267
|
+
const toolCallInfo = state.toolCalls[toolCall.index];
|
|
5268
|
+
if (toolCallInfo) events.push({
|
|
5269
|
+
type: "content_block_delta",
|
|
5270
|
+
index: toolCallInfo.anthropicBlockIndex,
|
|
5271
|
+
delta: {
|
|
5272
|
+
type: "input_json_delta",
|
|
5273
|
+
partial_json: toolCall.function.arguments
|
|
5274
|
+
}
|
|
5275
|
+
});
|
|
5276
|
+
}
|
|
5277
|
+
}
|
|
5278
|
+
}
|
|
5279
|
+
}
|
|
5280
|
+
function handleReasoningOpaqueInToolCalls(state, events, delta) {
|
|
5281
|
+
if (state.contentBlockOpen && !isToolBlockOpen(state)) {
|
|
5282
|
+
events.push({
|
|
5283
|
+
type: "content_block_stop",
|
|
5284
|
+
index: state.contentBlockIndex
|
|
5285
|
+
});
|
|
5286
|
+
state.contentBlockIndex++;
|
|
5287
|
+
state.contentBlockOpen = false;
|
|
5288
|
+
}
|
|
5289
|
+
handleReasoningOpaque(delta, events, state);
|
|
5290
|
+
}
|
|
5291
|
+
function handleContent(delta, state, events) {
|
|
5292
|
+
if (delta.content && delta.content.length > 0) {
|
|
5293
|
+
closeThinkingBlockIfOpen(state, events);
|
|
5294
|
+
if (isToolBlockOpen(state) || hasToolCallDelta(delta)) {
|
|
5295
|
+
state.deferredContent = `${state.deferredContent ?? ""}${delta.content}`;
|
|
5296
|
+
return;
|
|
5297
|
+
}
|
|
5298
|
+
if (!state.contentBlockOpen) {
|
|
5299
|
+
events.push({
|
|
5300
|
+
type: "content_block_start",
|
|
5301
|
+
index: state.contentBlockIndex,
|
|
5302
|
+
content_block: {
|
|
5303
|
+
type: "text",
|
|
5304
|
+
text: ""
|
|
5305
|
+
}
|
|
5306
|
+
});
|
|
5307
|
+
state.contentBlockOpen = true;
|
|
5308
|
+
}
|
|
5309
|
+
events.push({
|
|
5310
|
+
type: "content_block_delta",
|
|
5311
|
+
index: state.contentBlockIndex,
|
|
5312
|
+
delta: {
|
|
5313
|
+
type: "text_delta",
|
|
5314
|
+
text: delta.content
|
|
5315
|
+
}
|
|
5316
|
+
});
|
|
5317
|
+
}
|
|
5318
|
+
if (delta.content === "" && delta.reasoning_opaque && delta.reasoning_opaque.length > 0 && state.thinkingBlockOpen) {
|
|
5319
|
+
events.push({
|
|
5320
|
+
type: "content_block_delta",
|
|
5321
|
+
index: state.contentBlockIndex,
|
|
5322
|
+
delta: {
|
|
5323
|
+
type: "signature_delta",
|
|
5324
|
+
signature: delta.reasoning_opaque
|
|
5325
|
+
}
|
|
5326
|
+
}, {
|
|
5327
|
+
type: "content_block_stop",
|
|
5328
|
+
index: state.contentBlockIndex
|
|
5329
|
+
});
|
|
5330
|
+
state.contentBlockIndex++;
|
|
5331
|
+
state.thinkingBlockOpen = false;
|
|
5332
|
+
}
|
|
5333
|
+
}
|
|
5334
|
+
function hasToolCallDelta(delta) {
|
|
5335
|
+
return Boolean(delta.tool_calls && delta.tool_calls.length > 0);
|
|
5336
|
+
}
|
|
5337
|
+
function flushDeferredContent(state, events) {
|
|
5338
|
+
if (!state.deferredContent) return;
|
|
5339
|
+
if (!state.contentBlockOpen) {
|
|
5340
|
+
events.push({
|
|
5341
|
+
type: "content_block_start",
|
|
5342
|
+
index: state.contentBlockIndex,
|
|
5343
|
+
content_block: {
|
|
5344
|
+
type: "text",
|
|
5345
|
+
text: ""
|
|
5346
|
+
}
|
|
5347
|
+
});
|
|
5348
|
+
state.contentBlockOpen = true;
|
|
5349
|
+
}
|
|
5350
|
+
events.push({
|
|
5351
|
+
type: "content_block_delta",
|
|
5352
|
+
index: state.contentBlockIndex,
|
|
5353
|
+
delta: {
|
|
5354
|
+
type: "text_delta",
|
|
5355
|
+
text: state.deferredContent
|
|
5356
|
+
}
|
|
5357
|
+
}, {
|
|
5358
|
+
type: "content_block_stop",
|
|
5359
|
+
index: state.contentBlockIndex
|
|
5360
|
+
});
|
|
5361
|
+
state.deferredContent = void 0;
|
|
5362
|
+
state.contentBlockOpen = false;
|
|
5363
|
+
state.contentBlockIndex++;
|
|
5364
|
+
}
|
|
5365
|
+
function handleMessageStart(state, events, chunk) {
|
|
5366
|
+
if (!state.messageStartSent) {
|
|
5367
|
+
const { cacheCreationTokens, inputTokens, cacheReadTokens } = getOpenAIChunkUsageTokens(chunk, state);
|
|
5368
|
+
events.push({
|
|
5369
|
+
type: "message_start",
|
|
5370
|
+
message: {
|
|
5371
|
+
id: chunk.id,
|
|
5372
|
+
type: "message",
|
|
5373
|
+
role: "assistant",
|
|
5374
|
+
content: [],
|
|
5375
|
+
model: chunk.model,
|
|
5376
|
+
stop_reason: null,
|
|
5377
|
+
stop_sequence: null,
|
|
5378
|
+
usage: {
|
|
5379
|
+
input_tokens: inputTokens,
|
|
5380
|
+
output_tokens: 0,
|
|
5381
|
+
...chunk.usage?.prompt_tokens_details?.cache_creation_input_tokens !== void 0 && { cache_creation_input_tokens: cacheCreationTokens },
|
|
5382
|
+
...cacheReadTokens !== void 0 && { cache_read_input_tokens: cacheReadTokens }
|
|
5383
|
+
}
|
|
5384
|
+
}
|
|
5385
|
+
});
|
|
5386
|
+
state.messageStartSent = true;
|
|
5387
|
+
}
|
|
5388
|
+
}
|
|
5389
|
+
function handleReasoningOpaque(delta, events, state) {
|
|
5390
|
+
if (delta.reasoning_opaque && delta.reasoning_opaque.length > 0) {
|
|
5391
|
+
events.push({
|
|
5392
|
+
type: "content_block_start",
|
|
5393
|
+
index: state.contentBlockIndex,
|
|
5394
|
+
content_block: {
|
|
5395
|
+
type: "thinking",
|
|
5396
|
+
thinking: ""
|
|
5397
|
+
}
|
|
5398
|
+
}, {
|
|
5399
|
+
type: "content_block_delta",
|
|
5400
|
+
index: state.contentBlockIndex,
|
|
5401
|
+
delta: {
|
|
5402
|
+
type: "thinking_delta",
|
|
5403
|
+
thinking: THINKING_TEXT$1
|
|
5404
|
+
}
|
|
5405
|
+
}, {
|
|
5406
|
+
type: "content_block_delta",
|
|
5407
|
+
index: state.contentBlockIndex,
|
|
5408
|
+
delta: {
|
|
5409
|
+
type: "signature_delta",
|
|
5410
|
+
signature: delta.reasoning_opaque
|
|
5411
|
+
}
|
|
5412
|
+
}, {
|
|
5413
|
+
type: "content_block_stop",
|
|
5414
|
+
index: state.contentBlockIndex
|
|
5415
|
+
});
|
|
5416
|
+
state.contentBlockIndex++;
|
|
5417
|
+
}
|
|
5418
|
+
}
|
|
5419
|
+
function handleThinkingText(delta, state, events) {
|
|
5420
|
+
const reasoningText = delta.reasoning_text ?? delta.reasoning_content;
|
|
5421
|
+
if (reasoningText && reasoningText.length > 0) {
|
|
5422
|
+
if (state.contentBlockOpen) {
|
|
5423
|
+
delta.content = reasoningText;
|
|
5424
|
+
delta.reasoning_text = void 0;
|
|
5425
|
+
delta.reasoning_content = void 0;
|
|
5426
|
+
return;
|
|
5427
|
+
}
|
|
5428
|
+
if (!state.thinkingBlockOpen) {
|
|
5429
|
+
events.push({
|
|
5430
|
+
type: "content_block_start",
|
|
5431
|
+
index: state.contentBlockIndex,
|
|
5432
|
+
content_block: {
|
|
5433
|
+
type: "thinking",
|
|
5434
|
+
thinking: ""
|
|
5435
|
+
}
|
|
5436
|
+
});
|
|
5437
|
+
state.thinkingBlockOpen = true;
|
|
5438
|
+
}
|
|
5439
|
+
events.push({
|
|
5440
|
+
type: "content_block_delta",
|
|
5441
|
+
index: state.contentBlockIndex,
|
|
5442
|
+
delta: {
|
|
5443
|
+
type: "thinking_delta",
|
|
5444
|
+
thinking: reasoningText
|
|
5445
|
+
}
|
|
5446
|
+
});
|
|
5447
|
+
}
|
|
5448
|
+
}
|
|
5449
|
+
function closeThinkingBlockIfOpen(state, events) {
|
|
5450
|
+
if (state.thinkingBlockOpen) {
|
|
5451
|
+
events.push({
|
|
5452
|
+
type: "content_block_delta",
|
|
5453
|
+
index: state.contentBlockIndex,
|
|
5454
|
+
delta: {
|
|
5455
|
+
type: "signature_delta",
|
|
5456
|
+
signature: ""
|
|
5457
|
+
}
|
|
5458
|
+
}, {
|
|
5459
|
+
type: "content_block_stop",
|
|
5460
|
+
index: state.contentBlockIndex
|
|
5461
|
+
});
|
|
5462
|
+
state.contentBlockIndex++;
|
|
5463
|
+
state.thinkingBlockOpen = false;
|
|
5464
|
+
}
|
|
5465
|
+
}
|
|
5466
|
+
//#endregion
|
|
5467
|
+
//#region src/services/providers/anthropic-proxy.ts
|
|
5468
|
+
const SHARED_FORWARDABLE_HEADERS = ["accept", "user-agent"];
|
|
5469
|
+
const ANTHROPIC_FORWARDABLE_HEADERS = ["anthropic-version", "anthropic-beta"];
|
|
5470
|
+
const STRIPPED_RESPONSE_HEADERS = [
|
|
5471
|
+
"connection",
|
|
5472
|
+
"content-encoding",
|
|
5473
|
+
"content-length",
|
|
5474
|
+
"keep-alive",
|
|
5475
|
+
"proxy-authenticate",
|
|
5476
|
+
"proxy-authorization",
|
|
5477
|
+
"te",
|
|
5478
|
+
"trailer",
|
|
5479
|
+
"transfer-encoding",
|
|
5480
|
+
"upgrade"
|
|
5481
|
+
];
|
|
5482
|
+
function buildProviderUpstreamHeaders(providerConfig, requestHeaders) {
|
|
5483
|
+
const authHeaders = {};
|
|
5484
|
+
if (providerConfig.authType === "authorization") authHeaders.authorization = `Bearer ${providerConfig.apiKey}`;
|
|
5485
|
+
else authHeaders["x-api-key"] = providerConfig.apiKey;
|
|
5486
|
+
const headers = {
|
|
5487
|
+
"content-type": "application/json",
|
|
5488
|
+
accept: "application/json",
|
|
5489
|
+
...authHeaders
|
|
5490
|
+
};
|
|
5491
|
+
for (const headerName of SHARED_FORWARDABLE_HEADERS) {
|
|
5492
|
+
const headerValue = requestHeaders.get(headerName);
|
|
5493
|
+
if (headerValue) headers[headerName] = headerValue;
|
|
5494
|
+
}
|
|
5495
|
+
if (providerConfig.type !== "anthropic") return headers;
|
|
5496
|
+
for (const headerName of ANTHROPIC_FORWARDABLE_HEADERS) {
|
|
5497
|
+
const headerValue = requestHeaders.get(headerName);
|
|
5498
|
+
if (headerValue) headers[headerName] = headerValue;
|
|
5499
|
+
}
|
|
5500
|
+
return headers;
|
|
5501
|
+
}
|
|
5502
|
+
function createProviderProxyResponse(upstreamResponse) {
|
|
5503
|
+
const headers = new Headers(upstreamResponse.headers);
|
|
5504
|
+
for (const headerName of STRIPPED_RESPONSE_HEADERS) headers.delete(headerName);
|
|
5505
|
+
return new Response(upstreamResponse.body, {
|
|
5506
|
+
headers,
|
|
5507
|
+
status: upstreamResponse.status,
|
|
5508
|
+
statusText: upstreamResponse.statusText
|
|
5509
|
+
});
|
|
5510
|
+
}
|
|
5511
|
+
async function forwardProviderMessages(providerConfig, payload, requestHeaders, fetchImpl = fetch) {
|
|
5512
|
+
return await fetchImpl(`${providerConfig.baseUrl}/v1/messages`, {
|
|
5513
|
+
method: "POST",
|
|
5514
|
+
headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
|
|
5515
|
+
body: JSON.stringify(payload)
|
|
5516
|
+
});
|
|
5517
|
+
}
|
|
5518
|
+
async function forwardProviderChatCompletions(providerConfig, payload, requestHeaders, fetchImpl = fetch) {
|
|
5519
|
+
return await fetchImpl(`${providerConfig.baseUrl}/v1/chat/completions`, {
|
|
5520
|
+
method: "POST",
|
|
5521
|
+
headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
|
|
5522
|
+
body: JSON.stringify(payload)
|
|
5523
|
+
});
|
|
5524
|
+
}
|
|
5525
|
+
async function forwardProviderModels(providerConfig, requestHeaders, fetchImpl = fetch) {
|
|
5526
|
+
return await fetchImpl(`${providerConfig.baseUrl}/v1/models`, {
|
|
5527
|
+
method: "GET",
|
|
5528
|
+
headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders)
|
|
5529
|
+
});
|
|
5530
|
+
}
|
|
5531
|
+
//#endregion
|
|
5532
|
+
//#region src/routes/provider/messages/handler.ts
|
|
5533
|
+
const logger$4 = createHandlerLogger("provider-messages-handler");
|
|
5534
|
+
const getProviderFetch$1 = (c) => c.get("providerFetch") ?? fetch;
|
|
5535
|
+
const resolveProviderConfig$1 = (c, provider) => {
|
|
5536
|
+
return (c.get("providerConfigResolver") ?? getProviderConfig)(provider);
|
|
5537
|
+
};
|
|
5538
|
+
const OPENAI_COMPATIBLE_CONTEXT_CACHE_MARKER_LIMIT = 4;
|
|
5539
|
+
const OPENAI_COMPATIBLE_CONTEXT_CACHE_CONTROL = { type: "ephemeral" };
|
|
5540
|
+
const OPENAI_COMPATIBLE_CONTEXT_CACHE_ROLES = new Set([
|
|
5541
|
+
"system",
|
|
5542
|
+
"user",
|
|
5543
|
+
"assistant",
|
|
5544
|
+
"tool"
|
|
5545
|
+
]);
|
|
5546
|
+
const writeProviderStreamError = async (stream, message) => {
|
|
5547
|
+
try {
|
|
5548
|
+
await stream.writeSSE({
|
|
5549
|
+
event: "error",
|
|
5550
|
+
data: JSON.stringify({
|
|
5551
|
+
error: {
|
|
5552
|
+
message,
|
|
5553
|
+
type: "api_error"
|
|
5554
|
+
},
|
|
5555
|
+
type: "error"
|
|
5556
|
+
})
|
|
5557
|
+
});
|
|
5558
|
+
} catch (error) {
|
|
5559
|
+
logger$4.warn("Failed to write provider stream error event", error);
|
|
5560
|
+
}
|
|
5561
|
+
};
|
|
5562
|
+
async function handleProviderMessages(c) {
|
|
5563
|
+
const provider = c.req.param("provider");
|
|
5564
|
+
return await handleProviderMessagesForProvider(c, {
|
|
5565
|
+
payload: await c.req.json(),
|
|
5566
|
+
provider
|
|
5567
|
+
});
|
|
5568
|
+
}
|
|
5569
|
+
async function handleProviderMessagesForProvider(c, options) {
|
|
5570
|
+
const { instrumentation, payload, provider } = options;
|
|
5571
|
+
const providerConfig = resolveProviderConfig$1(c, provider);
|
|
5572
|
+
if (!providerConfig) {
|
|
5573
|
+
const message = `Provider '${provider}' not found or disabled`;
|
|
5574
|
+
instrumentation?.onError?.({
|
|
5575
|
+
errorMessage: message,
|
|
5576
|
+
errorName: "ProviderNotFoundError",
|
|
5577
|
+
errorStatus: 404,
|
|
5578
|
+
httpStatus: 404
|
|
5579
|
+
});
|
|
5580
|
+
return c.json({ error: {
|
|
5581
|
+
message,
|
|
5582
|
+
type: "invalid_request_error"
|
|
5583
|
+
} }, 404);
|
|
5584
|
+
}
|
|
5585
|
+
try {
|
|
5586
|
+
const modelConfig = providerConfig.models?.[payload.model];
|
|
5587
|
+
applyModelDefaults(payload, modelConfig);
|
|
5588
|
+
debugJson(logger$4, "provider.messages.request", {
|
|
5589
|
+
payload,
|
|
5590
|
+
provider
|
|
5591
|
+
});
|
|
5592
|
+
if (providerConfig.type === "openai-compatible") return await handleOpenAICompatibleProviderMessages(c, {
|
|
5593
|
+
instrumentation,
|
|
5594
|
+
modelConfig,
|
|
5595
|
+
payload,
|
|
5596
|
+
provider,
|
|
5597
|
+
providerConfig
|
|
5598
|
+
});
|
|
5599
|
+
applyMissingExtraBody(payload, { extraBody: modelConfig?.extraBody });
|
|
5600
|
+
const upstreamResponse = await forwardProviderMessages(providerConfig, payload, c.req.raw.headers, getProviderFetch$1(c));
|
|
5601
|
+
if (!upstreamResponse.ok) {
|
|
5602
|
+
logger$4.error("Failed to create responses", upstreamResponse);
|
|
5603
|
+
throw new HTTPError("Failed to create responses", upstreamResponse);
|
|
5604
|
+
}
|
|
5605
|
+
const contentType = upstreamResponse.headers.get("content-type") ?? "";
|
|
5606
|
+
if (Boolean(payload.stream) && contentType.includes("text/event-stream")) return streamProviderMessages({
|
|
5607
|
+
c,
|
|
5608
|
+
instrumentation,
|
|
5609
|
+
payload,
|
|
5610
|
+
provider,
|
|
5611
|
+
providerConfig,
|
|
5612
|
+
upstreamResponse
|
|
5613
|
+
});
|
|
5614
|
+
return respondProviderMessagesJson(c, {
|
|
5615
|
+
body: await upstreamResponse.json(),
|
|
5616
|
+
instrumentation,
|
|
5617
|
+
payload,
|
|
5618
|
+
provider,
|
|
5619
|
+
providerConfig
|
|
5620
|
+
});
|
|
5621
|
+
} catch (error) {
|
|
5622
|
+
logger$4.error("provider.messages.error", {
|
|
5623
|
+
provider,
|
|
5624
|
+
error
|
|
5625
|
+
});
|
|
5626
|
+
throw error;
|
|
5627
|
+
}
|
|
5628
|
+
}
|
|
5629
|
+
const applyModelDefaults = (payload, modelConfig) => {
|
|
5630
|
+
payload.temperature ??= modelConfig?.temperature;
|
|
5631
|
+
payload.top_p ??= modelConfig?.topP;
|
|
5632
|
+
payload.top_k ??= modelConfig?.topK;
|
|
5633
|
+
};
|
|
5634
|
+
const applyMissingExtraBody = (payload, options) => {
|
|
5635
|
+
for (const [key, value] of Object.entries(options.extraBody ?? {})) if (!Object.hasOwn(payload, key)) payload[key] = value;
|
|
5636
|
+
};
|
|
5637
|
+
const handleOpenAICompatibleProviderMessages = async (c, options) => {
|
|
5638
|
+
const { instrumentation, modelConfig, payload, provider, providerConfig } = options;
|
|
5639
|
+
const openAIPayload = createOpenAICompatiblePayload(payload, modelConfig);
|
|
5640
|
+
debugJson(logger$4, "provider.messages.openai_compatible.request", {
|
|
5641
|
+
payload: openAIPayload,
|
|
5642
|
+
provider
|
|
5643
|
+
});
|
|
5644
|
+
const upstreamResponse = await forwardProviderChatCompletions(providerConfig, openAIPayload, c.req.raw.headers, getProviderFetch$1(c));
|
|
5645
|
+
if (!upstreamResponse.ok) {
|
|
5646
|
+
logger$4.error("Failed to create openai-compatible responses", upstreamResponse);
|
|
5647
|
+
throw new HTTPError("Failed to create openai-compatible responses", upstreamResponse);
|
|
5648
|
+
}
|
|
5649
|
+
const contentType = upstreamResponse.headers.get("content-type") ?? "";
|
|
5650
|
+
if (Boolean(openAIPayload.stream) && contentType.includes("text/event-stream")) return streamOpenAICompatibleProviderMessages({
|
|
5651
|
+
c,
|
|
5652
|
+
instrumentation,
|
|
5653
|
+
payload,
|
|
5654
|
+
provider,
|
|
5655
|
+
upstreamResponse
|
|
5656
|
+
});
|
|
5657
|
+
return respondOpenAICompatibleProviderMessagesJson(c, {
|
|
5658
|
+
body: await upstreamResponse.json(),
|
|
5659
|
+
instrumentation,
|
|
5660
|
+
payload,
|
|
5661
|
+
provider
|
|
5662
|
+
});
|
|
5663
|
+
};
|
|
5664
|
+
const createOpenAICompatiblePayload = (payload, modelConfig) => {
|
|
5665
|
+
const openAIPayload = translateToOpenAI(payload, {
|
|
5666
|
+
supportPdf: modelConfig?.supportPdf,
|
|
5667
|
+
toolContentSupportType: modelConfig?.toolContentSupportType ?? []
|
|
5668
|
+
});
|
|
5669
|
+
if (payload.top_k !== void 0) openAIPayload.top_k = payload.top_k;
|
|
5670
|
+
if (openAIPayload.stream) openAIPayload.stream_options = { include_usage: true };
|
|
5671
|
+
normalizeOpenAICompatibleReasoningContent(openAIPayload);
|
|
5672
|
+
applyOpenAICompatibleRequestOverrides(openAIPayload, {
|
|
5673
|
+
extraBody: modelConfig?.extraBody,
|
|
5674
|
+
source: payload
|
|
5675
|
+
});
|
|
5676
|
+
applyMissingExtraBody(openAIPayload, { extraBody: modelConfig?.extraBody });
|
|
5677
|
+
if (!Object.hasOwn(openAIPayload, "parallel_tool_calls")) openAIPayload.parallel_tool_calls = true;
|
|
5678
|
+
if (modelConfig?.contextCache !== false) applyOpenAICompatibleContextCache(openAIPayload);
|
|
5679
|
+
return openAIPayload;
|
|
5680
|
+
};
|
|
5681
|
+
const normalizeOpenAICompatibleReasoningContent = (payload) => {
|
|
5682
|
+
for (const message of payload.messages) {
|
|
5683
|
+
if (message.role !== "assistant") continue;
|
|
5684
|
+
if (message.reasoning_content === void 0 && message.reasoning_text !== void 0) message.reasoning_content = message.reasoning_text;
|
|
5685
|
+
delete message.reasoning_text;
|
|
5686
|
+
delete message.reasoning_opaque;
|
|
5687
|
+
}
|
|
5688
|
+
};
|
|
5689
|
+
const applyOpenAICompatibleRequestOverrides = (payload, options) => {
|
|
5690
|
+
const allowedKeys = new Set(Object.keys(options.extraBody ?? {}));
|
|
5691
|
+
for (const key of allowedKeys) if (Object.hasOwn(options.source, key)) payload[key] = options.source[key];
|
|
5692
|
+
};
|
|
5693
|
+
const applyOpenAICompatibleContextCache = (payload) => {
|
|
5694
|
+
const messageIndexes = selectContextCacheMessageIndexes(payload.messages);
|
|
5695
|
+
for (const messageIndex of messageIndexes) applyContextCacheControl(payload.messages[messageIndex]);
|
|
5696
|
+
};
|
|
5697
|
+
const selectContextCacheMessageIndexes = (messages) => {
|
|
5698
|
+
const cacheableIndexes = messages.flatMap((message, index) => isContextCacheMarkerEligible(message) ? [index] : []);
|
|
5699
|
+
const systemIndexes = cacheableIndexes.filter((index) => messages[index]?.role === "system").slice(0, 2);
|
|
5700
|
+
const finalIndexes = cacheableIndexes.filter((index) => messages[index]?.role !== "system").slice(-2);
|
|
5701
|
+
return uniqueIndexes([...systemIndexes, ...finalIndexes]).sort((a, b) => a - b);
|
|
5702
|
+
};
|
|
5703
|
+
const uniqueIndexes = (indexes) => [...new Set(indexes)].slice(0, OPENAI_COMPATIBLE_CONTEXT_CACHE_MARKER_LIMIT);
|
|
5704
|
+
const isContextCacheMarkerEligible = (message) => {
|
|
5705
|
+
if (!OPENAI_COMPATIBLE_CONTEXT_CACHE_ROLES.has(message.role)) return false;
|
|
5706
|
+
if (typeof message.content === "string") return message.content.length > 0;
|
|
5707
|
+
return Array.isArray(message.content) && message.content.length > 0;
|
|
5708
|
+
};
|
|
5709
|
+
const applyContextCacheControl = (message) => {
|
|
5710
|
+
if (!message) return;
|
|
5711
|
+
if (typeof message.content === "string") {
|
|
5712
|
+
message.content = [{
|
|
5713
|
+
type: "text",
|
|
5714
|
+
text: message.content,
|
|
5715
|
+
cache_control: { ...OPENAI_COMPATIBLE_CONTEXT_CACHE_CONTROL }
|
|
5716
|
+
}];
|
|
5717
|
+
return;
|
|
5718
|
+
}
|
|
5719
|
+
if (!Array.isArray(message.content)) return;
|
|
5720
|
+
const lastPart = message.content.at(-1);
|
|
5721
|
+
if (!lastPart) return;
|
|
5722
|
+
setContextCacheControl(lastPart);
|
|
5723
|
+
};
|
|
5724
|
+
const setContextCacheControl = (part) => {
|
|
5725
|
+
part.cache_control = { ...OPENAI_COMPATIBLE_CONTEXT_CACHE_CONTROL };
|
|
5726
|
+
};
|
|
5727
|
+
const streamProviderMessages = ({ c, instrumentation, providerConfig, upstreamResponse }) => {
|
|
5728
|
+
logger$4.debug("provider.messages.streaming");
|
|
5729
|
+
return streamSSE(c, async (stream) => {
|
|
5730
|
+
let usage = {};
|
|
5731
|
+
try {
|
|
5732
|
+
let completed = false;
|
|
5733
|
+
for await (const chunk of events(upstreamResponse)) {
|
|
5734
|
+
logger$4.debug("provider.messages.raw_stream_event:", chunk.data);
|
|
5735
|
+
const eventName = chunk.event;
|
|
5736
|
+
if (eventName === "ping") {
|
|
5737
|
+
await stream.writeSSE({
|
|
5738
|
+
event: "ping",
|
|
5739
|
+
data: "{\"type\":\"ping\"}"
|
|
5740
|
+
});
|
|
5741
|
+
continue;
|
|
5742
|
+
}
|
|
5743
|
+
let data = chunk.data;
|
|
5744
|
+
if (!data) continue;
|
|
5745
|
+
if (chunk.data === "[DONE]") {
|
|
5746
|
+
completed = true;
|
|
5747
|
+
break;
|
|
5748
|
+
}
|
|
5749
|
+
const parsed = parseProviderStreamEvent(data, providerConfig);
|
|
5750
|
+
usage = mergeAnthropicUsage(usage, parsed.usage);
|
|
5751
|
+
data = parsed.data;
|
|
5752
|
+
await stream.writeSSE({
|
|
5753
|
+
event: eventName,
|
|
5754
|
+
data
|
|
5755
|
+
});
|
|
5756
|
+
if (parsed.error || eventName === "error") {
|
|
5757
|
+
instrumentation?.onError?.(parsed.error ?? {
|
|
5758
|
+
errorMessage: data,
|
|
5759
|
+
errorName: "ProviderStreamError",
|
|
5760
|
+
httpStatus: 500
|
|
5761
|
+
});
|
|
5762
|
+
return;
|
|
5763
|
+
}
|
|
5764
|
+
completed ||= parsed.done;
|
|
5765
|
+
}
|
|
5766
|
+
if (!completed) throw new Error("Provider messages stream ended before completion");
|
|
5767
|
+
instrumentation?.onComplete?.(usage);
|
|
5768
|
+
} catch (error) {
|
|
5769
|
+
const details = await extractErrorObservability(error);
|
|
5770
|
+
logger$4.warn("provider.messages.streaming.error", error);
|
|
5771
|
+
instrumentation?.onError?.(details);
|
|
5772
|
+
await writeProviderStreamError(stream, getUserVisibleErrorMessage(details));
|
|
5773
|
+
}
|
|
5774
|
+
});
|
|
5775
|
+
};
|
|
5776
|
+
const streamOpenAICompatibleProviderMessages = ({ c, instrumentation, upstreamResponse }) => {
|
|
5777
|
+
logger$4.debug("provider.messages.openai_compatible.streaming");
|
|
5778
|
+
return streamSSE(c, async (stream) => {
|
|
5779
|
+
let usage = {};
|
|
5780
|
+
const streamState = {
|
|
5781
|
+
messageStartSent: false,
|
|
5782
|
+
contentBlockIndex: 0,
|
|
5783
|
+
contentBlockOpen: false,
|
|
5784
|
+
toolCalls: {},
|
|
5785
|
+
thinkingBlockOpen: false
|
|
5786
|
+
};
|
|
5787
|
+
try {
|
|
5788
|
+
let completed = false;
|
|
5789
|
+
for await (const chunk of events(upstreamResponse)) {
|
|
5790
|
+
logger$4.debug("provider.messages.openai_compatible.raw_stream_event:", chunk.data);
|
|
5791
|
+
if (chunk.event === "ping") {
|
|
5792
|
+
await stream.writeSSE({
|
|
5793
|
+
event: "ping",
|
|
5794
|
+
data: "{\"type\":\"ping\"}"
|
|
5795
|
+
});
|
|
5796
|
+
continue;
|
|
5797
|
+
}
|
|
5798
|
+
if (!chunk.data) continue;
|
|
5799
|
+
if (chunk.data === "[DONE]") {
|
|
5800
|
+
completed = true;
|
|
5801
|
+
break;
|
|
5802
|
+
}
|
|
5803
|
+
const parsed = parseOpenAICompatibleStreamChunk(chunk.data);
|
|
5804
|
+
if (parsed.usage) usage = normalizeOpenAIUsage(parsed.usage);
|
|
5805
|
+
const events = translateChunkToAnthropicEvents(parsed, streamState);
|
|
5806
|
+
for (const event of events) {
|
|
5807
|
+
const eventData = JSON.stringify(event);
|
|
5808
|
+
debugLazy(logger$4, () => ["provider.messages.openai_compatible.translated_event:", eventData]);
|
|
5809
|
+
await stream.writeSSE({
|
|
5810
|
+
event: event.type,
|
|
5811
|
+
data: eventData
|
|
5812
|
+
});
|
|
5813
|
+
completed ||= event.type === "message_stop";
|
|
5814
|
+
}
|
|
5815
|
+
}
|
|
5816
|
+
for (const event of flushPendingAnthropicStreamEvents(streamState)) {
|
|
5817
|
+
const eventData = JSON.stringify(event);
|
|
5818
|
+
debugLazy(logger$4, () => ["provider.messages.openai_compatible.translated_event:", eventData]);
|
|
5819
|
+
await stream.writeSSE({
|
|
5820
|
+
event: event.type,
|
|
5821
|
+
data: eventData
|
|
5822
|
+
});
|
|
5823
|
+
completed ||= event.type === "message_stop";
|
|
5824
|
+
}
|
|
5825
|
+
if (!completed) throw new Error("OpenAI-compatible provider messages stream ended before completion");
|
|
5826
|
+
instrumentation?.onComplete?.(usage);
|
|
5827
|
+
} catch (error) {
|
|
5828
|
+
const details = await extractErrorObservability(error);
|
|
5829
|
+
logger$4.warn("provider.messages.openai_compatible.streaming.error", error);
|
|
5830
|
+
instrumentation?.onError?.(details);
|
|
5831
|
+
await writeProviderStreamError(stream, getUserVisibleErrorMessage(details));
|
|
5832
|
+
}
|
|
5833
|
+
});
|
|
5834
|
+
};
|
|
5835
|
+
const parseOpenAICompatibleStreamChunk = (data) => {
|
|
5836
|
+
let parsed;
|
|
5837
|
+
try {
|
|
5838
|
+
parsed = JSON.parse(data);
|
|
5839
|
+
} catch (error) {
|
|
5840
|
+
logger$4.error("provider.messages.openai_compatible.parse_chunk_error", {
|
|
5841
|
+
data,
|
|
5842
|
+
error
|
|
5843
|
+
});
|
|
5844
|
+
throw new Error("Failed to parse OpenAI-compatible stream chunk", { cause: error });
|
|
5845
|
+
}
|
|
5846
|
+
const streamErrorMessage = getOpenAICompatibleStreamErrorMessage(parsed.error);
|
|
5847
|
+
if (streamErrorMessage) throw new Error(streamErrorMessage);
|
|
5848
|
+
return parsed;
|
|
5849
|
+
};
|
|
5850
|
+
const getOpenAICompatibleStreamErrorMessage = (error) => {
|
|
5851
|
+
if (typeof error === "string") return error;
|
|
5852
|
+
if (!error || typeof error !== "object") return null;
|
|
5853
|
+
const message = error.message;
|
|
5854
|
+
return typeof message === "string" ? message : JSON.stringify(error);
|
|
5855
|
+
};
|
|
5856
|
+
const parseProviderStreamEvent = (data, providerConfig) => {
|
|
5857
|
+
try {
|
|
5858
|
+
const parsed = JSON.parse(data);
|
|
5859
|
+
if (parsed.type === "message_start") {
|
|
5860
|
+
adjustInputTokens(providerConfig, parsed.message.usage);
|
|
5861
|
+
return {
|
|
5862
|
+
data: JSON.stringify(parsed),
|
|
5863
|
+
done: false,
|
|
5864
|
+
model: parsed.message.model,
|
|
5865
|
+
usage: normalizeAnthropicUsage(parsed.message.usage)
|
|
5866
|
+
};
|
|
5867
|
+
}
|
|
5868
|
+
if (parsed.type === "message_delta") {
|
|
5869
|
+
adjustInputTokens(providerConfig, parsed.usage);
|
|
5870
|
+
return {
|
|
5871
|
+
data: JSON.stringify(parsed),
|
|
5872
|
+
done: false,
|
|
5873
|
+
usage: normalizeAnthropicUsage(parsed.usage)
|
|
5874
|
+
};
|
|
5875
|
+
}
|
|
5876
|
+
if (parsed.type === "message_stop") return {
|
|
5877
|
+
data: JSON.stringify(parsed),
|
|
5878
|
+
done: true,
|
|
5879
|
+
usage: {}
|
|
5880
|
+
};
|
|
5881
|
+
if (parsed.type === "error") return {
|
|
5882
|
+
data: JSON.stringify(parsed),
|
|
5883
|
+
done: false,
|
|
5884
|
+
error: {
|
|
5885
|
+
errorMessage: parsed.error.message,
|
|
5886
|
+
errorName: parsed.error.type,
|
|
5887
|
+
httpStatus: 500
|
|
5888
|
+
},
|
|
5889
|
+
usage: {}
|
|
5890
|
+
};
|
|
5891
|
+
return {
|
|
5892
|
+
data: JSON.stringify(parsed),
|
|
5893
|
+
done: false,
|
|
5894
|
+
usage: {}
|
|
5895
|
+
};
|
|
5896
|
+
} catch (error) {
|
|
5897
|
+
logger$4.error("provider.messages.streaming.adjust_tokens_error", {
|
|
5898
|
+
error,
|
|
5899
|
+
originalData: data
|
|
5900
|
+
});
|
|
5901
|
+
throw new Error("Failed to parse provider messages stream event", { cause: error });
|
|
5902
|
+
}
|
|
5903
|
+
};
|
|
5904
|
+
const respondProviderMessagesJson = (c, options) => {
|
|
5905
|
+
const { body, instrumentation, providerConfig } = options;
|
|
5906
|
+
adjustInputTokens(providerConfig, body.usage);
|
|
5907
|
+
debugJson(logger$4, "provider.messages.no_stream result:", body);
|
|
5908
|
+
const response = c.json(body);
|
|
5909
|
+
instrumentation?.onComplete?.(normalizeAnthropicUsage(body.usage));
|
|
5910
|
+
return response;
|
|
5911
|
+
};
|
|
5912
|
+
const respondOpenAICompatibleProviderMessagesJson = (c, options) => {
|
|
5913
|
+
const { body, instrumentation } = options;
|
|
5914
|
+
const anthropicResponse = translateToAnthropic(body);
|
|
5915
|
+
debugJson(logger$4, "provider.messages.openai_compatible.no_stream result:", anthropicResponse);
|
|
5916
|
+
const response = c.json(anthropicResponse);
|
|
5917
|
+
instrumentation?.onComplete?.(normalizeOpenAIUsage(body.usage));
|
|
5918
|
+
return response;
|
|
5919
|
+
};
|
|
5920
|
+
const normalizeOpenAIUsage = (usage) => {
|
|
5921
|
+
const cacheCreationInputTokens = usage?.prompt_tokens_details?.cache_creation_input_tokens;
|
|
5922
|
+
const cacheReadInputTokens = usage?.prompt_tokens_details?.cached_tokens;
|
|
5923
|
+
return {
|
|
5924
|
+
inputTokens: usage?.prompt_tokens === void 0 ? void 0 : Math.max(0, usage.prompt_tokens - (cacheCreationInputTokens ?? 0) - (cacheReadInputTokens ?? 0)),
|
|
5925
|
+
outputTokens: usage?.completion_tokens,
|
|
5926
|
+
cacheCreationInputTokens,
|
|
5927
|
+
cacheReadInputTokens
|
|
5928
|
+
};
|
|
5929
|
+
};
|
|
5930
|
+
const normalizeAnthropicUsage = (usage) => ({
|
|
5931
|
+
inputTokens: usage?.input_tokens,
|
|
5932
|
+
outputTokens: usage?.output_tokens,
|
|
5933
|
+
cacheCreationInputTokens: usage?.cache_creation_input_tokens,
|
|
5934
|
+
cacheReadInputTokens: usage?.cache_read_input_tokens
|
|
5935
|
+
});
|
|
5936
|
+
const mergeAnthropicUsage = (current, next) => ({
|
|
5937
|
+
inputTokens: next.inputTokens ?? current.inputTokens,
|
|
5938
|
+
outputTokens: next.outputTokens ?? current.outputTokens,
|
|
5939
|
+
cacheCreationInputTokens: next.cacheCreationInputTokens ?? current.cacheCreationInputTokens,
|
|
5940
|
+
cacheReadInputTokens: next.cacheReadInputTokens ?? current.cacheReadInputTokens
|
|
5941
|
+
});
|
|
5942
|
+
const adjustInputTokens = (providerConfig, usage) => {
|
|
5943
|
+
if (!providerConfig.adjustInputTokens || !usage) return;
|
|
5944
|
+
usage.input_tokens = Math.max(0, (usage.input_tokens ?? 0) - (usage.cache_read_input_tokens ?? 0) - (usage.cache_creation_input_tokens ?? 0));
|
|
5945
|
+
debugJson(logger$4, "provider.messages.adjusted_usage:", usage);
|
|
5946
|
+
};
|
|
5947
|
+
//#endregion
|
|
5948
|
+
//#region src/routes/messages/responses-stream-translation.ts
|
|
5949
|
+
const MAX_CONSECUTIVE_FUNCTION_CALL_WHITESPACE = 20;
|
|
5950
|
+
var FunctionCallArgumentsValidationError = class extends Error {
|
|
5951
|
+
constructor(message) {
|
|
5952
|
+
super(message);
|
|
5953
|
+
this.name = "FunctionCallArgumentsValidationError";
|
|
5954
|
+
}
|
|
5955
|
+
};
|
|
5956
|
+
const updateWhitespaceRunState = (previousCount, chunk) => {
|
|
5957
|
+
let count = previousCount;
|
|
5958
|
+
for (const char of chunk) {
|
|
5959
|
+
if (char === "\r" || char === "\n" || char === " ") {
|
|
5960
|
+
count += 1;
|
|
5961
|
+
if (count > MAX_CONSECUTIVE_FUNCTION_CALL_WHITESPACE) return {
|
|
5962
|
+
nextCount: count,
|
|
5963
|
+
exceeded: true
|
|
5964
|
+
};
|
|
5965
|
+
continue;
|
|
5966
|
+
}
|
|
5967
|
+
if (char !== " ") count = 0;
|
|
5968
|
+
}
|
|
5969
|
+
return {
|
|
5970
|
+
nextCount: count,
|
|
5971
|
+
exceeded: false
|
|
5972
|
+
};
|
|
5973
|
+
};
|
|
5974
|
+
const createResponsesStreamState = () => ({
|
|
5975
|
+
messageStartSent: false,
|
|
5976
|
+
messageCompleted: false,
|
|
5977
|
+
nextContentBlockIndex: 0,
|
|
5978
|
+
blockIndexByKey: /* @__PURE__ */ new Map(),
|
|
5979
|
+
openBlocks: /* @__PURE__ */ new Set(),
|
|
5980
|
+
blockHasDelta: /* @__PURE__ */ new Set(),
|
|
5981
|
+
functionCallStateByOutputIndex: /* @__PURE__ */ new Map()
|
|
5982
|
+
});
|
|
5983
|
+
const translateResponsesStreamEvent = (rawEvent, state) => {
|
|
5984
|
+
switch (rawEvent.type) {
|
|
5985
|
+
case "response.created": return handleResponseCreated(rawEvent, state);
|
|
5986
|
+
case "response.output_item.added": return handleOutputItemAdded$1(rawEvent, state);
|
|
5987
|
+
case "response.reasoning_summary_text.delta": return handleReasoningSummaryTextDelta(rawEvent, state);
|
|
5988
|
+
case "response.output_text.delta": return handleOutputTextDelta(rawEvent, state);
|
|
5989
|
+
case "response.reasoning_summary_text.done": return handleReasoningSummaryTextDone(rawEvent, state);
|
|
5990
|
+
case "response.output_text.done": return handleOutputTextDone(rawEvent, state);
|
|
5991
|
+
case "response.output_item.done": return handleOutputItemDone$1(rawEvent, state);
|
|
5992
|
+
case "response.function_call_arguments.delta": return handleFunctionCallArgumentsDelta(rawEvent, state);
|
|
5993
|
+
case "response.function_call_arguments.done": return handleFunctionCallArgumentsDone(rawEvent, state);
|
|
5994
|
+
case "response.completed":
|
|
5995
|
+
case "response.incomplete": return handleResponseCompleted(rawEvent, state);
|
|
5996
|
+
case "response.failed": return handleResponseFailed(rawEvent, state);
|
|
5997
|
+
case "error": return handleErrorEvent(rawEvent, state);
|
|
5998
|
+
default: return [];
|
|
5999
|
+
}
|
|
6000
|
+
};
|
|
6001
|
+
const handleResponseCreated = (rawEvent, state) => {
|
|
6002
|
+
return messageStart(state, rawEvent.response);
|
|
6003
|
+
};
|
|
6004
|
+
const handleOutputItemAdded$1 = (rawEvent, state) => {
|
|
6005
|
+
const events = new Array();
|
|
6006
|
+
const functionCallDetails = extractFunctionCallDetails(rawEvent);
|
|
6007
|
+
if (!functionCallDetails) return events;
|
|
6008
|
+
const { outputIndex, toolCallId, name, initialArguments } = functionCallDetails;
|
|
6009
|
+
const blockIndex = openFunctionCallBlock(state, {
|
|
6010
|
+
outputIndex,
|
|
6011
|
+
toolCallId,
|
|
6012
|
+
name,
|
|
6013
|
+
events
|
|
6014
|
+
});
|
|
6015
|
+
if (initialArguments !== void 0 && initialArguments.length > 0) {
|
|
6016
|
+
events.push({
|
|
6017
|
+
type: "content_block_delta",
|
|
6018
|
+
index: blockIndex,
|
|
6019
|
+
delta: {
|
|
6020
|
+
type: "input_json_delta",
|
|
6021
|
+
partial_json: initialArguments
|
|
6022
|
+
}
|
|
6023
|
+
});
|
|
6024
|
+
state.blockHasDelta.add(blockIndex);
|
|
6025
|
+
}
|
|
6026
|
+
return events;
|
|
6027
|
+
};
|
|
6028
|
+
const handleOutputItemDone$1 = (rawEvent, state) => {
|
|
6029
|
+
const events = new Array();
|
|
6030
|
+
const item = rawEvent.item;
|
|
6031
|
+
const itemType = item.type;
|
|
6032
|
+
const outputIndex = rawEvent.output_index;
|
|
6033
|
+
if (itemType === "compaction") {
|
|
6034
|
+
if (!item.id || !item.encrypted_content) return events;
|
|
6035
|
+
const blockIndex = openThinkingBlockIfNeeded(state, outputIndex, events);
|
|
6036
|
+
if (!state.blockHasDelta.has(blockIndex)) events.push({
|
|
6037
|
+
type: "content_block_delta",
|
|
6038
|
+
index: blockIndex,
|
|
6039
|
+
delta: {
|
|
6040
|
+
type: "thinking_delta",
|
|
6041
|
+
thinking: THINKING_TEXT
|
|
6042
|
+
}
|
|
6043
|
+
});
|
|
6044
|
+
events.push({
|
|
6045
|
+
type: "content_block_delta",
|
|
6046
|
+
index: blockIndex,
|
|
4963
6047
|
delta: {
|
|
4964
6048
|
type: "signature_delta",
|
|
4965
6049
|
signature: encodeCompactionCarrierSignature({
|
|
@@ -4968,22 +6052,22 @@ const handleOutputItemDone$1 = (rawEvent, state$1) => {
|
|
|
4968
6052
|
})
|
|
4969
6053
|
}
|
|
4970
6054
|
});
|
|
4971
|
-
state
|
|
4972
|
-
return events
|
|
6055
|
+
state.blockHasDelta.add(blockIndex);
|
|
6056
|
+
return events;
|
|
4973
6057
|
}
|
|
4974
|
-
if (itemType !== "reasoning") return events
|
|
4975
|
-
const blockIndex = openThinkingBlockIfNeeded(state
|
|
6058
|
+
if (itemType !== "reasoning") return events;
|
|
6059
|
+
const blockIndex = openThinkingBlockIfNeeded(state, outputIndex, events);
|
|
4976
6060
|
const signature = (item.encrypted_content ?? "") + "@" + item.id;
|
|
4977
6061
|
if (signature) {
|
|
4978
|
-
if (!item.summary || item.summary.length === 0) events
|
|
6062
|
+
if (!item.summary || item.summary.length === 0) events.push({
|
|
4979
6063
|
type: "content_block_delta",
|
|
4980
6064
|
index: blockIndex,
|
|
4981
6065
|
delta: {
|
|
4982
6066
|
type: "thinking_delta",
|
|
4983
|
-
thinking: THINKING_TEXT
|
|
6067
|
+
thinking: THINKING_TEXT
|
|
4984
6068
|
}
|
|
4985
6069
|
});
|
|
4986
|
-
events
|
|
6070
|
+
events.push({
|
|
4987
6071
|
type: "content_block_delta",
|
|
4988
6072
|
index: blockIndex,
|
|
4989
6073
|
delta: {
|
|
@@ -4991,25 +6075,25 @@ const handleOutputItemDone$1 = (rawEvent, state$1) => {
|
|
|
4991
6075
|
signature
|
|
4992
6076
|
}
|
|
4993
6077
|
});
|
|
4994
|
-
state
|
|
6078
|
+
state.blockHasDelta.add(blockIndex);
|
|
4995
6079
|
}
|
|
4996
|
-
return events
|
|
6080
|
+
return events;
|
|
4997
6081
|
};
|
|
4998
|
-
const handleFunctionCallArgumentsDelta = (rawEvent, state
|
|
4999
|
-
const events
|
|
6082
|
+
const handleFunctionCallArgumentsDelta = (rawEvent, state) => {
|
|
6083
|
+
const events = new Array();
|
|
5000
6084
|
const outputIndex = rawEvent.output_index;
|
|
5001
6085
|
const deltaText = rawEvent.delta;
|
|
5002
|
-
if (!deltaText) return events
|
|
5003
|
-
const blockIndex = openFunctionCallBlock(state
|
|
6086
|
+
if (!deltaText) return events;
|
|
6087
|
+
const blockIndex = openFunctionCallBlock(state, {
|
|
5004
6088
|
outputIndex,
|
|
5005
|
-
events
|
|
6089
|
+
events
|
|
5006
6090
|
});
|
|
5007
|
-
const functionCallState = state
|
|
5008
|
-
if (!functionCallState) return handleFunctionCallArgumentsValidationError(new FunctionCallArgumentsValidationError("Received function call arguments delta without an open tool call block."), state
|
|
6091
|
+
const functionCallState = state.functionCallStateByOutputIndex.get(outputIndex);
|
|
6092
|
+
if (!functionCallState) return handleFunctionCallArgumentsValidationError(new FunctionCallArgumentsValidationError("Received function call arguments delta without an open tool call block."), state, events);
|
|
5009
6093
|
const { nextCount, exceeded } = updateWhitespaceRunState(functionCallState.consecutiveWhitespaceCount, deltaText);
|
|
5010
|
-
if (exceeded) return handleFunctionCallArgumentsValidationError(new FunctionCallArgumentsValidationError("Received function call arguments delta containing more than 20 consecutive whitespace characters."), state
|
|
6094
|
+
if (exceeded) return handleFunctionCallArgumentsValidationError(new FunctionCallArgumentsValidationError("Received function call arguments delta containing more than 20 consecutive whitespace characters."), state, events);
|
|
5011
6095
|
functionCallState.consecutiveWhitespaceCount = nextCount;
|
|
5012
|
-
events
|
|
6096
|
+
events.push({
|
|
5013
6097
|
type: "content_block_delta",
|
|
5014
6098
|
index: blockIndex,
|
|
5015
6099
|
delta: {
|
|
@@ -5017,19 +6101,19 @@ const handleFunctionCallArgumentsDelta = (rawEvent, state$1) => {
|
|
|
5017
6101
|
partial_json: deltaText
|
|
5018
6102
|
}
|
|
5019
6103
|
});
|
|
5020
|
-
state
|
|
5021
|
-
return events
|
|
6104
|
+
state.blockHasDelta.add(blockIndex);
|
|
6105
|
+
return events;
|
|
5022
6106
|
};
|
|
5023
|
-
const handleFunctionCallArgumentsDone = (rawEvent, state
|
|
5024
|
-
const events
|
|
6107
|
+
const handleFunctionCallArgumentsDone = (rawEvent, state) => {
|
|
6108
|
+
const events = new Array();
|
|
5025
6109
|
const outputIndex = rawEvent.output_index;
|
|
5026
|
-
const blockIndex = openFunctionCallBlock(state
|
|
6110
|
+
const blockIndex = openFunctionCallBlock(state, {
|
|
5027
6111
|
outputIndex,
|
|
5028
|
-
events
|
|
6112
|
+
events
|
|
5029
6113
|
});
|
|
5030
6114
|
const finalArguments = typeof rawEvent.arguments === "string" ? rawEvent.arguments : void 0;
|
|
5031
|
-
if (!state
|
|
5032
|
-
events
|
|
6115
|
+
if (!state.blockHasDelta.has(blockIndex) && finalArguments) {
|
|
6116
|
+
events.push({
|
|
5033
6117
|
type: "content_block_delta",
|
|
5034
6118
|
index: blockIndex,
|
|
5035
6119
|
delta: {
|
|
@@ -5037,23 +6121,23 @@ const handleFunctionCallArgumentsDone = (rawEvent, state$1) => {
|
|
|
5037
6121
|
partial_json: finalArguments
|
|
5038
6122
|
}
|
|
5039
6123
|
});
|
|
5040
|
-
state
|
|
6124
|
+
state.blockHasDelta.add(blockIndex);
|
|
5041
6125
|
}
|
|
5042
|
-
state
|
|
5043
|
-
return events
|
|
6126
|
+
state.functionCallStateByOutputIndex.delete(outputIndex);
|
|
6127
|
+
return events;
|
|
5044
6128
|
};
|
|
5045
|
-
const handleOutputTextDelta = (rawEvent, state
|
|
5046
|
-
const events
|
|
6129
|
+
const handleOutputTextDelta = (rawEvent, state) => {
|
|
6130
|
+
const events = new Array();
|
|
5047
6131
|
const outputIndex = rawEvent.output_index;
|
|
5048
6132
|
const contentIndex = rawEvent.content_index;
|
|
5049
6133
|
const deltaText = rawEvent.delta;
|
|
5050
|
-
if (!deltaText) return events
|
|
5051
|
-
const blockIndex = openTextBlockIfNeeded(state
|
|
6134
|
+
if (!deltaText) return events;
|
|
6135
|
+
const blockIndex = openTextBlockIfNeeded(state, {
|
|
5052
6136
|
outputIndex,
|
|
5053
6137
|
contentIndex,
|
|
5054
|
-
events
|
|
6138
|
+
events
|
|
5055
6139
|
});
|
|
5056
|
-
events
|
|
6140
|
+
events.push({
|
|
5057
6141
|
type: "content_block_delta",
|
|
5058
6142
|
index: blockIndex,
|
|
5059
6143
|
delta: {
|
|
@@ -5061,15 +6145,15 @@ const handleOutputTextDelta = (rawEvent, state$1) => {
|
|
|
5061
6145
|
text: deltaText
|
|
5062
6146
|
}
|
|
5063
6147
|
});
|
|
5064
|
-
state
|
|
5065
|
-
return events
|
|
6148
|
+
state.blockHasDelta.add(blockIndex);
|
|
6149
|
+
return events;
|
|
5066
6150
|
};
|
|
5067
|
-
const handleReasoningSummaryTextDelta = (rawEvent, state
|
|
6151
|
+
const handleReasoningSummaryTextDelta = (rawEvent, state) => {
|
|
5068
6152
|
const outputIndex = rawEvent.output_index;
|
|
5069
6153
|
const deltaText = rawEvent.delta;
|
|
5070
|
-
const events
|
|
5071
|
-
const blockIndex = openThinkingBlockIfNeeded(state
|
|
5072
|
-
events
|
|
6154
|
+
const events = new Array();
|
|
6155
|
+
const blockIndex = openThinkingBlockIfNeeded(state, outputIndex, events);
|
|
6156
|
+
events.push({
|
|
5073
6157
|
type: "content_block_delta",
|
|
5074
6158
|
index: blockIndex,
|
|
5075
6159
|
delta: {
|
|
@@ -5077,15 +6161,15 @@ const handleReasoningSummaryTextDelta = (rawEvent, state$1) => {
|
|
|
5077
6161
|
thinking: deltaText
|
|
5078
6162
|
}
|
|
5079
6163
|
});
|
|
5080
|
-
state
|
|
5081
|
-
return events
|
|
6164
|
+
state.blockHasDelta.add(blockIndex);
|
|
6165
|
+
return events;
|
|
5082
6166
|
};
|
|
5083
|
-
const handleReasoningSummaryTextDone = (rawEvent, state
|
|
6167
|
+
const handleReasoningSummaryTextDone = (rawEvent, state) => {
|
|
5084
6168
|
const outputIndex = rawEvent.output_index;
|
|
5085
6169
|
const text = rawEvent.text;
|
|
5086
|
-
const events
|
|
5087
|
-
const blockIndex = openThinkingBlockIfNeeded(state
|
|
5088
|
-
if (text && !state
|
|
6170
|
+
const events = new Array();
|
|
6171
|
+
const blockIndex = openThinkingBlockIfNeeded(state, outputIndex, events);
|
|
6172
|
+
if (text && !state.blockHasDelta.has(blockIndex)) events.push({
|
|
5089
6173
|
type: "content_block_delta",
|
|
5090
6174
|
index: blockIndex,
|
|
5091
6175
|
delta: {
|
|
@@ -5093,19 +6177,19 @@ const handleReasoningSummaryTextDone = (rawEvent, state$1) => {
|
|
|
5093
6177
|
thinking: text
|
|
5094
6178
|
}
|
|
5095
6179
|
});
|
|
5096
|
-
return events
|
|
6180
|
+
return events;
|
|
5097
6181
|
};
|
|
5098
|
-
const handleOutputTextDone = (rawEvent, state
|
|
5099
|
-
const events
|
|
6182
|
+
const handleOutputTextDone = (rawEvent, state) => {
|
|
6183
|
+
const events = new Array();
|
|
5100
6184
|
const outputIndex = rawEvent.output_index;
|
|
5101
6185
|
const contentIndex = rawEvent.content_index;
|
|
5102
6186
|
const text = rawEvent.text;
|
|
5103
|
-
const blockIndex = openTextBlockIfNeeded(state
|
|
6187
|
+
const blockIndex = openTextBlockIfNeeded(state, {
|
|
5104
6188
|
outputIndex,
|
|
5105
6189
|
contentIndex,
|
|
5106
|
-
events
|
|
6190
|
+
events
|
|
5107
6191
|
});
|
|
5108
|
-
if (text && !state
|
|
6192
|
+
if (text && !state.blockHasDelta.has(blockIndex)) events.push({
|
|
5109
6193
|
type: "content_block_delta",
|
|
5110
6194
|
index: blockIndex,
|
|
5111
6195
|
delta: {
|
|
@@ -5113,14 +6197,15 @@ const handleOutputTextDone = (rawEvent, state$1) => {
|
|
|
5113
6197
|
text
|
|
5114
6198
|
}
|
|
5115
6199
|
});
|
|
5116
|
-
return events
|
|
6200
|
+
return events;
|
|
5117
6201
|
};
|
|
5118
|
-
const handleResponseCompleted = (rawEvent, state
|
|
6202
|
+
const handleResponseCompleted = (rawEvent, state) => {
|
|
5119
6203
|
const response = rawEvent.response;
|
|
5120
|
-
const events
|
|
5121
|
-
closeAllOpenBlocks(state
|
|
6204
|
+
const events = new Array();
|
|
6205
|
+
closeAllOpenBlocks(state, events);
|
|
6206
|
+
state.responseStatus = response.status;
|
|
5122
6207
|
const anthropic = translateResponsesResultToAnthropic(response);
|
|
5123
|
-
events
|
|
6208
|
+
events.push({
|
|
5124
6209
|
type: "message_delta",
|
|
5125
6210
|
delta: {
|
|
5126
6211
|
stop_reason: anthropic.stop_reason,
|
|
@@ -5128,39 +6213,40 @@ const handleResponseCompleted = (rawEvent, state$1) => {
|
|
|
5128
6213
|
},
|
|
5129
6214
|
usage: anthropic.usage
|
|
5130
6215
|
}, { type: "message_stop" });
|
|
5131
|
-
state
|
|
5132
|
-
return events
|
|
6216
|
+
state.messageCompleted = true;
|
|
6217
|
+
return events;
|
|
5133
6218
|
};
|
|
5134
|
-
const handleResponseFailed = (rawEvent, state
|
|
6219
|
+
const handleResponseFailed = (rawEvent, state) => {
|
|
5135
6220
|
const response = rawEvent.response;
|
|
5136
|
-
const events
|
|
5137
|
-
closeAllOpenBlocks(state
|
|
6221
|
+
const events = new Array();
|
|
6222
|
+
closeAllOpenBlocks(state, events);
|
|
6223
|
+
state.responseStatus = response.status;
|
|
5138
6224
|
const message = response.error?.message ?? "The response failed due to an unknown error.";
|
|
5139
|
-
events
|
|
5140
|
-
state
|
|
5141
|
-
return events
|
|
6225
|
+
events.push(buildErrorEvent(message));
|
|
6226
|
+
state.messageCompleted = true;
|
|
6227
|
+
return events;
|
|
5142
6228
|
};
|
|
5143
|
-
const handleErrorEvent = (rawEvent, state
|
|
6229
|
+
const handleErrorEvent = (rawEvent, state) => {
|
|
5144
6230
|
const message = typeof rawEvent.message === "string" ? rawEvent.message : "An unexpected error occurred during streaming.";
|
|
5145
|
-
state
|
|
6231
|
+
state.messageCompleted = true;
|
|
5146
6232
|
return [buildErrorEvent(message)];
|
|
5147
6233
|
};
|
|
5148
|
-
const handleFunctionCallArgumentsValidationError = (error, state
|
|
6234
|
+
const handleFunctionCallArgumentsValidationError = (error, state, events = []) => {
|
|
5149
6235
|
const reason = error.message;
|
|
5150
|
-
closeAllOpenBlocks(state
|
|
5151
|
-
state
|
|
5152
|
-
events
|
|
5153
|
-
return events
|
|
6236
|
+
closeAllOpenBlocks(state, events);
|
|
6237
|
+
state.messageCompleted = true;
|
|
6238
|
+
events.push(buildErrorEvent(reason));
|
|
6239
|
+
return events;
|
|
5154
6240
|
};
|
|
5155
|
-
const messageStart = (state
|
|
5156
|
-
state
|
|
6241
|
+
const messageStart = (state, response) => {
|
|
6242
|
+
state.messageStartSent = true;
|
|
5157
6243
|
const inputCachedTokens = response.usage?.input_tokens_details?.cached_tokens;
|
|
5158
6244
|
const upstreamInputTokens = response.usage?.input_tokens;
|
|
5159
|
-
const historicalInputTokens = state
|
|
5160
|
-
const historicalOutputTokens = state
|
|
6245
|
+
const historicalInputTokens = state.historicalInputTokens;
|
|
6246
|
+
const historicalOutputTokens = state.historicalOutputTokens ?? 0;
|
|
5161
6247
|
const historicalTotalTokens = historicalInputTokens !== void 0 ? historicalInputTokens + historicalOutputTokens : void 0;
|
|
5162
|
-
const inputTokens = upstreamInputTokens !== void 0 ? upstreamInputTokens - (inputCachedTokens ?? 0) : historicalTotalTokens ?? state
|
|
5163
|
-
const cacheReadTokens = upstreamInputTokens !== void 0 ? inputCachedTokens ?? 0 : state
|
|
6248
|
+
const inputTokens = upstreamInputTokens !== void 0 ? upstreamInputTokens - (inputCachedTokens ?? 0) : historicalTotalTokens ?? state.estimatedInputTokens ?? 0;
|
|
6249
|
+
const cacheReadTokens = upstreamInputTokens !== void 0 ? inputCachedTokens ?? 0 : state.historicalCachedInputTokens ?? 0;
|
|
5164
6250
|
return [{
|
|
5165
6251
|
type: "message_start",
|
|
5166
6252
|
message: {
|
|
@@ -5179,18 +6265,18 @@ const messageStart = (state$1, response) => {
|
|
|
5179
6265
|
}
|
|
5180
6266
|
}];
|
|
5181
6267
|
};
|
|
5182
|
-
const openTextBlockIfNeeded = (state
|
|
5183
|
-
const { outputIndex, contentIndex, events
|
|
6268
|
+
const openTextBlockIfNeeded = (state, params) => {
|
|
6269
|
+
const { outputIndex, contentIndex, events } = params;
|
|
5184
6270
|
const key = getBlockKey(outputIndex, contentIndex);
|
|
5185
|
-
let blockIndex = state
|
|
6271
|
+
let blockIndex = state.blockIndexByKey.get(key);
|
|
5186
6272
|
if (blockIndex === void 0) {
|
|
5187
|
-
blockIndex = state
|
|
5188
|
-
state
|
|
5189
|
-
state
|
|
6273
|
+
blockIndex = state.nextContentBlockIndex;
|
|
6274
|
+
state.nextContentBlockIndex += 1;
|
|
6275
|
+
state.blockIndexByKey.set(key, blockIndex);
|
|
5190
6276
|
}
|
|
5191
|
-
if (!state
|
|
5192
|
-
closeOpenBlocks(state
|
|
5193
|
-
events
|
|
6277
|
+
if (!state.openBlocks.has(blockIndex)) {
|
|
6278
|
+
closeOpenBlocks(state, events);
|
|
6279
|
+
events.push({
|
|
5194
6280
|
type: "content_block_start",
|
|
5195
6281
|
index: blockIndex,
|
|
5196
6282
|
content_block: {
|
|
@@ -5198,21 +6284,21 @@ const openTextBlockIfNeeded = (state$1, params) => {
|
|
|
5198
6284
|
text: ""
|
|
5199
6285
|
}
|
|
5200
6286
|
});
|
|
5201
|
-
state
|
|
6287
|
+
state.openBlocks.add(blockIndex);
|
|
5202
6288
|
}
|
|
5203
6289
|
return blockIndex;
|
|
5204
6290
|
};
|
|
5205
|
-
const openThinkingBlockIfNeeded = (state
|
|
6291
|
+
const openThinkingBlockIfNeeded = (state, outputIndex, events) => {
|
|
5206
6292
|
const key = getBlockKey(outputIndex, 0);
|
|
5207
|
-
let blockIndex = state
|
|
6293
|
+
let blockIndex = state.blockIndexByKey.get(key);
|
|
5208
6294
|
if (blockIndex === void 0) {
|
|
5209
|
-
blockIndex = state
|
|
5210
|
-
state
|
|
5211
|
-
state
|
|
6295
|
+
blockIndex = state.nextContentBlockIndex;
|
|
6296
|
+
state.nextContentBlockIndex += 1;
|
|
6297
|
+
state.blockIndexByKey.set(key, blockIndex);
|
|
5212
6298
|
}
|
|
5213
|
-
if (!state
|
|
5214
|
-
closeOpenBlocks(state
|
|
5215
|
-
events
|
|
6299
|
+
if (!state.openBlocks.has(blockIndex)) {
|
|
6300
|
+
closeOpenBlocks(state, events);
|
|
6301
|
+
events.push({
|
|
5216
6302
|
type: "content_block_start",
|
|
5217
6303
|
index: blockIndex,
|
|
5218
6304
|
content_block: {
|
|
@@ -5220,25 +6306,25 @@ const openThinkingBlockIfNeeded = (state$1, outputIndex, events$1) => {
|
|
|
5220
6306
|
thinking: ""
|
|
5221
6307
|
}
|
|
5222
6308
|
});
|
|
5223
|
-
state
|
|
6309
|
+
state.openBlocks.add(blockIndex);
|
|
5224
6310
|
}
|
|
5225
6311
|
return blockIndex;
|
|
5226
6312
|
};
|
|
5227
|
-
const closeBlockIfOpen = (state
|
|
5228
|
-
if (!state
|
|
5229
|
-
events
|
|
6313
|
+
const closeBlockIfOpen = (state, blockIndex, events) => {
|
|
6314
|
+
if (!state.openBlocks.has(blockIndex)) return;
|
|
6315
|
+
events.push({
|
|
5230
6316
|
type: "content_block_stop",
|
|
5231
6317
|
index: blockIndex
|
|
5232
6318
|
});
|
|
5233
|
-
state
|
|
5234
|
-
state
|
|
6319
|
+
state.openBlocks.delete(blockIndex);
|
|
6320
|
+
state.blockHasDelta.delete(blockIndex);
|
|
5235
6321
|
};
|
|
5236
|
-
const closeOpenBlocks = (state
|
|
5237
|
-
for (const blockIndex of state
|
|
6322
|
+
const closeOpenBlocks = (state, events) => {
|
|
6323
|
+
for (const blockIndex of state.openBlocks) closeBlockIfOpen(state, blockIndex, events);
|
|
5238
6324
|
};
|
|
5239
|
-
const closeAllOpenBlocks = (state
|
|
5240
|
-
closeOpenBlocks(state
|
|
5241
|
-
state
|
|
6325
|
+
const closeAllOpenBlocks = (state, events) => {
|
|
6326
|
+
closeOpenBlocks(state, events);
|
|
6327
|
+
state.functionCallStateByOutputIndex.clear();
|
|
5242
6328
|
};
|
|
5243
6329
|
const buildErrorEvent = (message) => ({
|
|
5244
6330
|
type: "error",
|
|
@@ -5248,24 +6334,24 @@ const buildErrorEvent = (message) => ({
|
|
|
5248
6334
|
}
|
|
5249
6335
|
});
|
|
5250
6336
|
const getBlockKey = (outputIndex, contentIndex) => `${outputIndex}:${contentIndex}`;
|
|
5251
|
-
const openFunctionCallBlock = (state
|
|
5252
|
-
const { outputIndex, toolCallId, name, events
|
|
5253
|
-
let functionCallState = state
|
|
6337
|
+
const openFunctionCallBlock = (state, params) => {
|
|
6338
|
+
const { outputIndex, toolCallId, name, events } = params;
|
|
6339
|
+
let functionCallState = state.functionCallStateByOutputIndex.get(outputIndex);
|
|
5254
6340
|
if (!functionCallState) {
|
|
5255
|
-
const blockIndex
|
|
5256
|
-
state
|
|
6341
|
+
const blockIndex = state.nextContentBlockIndex;
|
|
6342
|
+
state.nextContentBlockIndex += 1;
|
|
5257
6343
|
functionCallState = {
|
|
5258
|
-
blockIndex
|
|
5259
|
-
toolCallId: toolCallId ?? `tool_call_${blockIndex
|
|
6344
|
+
blockIndex,
|
|
6345
|
+
toolCallId: toolCallId ?? `tool_call_${blockIndex}`,
|
|
5260
6346
|
name: name ?? "function",
|
|
5261
6347
|
consecutiveWhitespaceCount: 0
|
|
5262
6348
|
};
|
|
5263
|
-
state
|
|
6349
|
+
state.functionCallStateByOutputIndex.set(outputIndex, functionCallState);
|
|
5264
6350
|
}
|
|
5265
6351
|
const { blockIndex } = functionCallState;
|
|
5266
|
-
if (!state
|
|
5267
|
-
closeOpenBlocks(state
|
|
5268
|
-
events
|
|
6352
|
+
if (!state.openBlocks.has(blockIndex)) {
|
|
6353
|
+
closeOpenBlocks(state, events);
|
|
6354
|
+
events.push({
|
|
5269
6355
|
type: "content_block_start",
|
|
5270
6356
|
index: blockIndex,
|
|
5271
6357
|
content_block: {
|
|
@@ -5275,7 +6361,7 @@ const openFunctionCallBlock = (state$1, params) => {
|
|
|
5275
6361
|
input: {}
|
|
5276
6362
|
}
|
|
5277
6363
|
});
|
|
5278
|
-
state
|
|
6364
|
+
state.openBlocks.add(blockIndex);
|
|
5279
6365
|
}
|
|
5280
6366
|
return blockIndex;
|
|
5281
6367
|
};
|
|
@@ -5289,7 +6375,6 @@ const extractFunctionCallDetails = (rawEvent) => {
|
|
|
5289
6375
|
initialArguments: item.arguments
|
|
5290
6376
|
};
|
|
5291
6377
|
};
|
|
5292
|
-
|
|
5293
6378
|
//#endregion
|
|
5294
6379
|
//#region src/routes/responses/utils.ts
|
|
5295
6380
|
const getResponsesRequestOptions = (payload) => {
|
|
@@ -5380,7 +6465,7 @@ function getStreamChunkFields(chunk) {
|
|
|
5380
6465
|
data: c.data
|
|
5381
6466
|
};
|
|
5382
6467
|
}
|
|
5383
|
-
const isAsyncIterable = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
|
|
6468
|
+
const isAsyncIterable$1 = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
|
|
5384
6469
|
const containsVisionContent = (value) => {
|
|
5385
6470
|
if (!value) return false;
|
|
5386
6471
|
if (Array.isArray(value)) return value.some((entry) => containsVisionContent(entry));
|
|
@@ -5390,7 +6475,6 @@ const containsVisionContent = (value) => {
|
|
|
5390
6475
|
if (Array.isArray(record.content)) return record.content.some((entry) => containsVisionContent(entry));
|
|
5391
6476
|
return false;
|
|
5392
6477
|
};
|
|
5393
|
-
|
|
5394
6478
|
//#endregion
|
|
5395
6479
|
//#region src/services/copilot/create-messages.ts
|
|
5396
6480
|
const isAgentMessage = (msg) => {
|
|
@@ -5445,305 +6529,44 @@ const buildMessagesHeaders = ({ ctx, enableVision, initiator, options, payload }
|
|
|
5445
6529
|
isSubagent: Boolean(options?.subagentMarker)
|
|
5446
6530
|
});
|
|
5447
6531
|
const headers = {
|
|
5448
|
-
...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
|
|
5449
|
-
"x-initiator": effectiveInitiator
|
|
5450
|
-
};
|
|
5451
|
-
prepareInteractionHeaders(options?.sessionId, Boolean(options?.subagentMarker), headers);
|
|
5452
|
-
prepareForCompact(headers, options?.compactType);
|
|
5453
|
-
if (shouldUseMessageProxyHeaders(payload)) prepareMessageProxyHeaders(headers);
|
|
5454
|
-
const anthropicBeta = buildAnthropicBetaHeader(options?.anthropicBetaHeader, payload.thinking, payload.model);
|
|
5455
|
-
if (anthropicBeta) headers["anthropic-beta"] = anthropicBeta;
|
|
5456
|
-
return headers;
|
|
5457
|
-
};
|
|
5458
|
-
const createMessages = async (payload, account, options) => {
|
|
5459
|
-
const ctx = account ?? accountFromState();
|
|
5460
|
-
if (!ctx.copilotToken) throw new Error("Copilot token not found");
|
|
5461
|
-
const headers = buildMessagesHeaders({
|
|
5462
|
-
ctx,
|
|
5463
|
-
enableVision: hasVisionInput(payload),
|
|
5464
|
-
initiator: options?.initiator ?? getMessagesInitiator(payload),
|
|
5465
|
-
options,
|
|
5466
|
-
payload
|
|
5467
|
-
});
|
|
5468
|
-
captureOutboundHeadersSnapshot(headers);
|
|
5469
|
-
const response = await copilotFetch(`${copilotBaseUrl(ctx)}/v1/messages`, {
|
|
5470
|
-
method: "POST",
|
|
5471
|
-
headers,
|
|
5472
|
-
body: JSON.stringify(payload)
|
|
5473
|
-
}, {
|
|
5474
|
-
requestId: options?.requestId,
|
|
5475
|
-
callSite: "messages"
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
if (payload.stream) return events(response);
|
|
5483
|
-
return await response.json();
|
|
5484
|
-
};
|
|
5485
|
-
|
|
5486
|
-
//#endregion
|
|
5487
|
-
//#region src/routes/messages/stream-translation.ts
|
|
5488
|
-
function isToolBlockOpen(state$1) {
|
|
5489
|
-
if (!state$1.contentBlockOpen) return false;
|
|
5490
|
-
return Object.values(state$1.toolCalls).some((tc) => tc.anthropicBlockIndex === state$1.contentBlockIndex);
|
|
5491
|
-
}
|
|
5492
|
-
function translateChunkToAnthropicEvents(chunk, state$1) {
|
|
5493
|
-
const events$1 = [];
|
|
5494
|
-
if (chunk.choices.length === 0) return events$1;
|
|
5495
|
-
const choice = chunk.choices[0];
|
|
5496
|
-
const { delta } = choice;
|
|
5497
|
-
handleMessageStart(state$1, events$1, chunk);
|
|
5498
|
-
handleThinkingText(delta, state$1, events$1);
|
|
5499
|
-
handleContent(delta, state$1, events$1);
|
|
5500
|
-
handleToolCalls(delta, state$1, events$1);
|
|
5501
|
-
handleFinish(choice, state$1, {
|
|
5502
|
-
events: events$1,
|
|
5503
|
-
chunk
|
|
5504
|
-
});
|
|
5505
|
-
return events$1;
|
|
5506
|
-
}
|
|
5507
|
-
function handleFinish(choice, state$1, context) {
|
|
5508
|
-
const { events: events$1, chunk } = context;
|
|
5509
|
-
if (choice.finish_reason && choice.finish_reason.length > 0) {
|
|
5510
|
-
if (state$1.contentBlockOpen) {
|
|
5511
|
-
const toolBlockOpen = isToolBlockOpen(state$1);
|
|
5512
|
-
context.events.push({
|
|
5513
|
-
type: "content_block_stop",
|
|
5514
|
-
index: state$1.contentBlockIndex
|
|
5515
|
-
});
|
|
5516
|
-
state$1.contentBlockOpen = false;
|
|
5517
|
-
state$1.contentBlockIndex++;
|
|
5518
|
-
if (!toolBlockOpen) handleReasoningOpaque(choice.delta, events$1, state$1);
|
|
5519
|
-
}
|
|
5520
|
-
events$1.push({
|
|
5521
|
-
type: "message_delta",
|
|
5522
|
-
delta: {
|
|
5523
|
-
stop_reason: mapOpenAIStopReasonToAnthropic(choice.finish_reason),
|
|
5524
|
-
stop_sequence: null
|
|
5525
|
-
},
|
|
5526
|
-
usage: {
|
|
5527
|
-
input_tokens: (chunk.usage?.prompt_tokens ?? 0) - (chunk.usage?.prompt_tokens_details?.cached_tokens ?? 0),
|
|
5528
|
-
output_tokens: chunk.usage?.completion_tokens ?? 0,
|
|
5529
|
-
...chunk.usage?.prompt_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: chunk.usage.prompt_tokens_details.cached_tokens }
|
|
5530
|
-
}
|
|
5531
|
-
}, { type: "message_stop" });
|
|
5532
|
-
}
|
|
5533
|
-
}
|
|
5534
|
-
function handleToolCalls(delta, state$1, events$1) {
|
|
5535
|
-
if (delta.tool_calls && delta.tool_calls.length > 0) {
|
|
5536
|
-
closeThinkingBlockIfOpen(state$1, events$1);
|
|
5537
|
-
handleReasoningOpaqueInToolCalls(state$1, events$1, delta);
|
|
5538
|
-
for (const toolCall of delta.tool_calls) {
|
|
5539
|
-
if (toolCall.id && toolCall.function?.name) {
|
|
5540
|
-
if (state$1.contentBlockOpen) {
|
|
5541
|
-
events$1.push({
|
|
5542
|
-
type: "content_block_stop",
|
|
5543
|
-
index: state$1.contentBlockIndex
|
|
5544
|
-
});
|
|
5545
|
-
state$1.contentBlockIndex++;
|
|
5546
|
-
state$1.contentBlockOpen = false;
|
|
5547
|
-
}
|
|
5548
|
-
const anthropicBlockIndex = state$1.contentBlockIndex;
|
|
5549
|
-
state$1.toolCalls[toolCall.index] = {
|
|
5550
|
-
id: toolCall.id,
|
|
5551
|
-
name: toolCall.function.name,
|
|
5552
|
-
anthropicBlockIndex
|
|
5553
|
-
};
|
|
5554
|
-
events$1.push({
|
|
5555
|
-
type: "content_block_start",
|
|
5556
|
-
index: anthropicBlockIndex,
|
|
5557
|
-
content_block: {
|
|
5558
|
-
type: "tool_use",
|
|
5559
|
-
id: toolCall.id,
|
|
5560
|
-
name: toolCall.function.name,
|
|
5561
|
-
input: {}
|
|
5562
|
-
}
|
|
5563
|
-
});
|
|
5564
|
-
state$1.contentBlockOpen = true;
|
|
5565
|
-
}
|
|
5566
|
-
if (toolCall.function?.arguments) {
|
|
5567
|
-
const toolCallInfo = state$1.toolCalls[toolCall.index];
|
|
5568
|
-
if (toolCallInfo) events$1.push({
|
|
5569
|
-
type: "content_block_delta",
|
|
5570
|
-
index: toolCallInfo.anthropicBlockIndex,
|
|
5571
|
-
delta: {
|
|
5572
|
-
type: "input_json_delta",
|
|
5573
|
-
partial_json: toolCall.function.arguments
|
|
5574
|
-
}
|
|
5575
|
-
});
|
|
5576
|
-
}
|
|
5577
|
-
}
|
|
5578
|
-
}
|
|
5579
|
-
}
|
|
5580
|
-
function handleReasoningOpaqueInToolCalls(state$1, events$1, delta) {
|
|
5581
|
-
if (state$1.contentBlockOpen && !isToolBlockOpen(state$1)) {
|
|
5582
|
-
events$1.push({
|
|
5583
|
-
type: "content_block_stop",
|
|
5584
|
-
index: state$1.contentBlockIndex
|
|
5585
|
-
});
|
|
5586
|
-
state$1.contentBlockIndex++;
|
|
5587
|
-
state$1.contentBlockOpen = false;
|
|
5588
|
-
}
|
|
5589
|
-
handleReasoningOpaque(delta, events$1, state$1);
|
|
5590
|
-
}
|
|
5591
|
-
function handleContent(delta, state$1, events$1) {
|
|
5592
|
-
if (delta.content && delta.content.length > 0) {
|
|
5593
|
-
closeThinkingBlockIfOpen(state$1, events$1);
|
|
5594
|
-
if (isToolBlockOpen(state$1)) {
|
|
5595
|
-
events$1.push({
|
|
5596
|
-
type: "content_block_stop",
|
|
5597
|
-
index: state$1.contentBlockIndex
|
|
5598
|
-
});
|
|
5599
|
-
state$1.contentBlockIndex++;
|
|
5600
|
-
state$1.contentBlockOpen = false;
|
|
5601
|
-
}
|
|
5602
|
-
if (!state$1.contentBlockOpen) {
|
|
5603
|
-
events$1.push({
|
|
5604
|
-
type: "content_block_start",
|
|
5605
|
-
index: state$1.contentBlockIndex,
|
|
5606
|
-
content_block: {
|
|
5607
|
-
type: "text",
|
|
5608
|
-
text: ""
|
|
5609
|
-
}
|
|
5610
|
-
});
|
|
5611
|
-
state$1.contentBlockOpen = true;
|
|
5612
|
-
}
|
|
5613
|
-
events$1.push({
|
|
5614
|
-
type: "content_block_delta",
|
|
5615
|
-
index: state$1.contentBlockIndex,
|
|
5616
|
-
delta: {
|
|
5617
|
-
type: "text_delta",
|
|
5618
|
-
text: delta.content
|
|
5619
|
-
}
|
|
5620
|
-
});
|
|
5621
|
-
}
|
|
5622
|
-
if (delta.content === "" && delta.reasoning_opaque && delta.reasoning_opaque.length > 0 && state$1.thinkingBlockOpen) {
|
|
5623
|
-
events$1.push({
|
|
5624
|
-
type: "content_block_delta",
|
|
5625
|
-
index: state$1.contentBlockIndex,
|
|
5626
|
-
delta: {
|
|
5627
|
-
type: "signature_delta",
|
|
5628
|
-
signature: delta.reasoning_opaque
|
|
5629
|
-
}
|
|
5630
|
-
}, {
|
|
5631
|
-
type: "content_block_stop",
|
|
5632
|
-
index: state$1.contentBlockIndex
|
|
5633
|
-
});
|
|
5634
|
-
state$1.contentBlockIndex++;
|
|
5635
|
-
state$1.thinkingBlockOpen = false;
|
|
5636
|
-
}
|
|
5637
|
-
}
|
|
5638
|
-
function handleMessageStart(state$1, events$1, chunk) {
|
|
5639
|
-
if (!state$1.messageStartSent) {
|
|
5640
|
-
const cachedTokens = chunk.usage?.prompt_tokens_details?.cached_tokens;
|
|
5641
|
-
const upstreamPromptTokens = chunk.usage?.prompt_tokens;
|
|
5642
|
-
const historicalInputTokens = state$1.historicalInputTokens;
|
|
5643
|
-
const historicalOutputTokens = state$1.historicalOutputTokens ?? 0;
|
|
5644
|
-
const historicalTotalTokens = historicalInputTokens !== void 0 ? historicalInputTokens + historicalOutputTokens : void 0;
|
|
5645
|
-
const inputTokens = upstreamPromptTokens !== void 0 ? upstreamPromptTokens - (cachedTokens ?? 0) : historicalTotalTokens ?? state$1.estimatedInputTokens ?? 0;
|
|
5646
|
-
const cacheReadTokens = upstreamPromptTokens !== void 0 ? cachedTokens : state$1.historicalCachedInputTokens;
|
|
5647
|
-
events$1.push({
|
|
5648
|
-
type: "message_start",
|
|
5649
|
-
message: {
|
|
5650
|
-
id: chunk.id,
|
|
5651
|
-
type: "message",
|
|
5652
|
-
role: "assistant",
|
|
5653
|
-
content: [],
|
|
5654
|
-
model: chunk.model,
|
|
5655
|
-
stop_reason: null,
|
|
5656
|
-
stop_sequence: null,
|
|
5657
|
-
usage: {
|
|
5658
|
-
input_tokens: inputTokens,
|
|
5659
|
-
output_tokens: 0,
|
|
5660
|
-
...cacheReadTokens !== void 0 && { cache_read_input_tokens: cacheReadTokens }
|
|
5661
|
-
}
|
|
5662
|
-
}
|
|
5663
|
-
});
|
|
5664
|
-
state$1.messageStartSent = true;
|
|
5665
|
-
}
|
|
5666
|
-
}
|
|
5667
|
-
function handleReasoningOpaque(delta, events$1, state$1) {
|
|
5668
|
-
if (delta.reasoning_opaque && delta.reasoning_opaque.length > 0) {
|
|
5669
|
-
events$1.push({
|
|
5670
|
-
type: "content_block_start",
|
|
5671
|
-
index: state$1.contentBlockIndex,
|
|
5672
|
-
content_block: {
|
|
5673
|
-
type: "thinking",
|
|
5674
|
-
thinking: ""
|
|
5675
|
-
}
|
|
5676
|
-
}, {
|
|
5677
|
-
type: "content_block_delta",
|
|
5678
|
-
index: state$1.contentBlockIndex,
|
|
5679
|
-
delta: {
|
|
5680
|
-
type: "thinking_delta",
|
|
5681
|
-
thinking: THINKING_TEXT
|
|
5682
|
-
}
|
|
5683
|
-
}, {
|
|
5684
|
-
type: "content_block_delta",
|
|
5685
|
-
index: state$1.contentBlockIndex,
|
|
5686
|
-
delta: {
|
|
5687
|
-
type: "signature_delta",
|
|
5688
|
-
signature: delta.reasoning_opaque
|
|
5689
|
-
}
|
|
5690
|
-
}, {
|
|
5691
|
-
type: "content_block_stop",
|
|
5692
|
-
index: state$1.contentBlockIndex
|
|
5693
|
-
});
|
|
5694
|
-
state$1.contentBlockIndex++;
|
|
5695
|
-
}
|
|
5696
|
-
}
|
|
5697
|
-
function handleThinkingText(delta, state$1, events$1) {
|
|
5698
|
-
if (delta.reasoning_text && delta.reasoning_text.length > 0) {
|
|
5699
|
-
if (state$1.contentBlockOpen) {
|
|
5700
|
-
delta.content = delta.reasoning_text;
|
|
5701
|
-
delta.reasoning_text = void 0;
|
|
5702
|
-
return;
|
|
5703
|
-
}
|
|
5704
|
-
if (!state$1.thinkingBlockOpen) {
|
|
5705
|
-
events$1.push({
|
|
5706
|
-
type: "content_block_start",
|
|
5707
|
-
index: state$1.contentBlockIndex,
|
|
5708
|
-
content_block: {
|
|
5709
|
-
type: "thinking",
|
|
5710
|
-
thinking: ""
|
|
5711
|
-
}
|
|
5712
|
-
});
|
|
5713
|
-
state$1.thinkingBlockOpen = true;
|
|
5714
|
-
}
|
|
5715
|
-
events$1.push({
|
|
5716
|
-
type: "content_block_delta",
|
|
5717
|
-
index: state$1.contentBlockIndex,
|
|
5718
|
-
delta: {
|
|
5719
|
-
type: "thinking_delta",
|
|
5720
|
-
thinking: delta.reasoning_text
|
|
5721
|
-
}
|
|
5722
|
-
});
|
|
5723
|
-
}
|
|
5724
|
-
}
|
|
5725
|
-
function closeThinkingBlockIfOpen(state$1, events$1) {
|
|
5726
|
-
if (state$1.thinkingBlockOpen) {
|
|
5727
|
-
events$1.push({
|
|
5728
|
-
type: "content_block_delta",
|
|
5729
|
-
index: state$1.contentBlockIndex,
|
|
5730
|
-
delta: {
|
|
5731
|
-
type: "signature_delta",
|
|
5732
|
-
signature: ""
|
|
5733
|
-
}
|
|
5734
|
-
}, {
|
|
5735
|
-
type: "content_block_stop",
|
|
5736
|
-
index: state$1.contentBlockIndex
|
|
5737
|
-
});
|
|
5738
|
-
state$1.contentBlockIndex++;
|
|
5739
|
-
state$1.thinkingBlockOpen = false;
|
|
6532
|
+
...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
|
|
6533
|
+
"x-initiator": effectiveInitiator
|
|
6534
|
+
};
|
|
6535
|
+
prepareInteractionHeaders(options?.sessionId, Boolean(options?.subagentMarker), headers);
|
|
6536
|
+
prepareForCompact(headers, options?.compactType);
|
|
6537
|
+
if (shouldUseMessageProxyHeaders(payload)) prepareMessageProxyHeaders(headers);
|
|
6538
|
+
const anthropicBeta = buildAnthropicBetaHeader(options?.anthropicBetaHeader, payload.thinking, payload.model);
|
|
6539
|
+
if (anthropicBeta) headers["anthropic-beta"] = anthropicBeta;
|
|
6540
|
+
return headers;
|
|
6541
|
+
};
|
|
6542
|
+
const createMessages = async (payload, account, options) => {
|
|
6543
|
+
const ctx = account ?? accountFromState();
|
|
6544
|
+
if (!ctx.copilotToken) throw new Error("Copilot token not found");
|
|
6545
|
+
const headers = buildMessagesHeaders({
|
|
6546
|
+
ctx,
|
|
6547
|
+
enableVision: hasVisionInput(payload),
|
|
6548
|
+
initiator: options?.initiator ?? getMessagesInitiator(payload),
|
|
6549
|
+
options,
|
|
6550
|
+
payload
|
|
6551
|
+
});
|
|
6552
|
+
captureOutboundHeadersSnapshot(headers);
|
|
6553
|
+
const response = await copilotFetch(`${copilotBaseUrl(ctx)}/v1/messages`, {
|
|
6554
|
+
method: "POST",
|
|
6555
|
+
headers,
|
|
6556
|
+
body: JSON.stringify(payload)
|
|
6557
|
+
}, {
|
|
6558
|
+
requestId: options?.requestId,
|
|
6559
|
+
callSite: "messages",
|
|
6560
|
+
fetchImpl: options?.fetchImpl
|
|
6561
|
+
});
|
|
6562
|
+
logCopilotRateLimits(response.headers);
|
|
6563
|
+
if (!response.ok) {
|
|
6564
|
+
consola.error("Failed to create messages", response);
|
|
6565
|
+
throw new HTTPError("Failed to create messages", response);
|
|
5740
6566
|
}
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
//#region src/lib/subagent.ts
|
|
5745
|
-
const subagentMarkerPrefix = "__SUBAGENT_MARKER__";
|
|
5746
|
-
|
|
6567
|
+
if (payload.stream) return events(response);
|
|
6568
|
+
return await response.json();
|
|
6569
|
+
};
|
|
5747
6570
|
//#endregion
|
|
5748
6571
|
//#region src/routes/messages/subagent-marker.ts
|
|
5749
6572
|
const subagentStartContextPrefix = "SubagentStart hook additional context:";
|
|
@@ -5778,8 +6601,8 @@ const extractMarkerPayloadFromReminderLine = (line) => {
|
|
|
5778
6601
|
if (!trimmedLine) return null;
|
|
5779
6602
|
let markerLine = trimmedLine;
|
|
5780
6603
|
if (markerLine.startsWith(subagentStartContextPrefix)) markerLine = markerLine.slice(38).trimStart();
|
|
5781
|
-
if (!markerLine.startsWith(
|
|
5782
|
-
return markerLine.slice(
|
|
6604
|
+
if (!markerLine.startsWith("__SUBAGENT_MARKER__")) return null;
|
|
6605
|
+
return markerLine.slice(19).trimStart();
|
|
5783
6606
|
};
|
|
5784
6607
|
const inspectSubagentMarkerFromSystemReminder = (text) => {
|
|
5785
6608
|
let sawInvalidMarker = false;
|
|
@@ -5848,32 +6671,127 @@ const extractBalancedJson = (text) => {
|
|
|
5848
6671
|
}
|
|
5849
6672
|
return null;
|
|
5850
6673
|
};
|
|
5851
|
-
|
|
5852
6674
|
//#endregion
|
|
5853
6675
|
//#region src/routes/messages/handler.ts
|
|
5854
|
-
const logger$
|
|
6676
|
+
const logger$3 = createHandlerLogger("messages-handler");
|
|
5855
6677
|
const CHAT_COMPLETIONS_ENDPOINT = "/chat/completions";
|
|
5856
6678
|
const RESPONSES_ENDPOINT$1 = "/responses";
|
|
5857
6679
|
const MESSAGES_ENDPOINT = "/v1/messages";
|
|
6680
|
+
function normalizeProviderAliasUsage(usage) {
|
|
6681
|
+
const tokensInput = usage.inputTokens === void 0 ? void 0 : Math.max(0, usage.inputTokens);
|
|
6682
|
+
const tokensCachedInput = usage.cacheReadInputTokens;
|
|
6683
|
+
const tokensTotal = usage.inputTokens === void 0 && usage.outputTokens === void 0 ? void 0 : (tokensInput ?? 0) + (usage.outputTokens ?? 0) + (usage.cacheCreationInputTokens ?? 0) + (tokensCachedInput ?? 0);
|
|
6684
|
+
return {
|
|
6685
|
+
tokensCachedInput,
|
|
6686
|
+
tokensInput,
|
|
6687
|
+
tokensOutput: usage.outputTokens,
|
|
6688
|
+
tokensTotal,
|
|
6689
|
+
usageJson: JSON.stringify({
|
|
6690
|
+
input_tokens: usage.inputTokens,
|
|
6691
|
+
output_tokens: usage.outputTokens,
|
|
6692
|
+
cache_creation_input_tokens: usage.cacheCreationInputTokens,
|
|
6693
|
+
cache_read_input_tokens: usage.cacheReadInputTokens
|
|
6694
|
+
})
|
|
6695
|
+
};
|
|
6696
|
+
}
|
|
6697
|
+
async function handleProviderAliasCompletion(c, options) {
|
|
6698
|
+
const { payload, provider, providerModel } = options;
|
|
6699
|
+
const requestId = randomUUID();
|
|
6700
|
+
const startedAtMs = Date.now();
|
|
6701
|
+
const method = c.req.raw.method;
|
|
6702
|
+
const path = new URL(c.req.url, "http://local").pathname;
|
|
6703
|
+
const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
|
|
6704
|
+
const userAgent = c.req.header("user-agent") ?? void 0;
|
|
6705
|
+
const streamRequested = Boolean(payload.stream);
|
|
6706
|
+
const originalModel = payload.model;
|
|
6707
|
+
const rawUserId = payload.metadata?.user_id;
|
|
6708
|
+
const userId = typeof rawUserId === "string" ? rawUserId : void 0;
|
|
6709
|
+
const { safetyIdentifier, sessionId: promptCacheKey } = parseUserIdMetadata(userId);
|
|
6710
|
+
const isSubagent = inspectSubagentMarkerFromFirstUser(payload).kind === "valid";
|
|
6711
|
+
let requestRecorded = false;
|
|
6712
|
+
const insertProviderAliasLog = (record) => {
|
|
6713
|
+
if (requestRecorded) {
|
|
6714
|
+
logger$3.warn("provider alias request already recorded", { requestId });
|
|
6715
|
+
return;
|
|
6716
|
+
}
|
|
6717
|
+
requestRecorded = true;
|
|
6718
|
+
const finishedAtMs = Date.now();
|
|
6719
|
+
getRequestHistoryStore().insert({
|
|
6720
|
+
requestId,
|
|
6721
|
+
startedAtMs,
|
|
6722
|
+
finishedAtMs,
|
|
6723
|
+
durationMs: finishedAtMs - startedAtMs,
|
|
6724
|
+
method,
|
|
6725
|
+
path,
|
|
6726
|
+
clientIp,
|
|
6727
|
+
clientIpSource,
|
|
6728
|
+
userAgent,
|
|
6729
|
+
userId,
|
|
6730
|
+
safetyIdentifier: safetyIdentifier ?? void 0,
|
|
6731
|
+
promptCacheKey: promptCacheKey ?? void 0,
|
|
6732
|
+
isSubagent,
|
|
6733
|
+
clientModel: originalModel,
|
|
6734
|
+
upstreamEndpoint: `/providers/${provider}/messages`,
|
|
6735
|
+
stream: streamRequested,
|
|
6736
|
+
upstreamModel: providerModel,
|
|
6737
|
+
...record
|
|
6738
|
+
});
|
|
6739
|
+
};
|
|
6740
|
+
const instrumentation = {
|
|
6741
|
+
onComplete: (usage) => {
|
|
6742
|
+
insertProviderAliasLog({
|
|
6743
|
+
...normalizeProviderAliasUsage(usage),
|
|
6744
|
+
httpStatus: 200
|
|
6745
|
+
});
|
|
6746
|
+
},
|
|
6747
|
+
onError: (error) => {
|
|
6748
|
+
insertProviderAliasLog({
|
|
6749
|
+
httpStatus: error.httpStatus,
|
|
6750
|
+
errorName: error.errorName,
|
|
6751
|
+
errorStatus: error.errorStatus,
|
|
6752
|
+
errorMessage: error.errorMessage,
|
|
6753
|
+
upstreamErrorMessageRaw: error.upstreamErrorMessageRaw
|
|
6754
|
+
});
|
|
6755
|
+
}
|
|
6756
|
+
};
|
|
6757
|
+
payload.model = providerModel;
|
|
6758
|
+
try {
|
|
6759
|
+
return await handleProviderMessagesForProvider(c, {
|
|
6760
|
+
instrumentation,
|
|
6761
|
+
payload,
|
|
6762
|
+
provider
|
|
6763
|
+
});
|
|
6764
|
+
} catch (error) {
|
|
6765
|
+
const observableError = await extractErrorObservability(error);
|
|
6766
|
+
instrumentation.onError?.(observableError);
|
|
6767
|
+
throw error;
|
|
6768
|
+
}
|
|
6769
|
+
}
|
|
5858
6770
|
async function handleCompletion(c) {
|
|
6771
|
+
const anthropicPayload = await c.req.json();
|
|
6772
|
+
const providerModelAlias = parseProviderModelAlias(anthropicPayload.model);
|
|
6773
|
+
if (providerModelAlias) return await handleProviderAliasCompletion(c, {
|
|
6774
|
+
payload: anthropicPayload,
|
|
6775
|
+
provider: providerModelAlias.provider,
|
|
6776
|
+
providerModel: providerModelAlias.model
|
|
6777
|
+
});
|
|
5859
6778
|
await checkRateLimit(state);
|
|
5860
6779
|
const store = getRequestHistoryStore();
|
|
5861
6780
|
const requestId = randomUUID();
|
|
5862
6781
|
const startedAtMs = Date.now();
|
|
5863
6782
|
const method = c.req.raw.method;
|
|
5864
|
-
const path
|
|
6783
|
+
const path = new URL(c.req.url, "http://local").pathname;
|
|
5865
6784
|
const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
|
|
5866
6785
|
const userAgent = c.req.header("user-agent") ?? void 0;
|
|
5867
|
-
const anthropicPayload = await c.req.json();
|
|
5868
6786
|
sanitizeIdeTools(anthropicPayload);
|
|
5869
|
-
debugJson(logger$
|
|
6787
|
+
debugJson(logger$3, "Anthropic request payload:", anthropicPayload);
|
|
5870
6788
|
const markerInspection = inspectSubagentMarkerFromFirstUser(anthropicPayload);
|
|
5871
6789
|
const subagentMarker = markerInspection.kind === "valid" ? markerInspection.marker : null;
|
|
5872
6790
|
const isSubagentRequest = subagentMarker !== null;
|
|
5873
6791
|
const invalidSubagentMarkerSelectionReason = markerInspection.kind === "invalid" ? "subagent_marker_invalid_fallback" : void 0;
|
|
5874
|
-
if (subagentMarker) debugJson(logger$
|
|
6792
|
+
if (subagentMarker) debugJson(logger$3, "Detected Subagent marker:", subagentMarker);
|
|
5875
6793
|
const sessionId = getRootSessionId(anthropicPayload, c);
|
|
5876
|
-
logger$
|
|
6794
|
+
logger$3.debug("Extracted session ID:", sessionId);
|
|
5877
6795
|
const ownershipLookupSessionId = markerInspection.kind === "valid" ? normalizeStableSessionId(markerInspection.marker.session_id) : void 0;
|
|
5878
6796
|
const ownershipWriteSessionId = markerInspection.kind === "none" ? sessionId : void 0;
|
|
5879
6797
|
const anthropicBeta = c.req.header("anthropic-beta");
|
|
@@ -5881,14 +6799,14 @@ async function handleCompletion(c) {
|
|
|
5881
6799
|
const isCompact = compactType !== 0;
|
|
5882
6800
|
const originalRequestModel = anthropicPayload.model;
|
|
5883
6801
|
if (anthropicBeta && isWarmupProbeRequest(anthropicPayload)) anthropicPayload.model = getSmallModel();
|
|
5884
|
-
if (compactType !== 0) logger$
|
|
5885
|
-
if (compactType ===
|
|
6802
|
+
if (compactType !== 0) logger$3.debug("Compact request type:", compactType);
|
|
6803
|
+
if (compactType === 1 && shouldCompactUseSmallModel()) anthropicPayload.model = getSmallModel();
|
|
5886
6804
|
if (compactType === 0) {
|
|
5887
6805
|
stripToolReferenceTurnBoundary(anthropicPayload);
|
|
5888
6806
|
mergeToolResultForClaude(anthropicPayload);
|
|
5889
6807
|
}
|
|
5890
6808
|
const upstreamRequestId = generateRequestIdFromPayload(anthropicPayload, sessionId);
|
|
5891
|
-
logger$
|
|
6809
|
+
logger$3.debug("Generated request ID:", upstreamRequestId);
|
|
5892
6810
|
const clientModel = anthropicPayload.model;
|
|
5893
6811
|
const streamRequested = Boolean(anthropicPayload.stream);
|
|
5894
6812
|
const rawUserId = anthropicPayload.metadata?.user_id;
|
|
@@ -5907,7 +6825,7 @@ async function handleCompletion(c) {
|
|
|
5907
6825
|
requestId,
|
|
5908
6826
|
startedAtMs,
|
|
5909
6827
|
method,
|
|
5910
|
-
path
|
|
6828
|
+
path,
|
|
5911
6829
|
streamRequested,
|
|
5912
6830
|
clientModel,
|
|
5913
6831
|
clientIp,
|
|
@@ -5942,11 +6860,13 @@ async function handleCompletion(c) {
|
|
|
5942
6860
|
headerSessionId: c.req.header("x-session-id") ?? null,
|
|
5943
6861
|
upstreamRequestId
|
|
5944
6862
|
});
|
|
6863
|
+
const responsesItemOwnershipKeys = extractAnthropicResponsesItemOwnerKeys(anthropicPayload);
|
|
5945
6864
|
const selection = await accountsManager.selectAccountForRequest(candidates, {
|
|
5946
6865
|
requestId: affinityKey.requestId,
|
|
5947
6866
|
affinityModelId,
|
|
5948
6867
|
ownershipLookupSessionId,
|
|
5949
|
-
ownershipWriteSessionId
|
|
6868
|
+
ownershipWriteSessionId,
|
|
6869
|
+
responsesItemOwnershipKeys
|
|
5950
6870
|
});
|
|
5951
6871
|
const selectionReason = invalidSubagentMarkerSelectionReason ?? selection.selectionReason;
|
|
5952
6872
|
if (!selection.ok) return handleSelectionFailure({
|
|
@@ -5955,7 +6875,7 @@ async function handleCompletion(c) {
|
|
|
5955
6875
|
requestId,
|
|
5956
6876
|
startedAtMs,
|
|
5957
6877
|
method,
|
|
5958
|
-
path
|
|
6878
|
+
path,
|
|
5959
6879
|
streamRequested,
|
|
5960
6880
|
clientModel,
|
|
5961
6881
|
clientIp,
|
|
@@ -5969,6 +6889,7 @@ async function handleCompletion(c) {
|
|
|
5969
6889
|
affinityKeyUsed: affinityKey.affinityKeyUsed,
|
|
5970
6890
|
affinityKeySource: affinityKey.affinityKeySource,
|
|
5971
6891
|
selectionReason,
|
|
6892
|
+
responsesItemOwnerLookupKeys: responsesItemOwnershipKeys,
|
|
5972
6893
|
selection
|
|
5973
6894
|
});
|
|
5974
6895
|
const { account, reservation, selectedModel, endpoint, costUnits } = selection;
|
|
@@ -5982,7 +6903,7 @@ async function handleCompletion(c) {
|
|
|
5982
6903
|
requestId,
|
|
5983
6904
|
startedAtMs,
|
|
5984
6905
|
method,
|
|
5985
|
-
path
|
|
6906
|
+
path,
|
|
5986
6907
|
clientIp,
|
|
5987
6908
|
clientIpSource,
|
|
5988
6909
|
userAgent,
|
|
@@ -6005,7 +6926,8 @@ async function handleCompletion(c) {
|
|
|
6005
6926
|
affinityCacheKey: selection.affinityCacheKey,
|
|
6006
6927
|
affinityKeyUsed: affinityKey.affinityKeyUsed,
|
|
6007
6928
|
affinityKeySource: affinityKey.affinityKeySource,
|
|
6008
|
-
selectionReason
|
|
6929
|
+
selectionReason,
|
|
6930
|
+
responsesItemOwnerLookupKeys: responsesItemOwnershipKeys
|
|
6009
6931
|
};
|
|
6010
6932
|
if (endpoint === MESSAGES_ENDPOINT) return await handleWithMessagesApi({
|
|
6011
6933
|
c,
|
|
@@ -6039,7 +6961,7 @@ async function handleCompletion(c) {
|
|
|
6039
6961
|
}
|
|
6040
6962
|
const handleWithChatCompletions = async (params) => {
|
|
6041
6963
|
const { c, openAIPayload, subagentMarker, sessionId, selectedModel, instr, compactType } = params;
|
|
6042
|
-
debugJson(logger$
|
|
6964
|
+
debugJson(logger$3, "Translated OpenAI request payload:", openAIPayload);
|
|
6043
6965
|
const ctx = toAccountContext(instr.account);
|
|
6044
6966
|
const effectiveInitiator = resolveEffectiveInitiator(getChatInitiator(openAIPayload.messages), {
|
|
6045
6967
|
isCompact: compactType !== 0,
|
|
@@ -6070,9 +6992,9 @@ const handleWithChatCompletions = async (params) => {
|
|
|
6070
6992
|
response,
|
|
6071
6993
|
instr
|
|
6072
6994
|
});
|
|
6073
|
-
logger$
|
|
6995
|
+
logger$3.debug("Streaming response from Copilot");
|
|
6074
6996
|
const fallbackEnabled = isMessageStartInputTokensFallbackEnabled();
|
|
6075
|
-
const estimatedInputTokens = fallbackEnabled ? await estimateInputTokens(openAIPayload, selectedModel, logger$
|
|
6997
|
+
const estimatedInputTokens = fallbackEnabled ? await estimateInputTokens(openAIPayload, selectedModel, logger$3) : void 0;
|
|
6076
6998
|
const historicalUsage = fallbackEnabled && instr.promptCacheKey && instr.safetyIdentifier ? instr.store.getLastCompletedUsageBySession({
|
|
6077
6999
|
promptCacheKey: instr.promptCacheKey,
|
|
6078
7000
|
safetyIdentifier: instr.safetyIdentifier,
|
|
@@ -6091,7 +7013,7 @@ const handleWithResponsesApi = async (params) => {
|
|
|
6091
7013
|
const responsesPayload = translateAnthropicMessagesToResponsesPayload(anthropicPayload, selectedModel.id);
|
|
6092
7014
|
applyResponsesApiContextManagement(responsesPayload, selectedModel.capabilities.limits.max_prompt_tokens);
|
|
6093
7015
|
compactInputByLatestCompaction(responsesPayload);
|
|
6094
|
-
debugJson(logger$
|
|
7016
|
+
debugJson(logger$3, "Translated Responses payload:", responsesPayload);
|
|
6095
7017
|
const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
|
|
6096
7018
|
const effectiveInitiator = resolveEffectiveInitiator(initiator, {
|
|
6097
7019
|
isCompact: compactType !== 0,
|
|
@@ -6119,10 +7041,10 @@ const handleWithResponsesApi = async (params) => {
|
|
|
6119
7041
|
stream: Boolean(responsesPayload.stream)
|
|
6120
7042
|
});
|
|
6121
7043
|
}
|
|
6122
|
-
if (responsesPayload.stream && isAsyncIterable
|
|
6123
|
-
logger$
|
|
7044
|
+
if (responsesPayload.stream && isAsyncIterable(response)) {
|
|
7045
|
+
logger$3.debug("Streaming response from Copilot (Responses API)");
|
|
6124
7046
|
const fallbackEnabled = isMessageStartInputTokensFallbackEnabled();
|
|
6125
|
-
const estimatedInputTokens = fallbackEnabled ? await estimateInputTokens(openAIPayload, selectedModel, logger$
|
|
7047
|
+
const estimatedInputTokens = fallbackEnabled ? await estimateInputTokens(openAIPayload, selectedModel, logger$3) : void 0;
|
|
6126
7048
|
const historicalUsage = fallbackEnabled && instr.promptCacheKey && instr.safetyIdentifier ? instr.store.getLastCompletedUsageBySession({
|
|
6127
7049
|
promptCacheKey: instr.promptCacheKey,
|
|
6128
7050
|
safetyIdentifier: instr.safetyIdentifier,
|
|
@@ -6142,13 +7064,16 @@ const handleWithResponsesApi = async (params) => {
|
|
|
6142
7064
|
instr
|
|
6143
7065
|
});
|
|
6144
7066
|
};
|
|
7067
|
+
function stringifyOwnerKeys(keys) {
|
|
7068
|
+
return keys && keys.length > 0 ? JSON.stringify(keys) : void 0;
|
|
7069
|
+
}
|
|
6145
7070
|
function insertRequestLog$1(instr, record) {
|
|
6146
|
-
const { store, requestId, startedAtMs, method, path
|
|
7071
|
+
const { store, requestId, startedAtMs, method, path, clientIp, clientIpSource, userAgent, clientModel, account, upstreamEndpoint, upstreamModel, costUnits, premiumRemainingBefore, premiumUnlimitedBefore } = instr;
|
|
6147
7072
|
store.insert({
|
|
6148
7073
|
requestId,
|
|
6149
7074
|
startedAtMs,
|
|
6150
7075
|
method,
|
|
6151
|
-
path
|
|
7076
|
+
path,
|
|
6152
7077
|
clientIp,
|
|
6153
7078
|
clientIpSource,
|
|
6154
7079
|
userAgent,
|
|
@@ -6171,7 +7096,9 @@ function insertRequestLog$1(instr, record) {
|
|
|
6171
7096
|
upstreamModel,
|
|
6172
7097
|
premiumRemainingBefore,
|
|
6173
7098
|
premiumUnlimitedBefore,
|
|
6174
|
-
...record
|
|
7099
|
+
...record,
|
|
7100
|
+
responsesItemOwnerLookupKeysJson: stringifyOwnerKeys(instr.responsesItemOwnerLookupKeys),
|
|
7101
|
+
responsesItemOwnerRecordedKeysJson: stringifyOwnerKeys(instr.responsesItemOwnerRecordedKeys)
|
|
6175
7102
|
});
|
|
6176
7103
|
flushPendingCapture(requestId);
|
|
6177
7104
|
}
|
|
@@ -6215,9 +7142,9 @@ async function handleChatCompletionsNonStreaming(params) {
|
|
|
6215
7142
|
let upstreamErrorMessageRaw;
|
|
6216
7143
|
const finishedAtMs = Date.now();
|
|
6217
7144
|
try {
|
|
6218
|
-
logger$
|
|
7145
|
+
logger$3.debug("Non-streaming response from Copilot:", JSON.stringify(response));
|
|
6219
7146
|
const anthropicResponse = translateToAnthropic(response);
|
|
6220
|
-
debugJson(logger$
|
|
7147
|
+
debugJson(logger$3, "Translated Anthropic response:", anthropicResponse);
|
|
6221
7148
|
return c.json(anthropicResponse);
|
|
6222
7149
|
} catch (error) {
|
|
6223
7150
|
const details = await extractErrorObservability(error);
|
|
@@ -6268,16 +7195,16 @@ async function streamChatCompletionsAndLog(params) {
|
|
|
6268
7195
|
try {
|
|
6269
7196
|
for await (const rawEvent of response) {
|
|
6270
7197
|
if (ttfbMs === void 0) ttfbMs = Date.now() - instr.startedAtMs;
|
|
6271
|
-
logger$
|
|
7198
|
+
logger$3.debug("Copilot raw stream event:", JSON.stringify(rawEvent));
|
|
6272
7199
|
const { data: rawData } = rawEvent;
|
|
6273
7200
|
const data = typeof rawData === "string" ? rawData : await rawData;
|
|
6274
7201
|
if (data === "[DONE]") break;
|
|
6275
7202
|
if (!data) continue;
|
|
6276
7203
|
const chunk = JSON.parse(data);
|
|
6277
7204
|
if (chunk.usage) lastUsage = normalizeChatCompletionsUsage(chunk.usage);
|
|
6278
|
-
const events
|
|
6279
|
-
for (const event of events
|
|
6280
|
-
logger$
|
|
7205
|
+
const events = translateChunkToAnthropicEvents(chunk, streamState);
|
|
7206
|
+
for (const event of events) {
|
|
7207
|
+
logger$3.debug("Translated Anthropic event:", JSON.stringify(event));
|
|
6281
7208
|
await stream.writeSSE({
|
|
6282
7209
|
event: event.type,
|
|
6283
7210
|
data: JSON.stringify(event)
|
|
@@ -6290,7 +7217,7 @@ async function streamChatCompletionsAndLog(params) {
|
|
|
6290
7217
|
errorStatus = details.errorStatus;
|
|
6291
7218
|
errorMessage = details.errorMessage;
|
|
6292
7219
|
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
6293
|
-
logger$
|
|
7220
|
+
logger$3.warn("Streaming error:", error);
|
|
6294
7221
|
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
6295
7222
|
await writeAnthropicStreamError(stream, getUserVisibleErrorMessage(details));
|
|
6296
7223
|
} finally {
|
|
@@ -6349,10 +7276,14 @@ async function handleResponsesNonStreaming(params) {
|
|
|
6349
7276
|
const finishedAtMs = Date.now();
|
|
6350
7277
|
try {
|
|
6351
7278
|
usage = extractResponsesUsageFromResult(result);
|
|
6352
|
-
|
|
7279
|
+
const responseOwnerKeys = extractResponsesResultOwnerKeys(result);
|
|
7280
|
+
instr.responsesItemOwnerRecordedKeys = responseOwnerKeys;
|
|
7281
|
+
logger$3.debug("Non-streaming Responses result:", JSON.stringify(result).slice(-400));
|
|
6353
7282
|
const anthropicResponse = translateResponsesResultToAnthropic(result);
|
|
6354
|
-
debugJson(logger$
|
|
6355
|
-
|
|
7283
|
+
debugJson(logger$3, "Translated Anthropic response:", anthropicResponse);
|
|
7284
|
+
const response = c.json(anthropicResponse);
|
|
7285
|
+
if (result.status === "completed") accountsManager.recordResponsesItemOwnership(responseOwnerKeys, instr.account.id);
|
|
7286
|
+
return response;
|
|
6356
7287
|
} catch (error) {
|
|
6357
7288
|
const details = await extractErrorObservability(error);
|
|
6358
7289
|
httpStatus = details.httpStatus;
|
|
@@ -6383,7 +7314,7 @@ async function handleResponsesNonStreaming(params) {
|
|
|
6383
7314
|
async function ensureResponsesStreamCompleted(params) {
|
|
6384
7315
|
const { stream, streamState, setStreamError } = params;
|
|
6385
7316
|
if (streamState.messageCompleted) return;
|
|
6386
|
-
logger$
|
|
7317
|
+
logger$3.warn("Responses stream ended without completion; sending error event");
|
|
6387
7318
|
const msg = "Responses stream ended without completion";
|
|
6388
7319
|
const errorEvent = buildErrorEvent(msg);
|
|
6389
7320
|
setStreamError("StreamIncomplete", msg);
|
|
@@ -6400,22 +7331,66 @@ async function writeAnthropicStreamError(stream, message) {
|
|
|
6400
7331
|
data: JSON.stringify(errorEvent)
|
|
6401
7332
|
});
|
|
6402
7333
|
} catch (streamError) {
|
|
6403
|
-
logger$
|
|
7334
|
+
logger$3.warn("Failed to write Anthropic stream error event:", streamError);
|
|
7335
|
+
}
|
|
7336
|
+
}
|
|
7337
|
+
function collectResponsesStreamOwnerKeys(event, responseOwnerKeys) {
|
|
7338
|
+
for (const key of extractResponsesStreamEventOwnerKeys(event)) responseOwnerKeys.add(key);
|
|
7339
|
+
}
|
|
7340
|
+
function createResponsesStreamStateWithUsage(params) {
|
|
7341
|
+
const streamState = createResponsesStreamState();
|
|
7342
|
+
streamState.estimatedInputTokens = params.estimatedInputTokens;
|
|
7343
|
+
streamState.historicalInputTokens = params.historicalUsage?.tokensInput;
|
|
7344
|
+
streamState.historicalOutputTokens = params.historicalUsage?.tokensOutput;
|
|
7345
|
+
streamState.historicalCachedInputTokens = params.historicalUsage?.tokensCachedInput;
|
|
7346
|
+
return streamState;
|
|
7347
|
+
}
|
|
7348
|
+
function recordStreamOwnerKeys(streamState, responseOwnerKeys, instr) {
|
|
7349
|
+
if (!streamState.messageCompleted) return;
|
|
7350
|
+
const ownerKeys = [...responseOwnerKeys];
|
|
7351
|
+
instr.responsesItemOwnerRecordedKeys = ownerKeys;
|
|
7352
|
+
if (streamState.responseStatus === "completed") accountsManager.recordResponsesItemOwnership(ownerKeys, instr.account.id);
|
|
7353
|
+
}
|
|
7354
|
+
function getResponsesStreamEventError(event) {
|
|
7355
|
+
if (event.type === "response.failed") {
|
|
7356
|
+
const message = event.response.error?.message ?? "Responses stream failed upstream.";
|
|
7357
|
+
return {
|
|
7358
|
+
errorName: "ResponsesStreamFailed",
|
|
7359
|
+
errorStatus: 502,
|
|
7360
|
+
errorMessage: message,
|
|
7361
|
+
upstreamErrorMessageRaw: message
|
|
7362
|
+
};
|
|
7363
|
+
}
|
|
7364
|
+
if (event.type === "error") {
|
|
7365
|
+
const message = event.message || "Responses stream returned an error.";
|
|
7366
|
+
return {
|
|
7367
|
+
errorName: "ResponsesStreamError",
|
|
7368
|
+
errorStatus: 502,
|
|
7369
|
+
errorMessage: message,
|
|
7370
|
+
upstreamErrorMessageRaw: message
|
|
7371
|
+
};
|
|
7372
|
+
}
|
|
7373
|
+
}
|
|
7374
|
+
async function writeTranslatedAnthropicStreamEvents(stream, events) {
|
|
7375
|
+
for (const event of events) {
|
|
7376
|
+
const eventData = JSON.stringify(event);
|
|
7377
|
+
logger$3.debug("Translated Anthropic event:", eventData);
|
|
7378
|
+
await stream.writeSSE({
|
|
7379
|
+
event: event.type,
|
|
7380
|
+
data: eventData
|
|
7381
|
+
});
|
|
6404
7382
|
}
|
|
6405
7383
|
}
|
|
6406
7384
|
async function streamResponsesAndLog$1(params) {
|
|
6407
|
-
const { stream, response, instr
|
|
7385
|
+
const { stream, response, instr } = params;
|
|
6408
7386
|
let ttfbMs;
|
|
6409
7387
|
let lastUsage = {};
|
|
6410
7388
|
let errorName;
|
|
6411
7389
|
let errorStatus;
|
|
6412
7390
|
let errorMessage;
|
|
6413
7391
|
let upstreamErrorMessageRaw;
|
|
6414
|
-
const streamState =
|
|
6415
|
-
|
|
6416
|
-
streamState.historicalInputTokens = historicalUsage?.tokensInput;
|
|
6417
|
-
streamState.historicalOutputTokens = historicalUsage?.tokensOutput;
|
|
6418
|
-
streamState.historicalCachedInputTokens = historicalUsage?.tokensCachedInput;
|
|
7392
|
+
const streamState = createResponsesStreamStateWithUsage(params);
|
|
7393
|
+
const responseOwnerKeys = /* @__PURE__ */ new Set();
|
|
6419
7394
|
try {
|
|
6420
7395
|
for await (const chunk of response) {
|
|
6421
7396
|
if (ttfbMs === void 0) ttfbMs = Date.now() - instr.startedAtMs;
|
|
@@ -6428,21 +7403,21 @@ async function streamResponsesAndLog$1(params) {
|
|
|
6428
7403
|
}
|
|
6429
7404
|
const data = chunk.data;
|
|
6430
7405
|
if (!data) continue;
|
|
6431
|
-
logger$
|
|
7406
|
+
logger$3.debug("Responses raw stream event:", data);
|
|
6432
7407
|
const parsed = JSON.parse(data);
|
|
7408
|
+
const streamEventError = getResponsesStreamEventError(parsed);
|
|
7409
|
+
if (streamEventError) {
|
|
7410
|
+
errorName = streamEventError.errorName;
|
|
7411
|
+
errorStatus = streamEventError.errorStatus;
|
|
7412
|
+
errorMessage = streamEventError.errorMessage;
|
|
7413
|
+
upstreamErrorMessageRaw = streamEventError.upstreamErrorMessageRaw;
|
|
7414
|
+
}
|
|
7415
|
+
collectResponsesStreamOwnerKeys(parsed, responseOwnerKeys);
|
|
6433
7416
|
const u = extractResponsesUsageFromStreamEvent(parsed);
|
|
6434
7417
|
if (u.usageJson) lastUsage = u;
|
|
6435
|
-
|
|
6436
|
-
for (const event of events$1) {
|
|
6437
|
-
const eventData = JSON.stringify(event);
|
|
6438
|
-
logger$5.debug("Translated Anthropic event:", eventData);
|
|
6439
|
-
await stream.writeSSE({
|
|
6440
|
-
event: event.type,
|
|
6441
|
-
data: eventData
|
|
6442
|
-
});
|
|
6443
|
-
}
|
|
7418
|
+
await writeTranslatedAnthropicStreamEvents(stream, translateResponsesStreamEvent(parsed, streamState));
|
|
6444
7419
|
if (streamState.messageCompleted) {
|
|
6445
|
-
logger$
|
|
7420
|
+
logger$3.debug("Message completed, ending stream");
|
|
6446
7421
|
break;
|
|
6447
7422
|
}
|
|
6448
7423
|
}
|
|
@@ -6454,13 +7429,14 @@ async function streamResponsesAndLog$1(params) {
|
|
|
6454
7429
|
errorMessage = message;
|
|
6455
7430
|
}
|
|
6456
7431
|
});
|
|
7432
|
+
recordStreamOwnerKeys(streamState, responseOwnerKeys, instr);
|
|
6457
7433
|
} catch (error) {
|
|
6458
7434
|
const details = await extractErrorObservability(error);
|
|
6459
7435
|
errorName = details.errorName;
|
|
6460
7436
|
errorStatus = details.errorStatus;
|
|
6461
7437
|
errorMessage = details.errorMessage;
|
|
6462
7438
|
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
6463
|
-
logger$
|
|
7439
|
+
logger$3.warn("Streaming error:", error);
|
|
6464
7440
|
invalidateAffinityOnOwnershipMismatch(details.ownershipMismatch, instr);
|
|
6465
7441
|
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
6466
7442
|
await writeAnthropicStreamError(stream, getUserVisibleErrorMessage(details));
|
|
@@ -6515,7 +7491,7 @@ async function handleMessagesNonStreaming(params) {
|
|
|
6515
7491
|
let upstreamErrorMessageRaw;
|
|
6516
7492
|
const finishedAtMs = Date.now();
|
|
6517
7493
|
try {
|
|
6518
|
-
logger$
|
|
7494
|
+
logger$3.debug("Non-streaming Messages result:", JSON.stringify(response).slice(-400));
|
|
6519
7495
|
return c.json(response);
|
|
6520
7496
|
} catch (error) {
|
|
6521
7497
|
const details = await extractErrorObservability(error);
|
|
@@ -6545,14 +7521,15 @@ async function handleMessagesNonStreaming(params) {
|
|
|
6545
7521
|
}
|
|
6546
7522
|
}
|
|
6547
7523
|
const parseMessagesStreamUsage = (data) => {
|
|
6548
|
-
if (!data) return null;
|
|
7524
|
+
if (!data || data === "[DONE]") return null;
|
|
6549
7525
|
try {
|
|
6550
7526
|
const parsed = JSON.parse(data);
|
|
7527
|
+
if (parsed.type === "error") throw new Error(parsed.error.message);
|
|
6551
7528
|
if (parsed.type !== "message_delta" || !parsed.usage) return null;
|
|
6552
7529
|
return normalizeMessagesUsage(parsed.usage);
|
|
6553
7530
|
} catch (error) {
|
|
6554
|
-
logger$
|
|
6555
|
-
|
|
7531
|
+
logger$3.warn("Failed to parse messages stream event", error);
|
|
7532
|
+
throw new Error("Failed to parse messages stream event", { cause: error });
|
|
6556
7533
|
}
|
|
6557
7534
|
};
|
|
6558
7535
|
async function streamMessagesAndLog(params) {
|
|
@@ -6569,7 +7546,7 @@ async function streamMessagesAndLog(params) {
|
|
|
6569
7546
|
const eventNameRaw = rawEvent.event;
|
|
6570
7547
|
const eventName = typeof eventNameRaw === "string" && eventNameRaw.length > 0 ? eventNameRaw : "message";
|
|
6571
7548
|
const data = rawEvent.data ?? "";
|
|
6572
|
-
logger$
|
|
7549
|
+
logger$3.debug("Messages raw stream event:", data);
|
|
6573
7550
|
const usage = parseMessagesStreamUsage(data);
|
|
6574
7551
|
if (usage) lastUsage = usage;
|
|
6575
7552
|
await stream.writeSSE({
|
|
@@ -6583,7 +7560,7 @@ async function streamMessagesAndLog(params) {
|
|
|
6583
7560
|
errorStatus = details.errorStatus;
|
|
6584
7561
|
errorMessage = details.errorMessage;
|
|
6585
7562
|
upstreamErrorMessageRaw = details.upstreamErrorMessageRaw;
|
|
6586
|
-
logger$
|
|
7563
|
+
logger$3.warn("Streaming error:", error);
|
|
6587
7564
|
if (shouldMarkAccountFailed(details)) accountsManager.markAccountFailed(instr.account.id, "Unauthorized (401)");
|
|
6588
7565
|
await writeAnthropicStreamError(stream, getUserVisibleErrorMessage(details));
|
|
6589
7566
|
} finally {
|
|
@@ -6609,7 +7586,7 @@ async function streamMessagesAndLog(params) {
|
|
|
6609
7586
|
const handleWithMessagesApi = async (params) => {
|
|
6610
7587
|
const { c, anthropicPayload, anthropicBetaHeader, subagentMarker, sessionId, instr, selectedModel, compactType } = params;
|
|
6611
7588
|
prepareMessagesApiPayload(anthropicPayload, selectedModel);
|
|
6612
|
-
debugJson(logger$
|
|
7589
|
+
debugJson(logger$3, "Translated Messages payload:", anthropicPayload);
|
|
6613
7590
|
const ctx = toAccountContext(instr.account);
|
|
6614
7591
|
const effectiveInitiator = resolveEffectiveInitiator(getMessagesInitiator(anthropicPayload), {
|
|
6615
7592
|
isCompact: compactType !== 0,
|
|
@@ -6636,8 +7613,8 @@ const handleWithMessagesApi = async (params) => {
|
|
|
6636
7613
|
stream: Boolean(anthropicPayload.stream)
|
|
6637
7614
|
});
|
|
6638
7615
|
}
|
|
6639
|
-
if (isAsyncIterable
|
|
6640
|
-
logger$
|
|
7616
|
+
if (isAsyncIterable(response)) {
|
|
7617
|
+
logger$3.debug("Streaming response from Copilot (Messages API)");
|
|
6641
7618
|
return streamSSE(c, (stream) => streamMessagesAndLog({
|
|
6642
7619
|
stream,
|
|
6643
7620
|
response,
|
|
@@ -6651,8 +7628,7 @@ const handleWithMessagesApi = async (params) => {
|
|
|
6651
7628
|
});
|
|
6652
7629
|
};
|
|
6653
7630
|
const isNonStreaming = (response) => Object.hasOwn(response, "choices");
|
|
6654
|
-
const isAsyncIterable
|
|
6655
|
-
|
|
7631
|
+
const isAsyncIterable = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
|
|
6656
7632
|
//#endregion
|
|
6657
7633
|
//#region src/routes/messages/route.ts
|
|
6658
7634
|
const messageRoutes = new Hono();
|
|
@@ -6670,22 +7646,23 @@ messageRoutes.post("/count_tokens", async (c) => {
|
|
|
6670
7646
|
return await forwardError(c, error);
|
|
6671
7647
|
}
|
|
6672
7648
|
});
|
|
6673
|
-
|
|
6674
7649
|
//#endregion
|
|
6675
7650
|
//#region src/routes/models/route.ts
|
|
6676
7651
|
const modelRoutes = new Hono();
|
|
6677
7652
|
modelRoutes.get("/", async (c) => {
|
|
6678
7653
|
try {
|
|
6679
7654
|
const blockedTargets = getAliasTargetSet();
|
|
6680
|
-
const models = getAvailableModels().filter((model) => !blockedTargets.has(model.id.toLowerCase())).map((model) =>
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
7655
|
+
const models = getAvailableModels().filter((model) => !blockedTargets.has(model.id.toLowerCase())).map((model) => {
|
|
7656
|
+
return {
|
|
7657
|
+
id: model.capabilities.limits?.max_context_window_tokens === 1e6 ? `${model.id}[1m]` : model.id,
|
|
7658
|
+
object: "model",
|
|
7659
|
+
type: "model",
|
|
7660
|
+
created: 0,
|
|
7661
|
+
created_at: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
7662
|
+
owned_by: model.vendor,
|
|
7663
|
+
display_name: model.name
|
|
7664
|
+
};
|
|
7665
|
+
});
|
|
6689
7666
|
const aliasModels = Object.keys(getModelAliases()).map((alias) => ({
|
|
6690
7667
|
id: alias,
|
|
6691
7668
|
object: "model",
|
|
@@ -6707,195 +7684,6 @@ modelRoutes.get("/", async (c) => {
|
|
|
6707
7684
|
return await forwardError(c, error);
|
|
6708
7685
|
}
|
|
6709
7686
|
});
|
|
6710
|
-
|
|
6711
|
-
//#endregion
|
|
6712
|
-
//#region src/routes/provider/messages/count-tokens-handler.ts
|
|
6713
|
-
const logger$4 = createHandlerLogger("provider-count-tokens-handler");
|
|
6714
|
-
const createFallbackModel = (modelId) => ({
|
|
6715
|
-
capabilities: {
|
|
6716
|
-
family: "provider",
|
|
6717
|
-
limits: {},
|
|
6718
|
-
object: "model_capabilities",
|
|
6719
|
-
supports: {},
|
|
6720
|
-
tokenizer: "o200k_base",
|
|
6721
|
-
type: "chat"
|
|
6722
|
-
},
|
|
6723
|
-
id: modelId,
|
|
6724
|
-
model_picker_enabled: false,
|
|
6725
|
-
name: modelId,
|
|
6726
|
-
object: "model",
|
|
6727
|
-
preview: false,
|
|
6728
|
-
vendor: "provider",
|
|
6729
|
-
version: "unknown"
|
|
6730
|
-
});
|
|
6731
|
-
async function handleProviderCountTokens(c) {
|
|
6732
|
-
const provider = c.req.param("provider");
|
|
6733
|
-
try {
|
|
6734
|
-
const anthropicPayload = await c.req.json();
|
|
6735
|
-
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
6736
|
-
const modelId = anthropicPayload.model.trim();
|
|
6737
|
-
let selectedModel = getAvailableModels().find((model) => model.id === modelId);
|
|
6738
|
-
if (!selectedModel && modelId) selectedModel = createFallbackModel(modelId);
|
|
6739
|
-
if (!selectedModel) {
|
|
6740
|
-
logger$4.warn("provider.count_tokens.model_not_found", {
|
|
6741
|
-
provider,
|
|
6742
|
-
model: anthropicPayload.model
|
|
6743
|
-
});
|
|
6744
|
-
return c.json({ input_tokens: 1 });
|
|
6745
|
-
}
|
|
6746
|
-
const tokenCount = await getTokenCount(openAIPayload, selectedModel);
|
|
6747
|
-
const finalTokenCount = tokenCount.input + tokenCount.output;
|
|
6748
|
-
logger$4.debug("provider.count_tokens.success", {
|
|
6749
|
-
provider,
|
|
6750
|
-
model: anthropicPayload.model,
|
|
6751
|
-
input_tokens: finalTokenCount
|
|
6752
|
-
});
|
|
6753
|
-
return c.json({ input_tokens: finalTokenCount });
|
|
6754
|
-
} catch (error) {
|
|
6755
|
-
logger$4.error("provider.count_tokens.error", {
|
|
6756
|
-
provider,
|
|
6757
|
-
error
|
|
6758
|
-
});
|
|
6759
|
-
return c.json({ input_tokens: 1 });
|
|
6760
|
-
}
|
|
6761
|
-
}
|
|
6762
|
-
|
|
6763
|
-
//#endregion
|
|
6764
|
-
//#region src/services/providers/anthropic-proxy.ts
|
|
6765
|
-
const FORWARDABLE_HEADERS = [
|
|
6766
|
-
"anthropic-version",
|
|
6767
|
-
"anthropic-beta",
|
|
6768
|
-
"accept",
|
|
6769
|
-
"user-agent"
|
|
6770
|
-
];
|
|
6771
|
-
const STRIPPED_RESPONSE_HEADERS = [
|
|
6772
|
-
"connection",
|
|
6773
|
-
"content-encoding",
|
|
6774
|
-
"content-length",
|
|
6775
|
-
"keep-alive",
|
|
6776
|
-
"proxy-authenticate",
|
|
6777
|
-
"proxy-authorization",
|
|
6778
|
-
"te",
|
|
6779
|
-
"trailer",
|
|
6780
|
-
"transfer-encoding",
|
|
6781
|
-
"upgrade"
|
|
6782
|
-
];
|
|
6783
|
-
function buildProviderUpstreamHeaders(providerConfig, requestHeaders) {
|
|
6784
|
-
const authHeaders = {};
|
|
6785
|
-
if (providerConfig.authType === "authorization") authHeaders.authorization = `Bearer ${providerConfig.apiKey}`;
|
|
6786
|
-
else authHeaders["x-api-key"] = providerConfig.apiKey;
|
|
6787
|
-
const headers = {
|
|
6788
|
-
"content-type": "application/json",
|
|
6789
|
-
accept: "application/json",
|
|
6790
|
-
...authHeaders
|
|
6791
|
-
};
|
|
6792
|
-
for (const headerName of FORWARDABLE_HEADERS) {
|
|
6793
|
-
const headerValue = requestHeaders.get(headerName);
|
|
6794
|
-
if (headerValue) headers[headerName] = headerValue;
|
|
6795
|
-
}
|
|
6796
|
-
return headers;
|
|
6797
|
-
}
|
|
6798
|
-
function createProviderProxyResponse(upstreamResponse) {
|
|
6799
|
-
const headers = new Headers(upstreamResponse.headers);
|
|
6800
|
-
for (const headerName of STRIPPED_RESPONSE_HEADERS) headers.delete(headerName);
|
|
6801
|
-
return new Response(upstreamResponse.body, {
|
|
6802
|
-
headers,
|
|
6803
|
-
status: upstreamResponse.status,
|
|
6804
|
-
statusText: upstreamResponse.statusText
|
|
6805
|
-
});
|
|
6806
|
-
}
|
|
6807
|
-
async function forwardProviderMessages(providerConfig, payload, requestHeaders) {
|
|
6808
|
-
return await fetch(`${providerConfig.baseUrl}/v1/messages`, {
|
|
6809
|
-
method: "POST",
|
|
6810
|
-
headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
|
|
6811
|
-
body: JSON.stringify(payload)
|
|
6812
|
-
});
|
|
6813
|
-
}
|
|
6814
|
-
async function forwardProviderModels(providerConfig, requestHeaders) {
|
|
6815
|
-
return await fetch(`${providerConfig.baseUrl}/v1/models`, {
|
|
6816
|
-
method: "GET",
|
|
6817
|
-
headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders)
|
|
6818
|
-
});
|
|
6819
|
-
}
|
|
6820
|
-
|
|
6821
|
-
//#endregion
|
|
6822
|
-
//#region src/routes/provider/messages/handler.ts
|
|
6823
|
-
const logger$3 = createHandlerLogger("provider-messages-handler");
|
|
6824
|
-
async function handleProviderMessages(c) {
|
|
6825
|
-
const provider = c.req.param("provider") ?? "";
|
|
6826
|
-
const providerConfig = getProviderConfig(provider);
|
|
6827
|
-
if (!providerConfig) return c.json({ error: {
|
|
6828
|
-
message: `Provider '${provider}' not found or disabled`,
|
|
6829
|
-
type: "invalid_request_error"
|
|
6830
|
-
} }, 404);
|
|
6831
|
-
try {
|
|
6832
|
-
const payload = await c.req.json();
|
|
6833
|
-
const modelConfig = providerConfig.models?.[payload.model];
|
|
6834
|
-
payload.temperature ??= modelConfig?.temperature;
|
|
6835
|
-
payload.top_p ??= modelConfig?.topP;
|
|
6836
|
-
payload.top_k ??= modelConfig?.topK;
|
|
6837
|
-
debugJson(logger$3, "provider.messages.request", {
|
|
6838
|
-
payload,
|
|
6839
|
-
provider
|
|
6840
|
-
});
|
|
6841
|
-
const upstreamResponse = await forwardProviderMessages(providerConfig, payload, c.req.raw.headers);
|
|
6842
|
-
if (!upstreamResponse.ok) {
|
|
6843
|
-
logger$3.error("Failed to create responses", upstreamResponse);
|
|
6844
|
-
throw new HTTPError("Failed to create responses", upstreamResponse);
|
|
6845
|
-
}
|
|
6846
|
-
const contentType = upstreamResponse.headers.get("content-type") ?? "";
|
|
6847
|
-
if (Boolean(payload.stream) && contentType.includes("text/event-stream")) {
|
|
6848
|
-
logger$3.debug("provider.messages.streaming");
|
|
6849
|
-
return streamSSE(c, async (stream) => {
|
|
6850
|
-
for await (const chunk of events(upstreamResponse)) {
|
|
6851
|
-
logger$3.debug("provider.messages.raw_stream_event:", chunk.data);
|
|
6852
|
-
const eventName = chunk.event;
|
|
6853
|
-
if (eventName === "ping") {
|
|
6854
|
-
await stream.writeSSE({
|
|
6855
|
-
event: "ping",
|
|
6856
|
-
data: "{\"type\":\"ping\"}"
|
|
6857
|
-
});
|
|
6858
|
-
continue;
|
|
6859
|
-
}
|
|
6860
|
-
let data = chunk.data;
|
|
6861
|
-
if (!data) continue;
|
|
6862
|
-
if (chunk.data === "[DONE]") break;
|
|
6863
|
-
try {
|
|
6864
|
-
const parsed = JSON.parse(data);
|
|
6865
|
-
if (parsed.type === "message_start") adjustInputTokens(providerConfig, parsed.message.usage);
|
|
6866
|
-
else if (parsed.type === "message_delta") adjustInputTokens(providerConfig, parsed.usage);
|
|
6867
|
-
data = JSON.stringify(parsed);
|
|
6868
|
-
} catch (error) {
|
|
6869
|
-
logger$3.error("provider.messages.streaming.adjust_tokens_error", {
|
|
6870
|
-
error,
|
|
6871
|
-
originalData: data
|
|
6872
|
-
});
|
|
6873
|
-
}
|
|
6874
|
-
await stream.writeSSE({
|
|
6875
|
-
event: eventName,
|
|
6876
|
-
data
|
|
6877
|
-
});
|
|
6878
|
-
}
|
|
6879
|
-
});
|
|
6880
|
-
}
|
|
6881
|
-
const jsonBody = await upstreamResponse.json();
|
|
6882
|
-
adjustInputTokens(providerConfig, jsonBody.usage);
|
|
6883
|
-
debugJson(logger$3, "provider.messages.no_stream result:", jsonBody);
|
|
6884
|
-
return c.json(jsonBody);
|
|
6885
|
-
} catch (error) {
|
|
6886
|
-
logger$3.error("provider.messages.error", {
|
|
6887
|
-
provider,
|
|
6888
|
-
error
|
|
6889
|
-
});
|
|
6890
|
-
throw error;
|
|
6891
|
-
}
|
|
6892
|
-
}
|
|
6893
|
-
const adjustInputTokens = (providerConfig, usage) => {
|
|
6894
|
-
if (!providerConfig.adjustInputTokens || !usage) return;
|
|
6895
|
-
usage.input_tokens = Math.max(0, (usage.input_tokens ?? 0) - (usage.cache_read_input_tokens ?? 0) - (usage.cache_creation_input_tokens ?? 0));
|
|
6896
|
-
debugJson(logger$3, "provider.messages.adjusted_usage:", usage);
|
|
6897
|
-
};
|
|
6898
|
-
|
|
6899
7687
|
//#endregion
|
|
6900
7688
|
//#region src/routes/provider/messages/route.ts
|
|
6901
7689
|
const providerMessageRoutes = new Hono();
|
|
@@ -6913,20 +7701,23 @@ providerMessageRoutes.post("/count_tokens", async (c) => {
|
|
|
6913
7701
|
return await forwardError(c, error);
|
|
6914
7702
|
}
|
|
6915
7703
|
});
|
|
6916
|
-
|
|
6917
7704
|
//#endregion
|
|
6918
7705
|
//#region src/routes/provider/models/route.ts
|
|
6919
7706
|
const logger$2 = createHandlerLogger("provider-models-handler");
|
|
7707
|
+
const getProviderFetch = (c) => c.get("providerFetch") ?? fetch;
|
|
7708
|
+
const resolveProviderConfig = (c, provider) => {
|
|
7709
|
+
return (c.get("providerConfigResolver") ?? getProviderConfig)(provider);
|
|
7710
|
+
};
|
|
6920
7711
|
const providerModelRoutes = new Hono();
|
|
6921
7712
|
providerModelRoutes.get("/", async (c) => {
|
|
6922
7713
|
const provider = c.req.param("provider") ?? "";
|
|
6923
7714
|
try {
|
|
6924
|
-
const providerConfig =
|
|
7715
|
+
const providerConfig = resolveProviderConfig(c, provider);
|
|
6925
7716
|
if (!providerConfig) return c.json({ error: {
|
|
6926
7717
|
message: `Provider '${provider}' not found or disabled`,
|
|
6927
7718
|
type: "invalid_request_error"
|
|
6928
7719
|
} }, 404);
|
|
6929
|
-
const upstreamResponse = await forwardProviderModels(providerConfig, c.req.raw.headers);
|
|
7720
|
+
const upstreamResponse = await forwardProviderModels(providerConfig, c.req.raw.headers, getProviderFetch(c));
|
|
6930
7721
|
logger$2.debug("provider.models.response", {
|
|
6931
7722
|
provider,
|
|
6932
7723
|
statusCode: upstreamResponse.status
|
|
@@ -6940,7 +7731,6 @@ providerModelRoutes.get("/", async (c) => {
|
|
|
6940
7731
|
return await forwardError(c, error);
|
|
6941
7732
|
}
|
|
6942
7733
|
});
|
|
6943
|
-
|
|
6944
7734
|
//#endregion
|
|
6945
7735
|
//#region src/routes/responses/stream-id-sync.ts
|
|
6946
7736
|
const createStreamIdTracker = () => ({ outputItems: /* @__PURE__ */ new Map() });
|
|
@@ -6977,7 +7767,6 @@ const handleItemId = (parsed, tracker) => {
|
|
|
6977
7767
|
}
|
|
6978
7768
|
return JSON.stringify(parsed);
|
|
6979
7769
|
};
|
|
6980
|
-
|
|
6981
7770
|
//#endregion
|
|
6982
7771
|
//#region src/routes/responses/handler.ts
|
|
6983
7772
|
const logger$1 = createHandlerLogger("responses-handler");
|
|
@@ -7121,13 +7910,13 @@ function buildRequestContext(c) {
|
|
|
7121
7910
|
const requestId = randomUUID();
|
|
7122
7911
|
const startedAtMs = Date.now();
|
|
7123
7912
|
const method = c.req.raw.method;
|
|
7124
|
-
const path
|
|
7913
|
+
const path = new URL(c.req.url, "http://local").pathname;
|
|
7125
7914
|
const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
|
|
7126
7915
|
return {
|
|
7127
7916
|
requestId,
|
|
7128
7917
|
startedAtMs,
|
|
7129
7918
|
method,
|
|
7130
|
-
path
|
|
7919
|
+
path,
|
|
7131
7920
|
clientIp,
|
|
7132
7921
|
clientIpSource,
|
|
7133
7922
|
userAgent: c.req.header("user-agent") ?? void 0
|
|
@@ -7212,7 +8001,7 @@ async function handleStreamingResponses(params) {
|
|
|
7212
8001
|
error
|
|
7213
8002
|
});
|
|
7214
8003
|
}
|
|
7215
|
-
if (isAsyncIterable(response)) {
|
|
8004
|
+
if (isAsyncIterable$1(response)) {
|
|
7216
8005
|
logger$1.debug("Forwarding native Responses stream");
|
|
7217
8006
|
return streamSSE(c, (stream) => streamResponsesAndLog({
|
|
7218
8007
|
stream,
|
|
@@ -7399,7 +8188,7 @@ async function handleNonStreamingResponses(params) {
|
|
|
7399
8188
|
sessionId: request.upstreamSessionId,
|
|
7400
8189
|
requestId: request.requestId
|
|
7401
8190
|
}, accountCtx);
|
|
7402
|
-
if (isAsyncIterable(response)) throw new Error("Upstream returned a stream unexpectedly");
|
|
8191
|
+
if (isAsyncIterable$1(response)) throw new Error("Upstream returned a stream unexpectedly");
|
|
7403
8192
|
selection.confirmAffinity?.();
|
|
7404
8193
|
finishedAtMs = Date.now();
|
|
7405
8194
|
const result = response;
|
|
@@ -7459,7 +8248,6 @@ const removeUnsupportedTools = (payload) => {
|
|
|
7459
8248
|
});
|
|
7460
8249
|
if (dropped.length > 0) logger$1.debug("Removed unsupported tools:", dropped);
|
|
7461
8250
|
};
|
|
7462
|
-
|
|
7463
8251
|
//#endregion
|
|
7464
8252
|
//#region src/routes/responses/route.ts
|
|
7465
8253
|
const responsesRoutes = new Hono();
|
|
@@ -7470,7 +8258,6 @@ responsesRoutes.post("/", async (c) => {
|
|
|
7470
8258
|
return await forwardError(c, error);
|
|
7471
8259
|
}
|
|
7472
8260
|
});
|
|
7473
|
-
|
|
7474
8261
|
//#endregion
|
|
7475
8262
|
//#region src/routes/token/route.ts
|
|
7476
8263
|
const tokenRoute = new Hono();
|
|
@@ -7485,7 +8272,6 @@ tokenRoute.get("/", (c) => {
|
|
|
7485
8272
|
}, 500);
|
|
7486
8273
|
}
|
|
7487
8274
|
});
|
|
7488
|
-
|
|
7489
8275
|
//#endregion
|
|
7490
8276
|
//#region src/routes/usage/route.ts
|
|
7491
8277
|
const usageRoute = new Hono();
|
|
@@ -7522,7 +8308,6 @@ usageRoute.get("/:accountIndex", async (c) => {
|
|
|
7522
8308
|
return c.json({ error: "Failed to fetch account usage" }, 500);
|
|
7523
8309
|
}
|
|
7524
8310
|
});
|
|
7525
|
-
|
|
7526
8311
|
//#endregion
|
|
7527
8312
|
//#region src/server.ts
|
|
7528
8313
|
const server = new Hono();
|
|
@@ -7549,7 +8334,7 @@ server.route("/v1/responses", responsesRoutes);
|
|
|
7549
8334
|
server.route("/v1/messages", messageRoutes);
|
|
7550
8335
|
server.route("/:provider/v1/messages", providerMessageRoutes);
|
|
7551
8336
|
server.route("/:provider/v1/models", providerModelRoutes);
|
|
7552
|
-
|
|
7553
8337
|
//#endregion
|
|
7554
8338
|
export { server };
|
|
7555
|
-
|
|
8339
|
+
|
|
8340
|
+
//# sourceMappingURL=server-BDCnb3Ao.js.map
|