@jeffreycao/copilot-api 1.16.2 → 1.16.6
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 +14 -3
- package/README.zh-CN.md +14 -3
- package/dist/{auth-BJIo9_6w.js → auth-C0aeKq7k.js} +3 -3
- package/dist/{auth-BJIo9_6w.js.map → auth-C0aeKq7k.js.map} +1 -1
- package/dist/auth-DH-ThnhJ.js +2 -0
- package/dist/{config-BAC1UYyJ.js → config-CoMdcHDW.js} +6 -2
- package/dist/config-CoMdcHDW.js.map +1 -0
- package/dist/{debug-DLs4OzAq.js → debug-D2giR-Kj.js} +2 -2
- package/dist/{debug-DLs4OzAq.js.map → debug-D2giR-Kj.js.map} +1 -1
- package/dist/main.js +3 -3
- package/dist/{models-BY_m4eOW.js → models-DUdPhOBN.js} +2 -2
- package/dist/{models-BY_m4eOW.js.map → models-DUdPhOBN.js.map} +1 -1
- package/dist/{server-DhaNHHv3.js → server-BdY9JFbK.js} +2104 -178
- package/dist/server-BdY9JFbK.js.map +1 -0
- package/dist/{start-D1TEEQrw.js → start-BwdJvu4z.js} +6 -6
- package/dist/{start-D1TEEQrw.js.map → start-BwdJvu4z.js.map} +1 -1
- package/dist/{token-ByZO3ykJ.js → token-_ZvkUtOA.js} +2 -2
- package/dist/{token-ByZO3ykJ.js.map → token-_ZvkUtOA.js.map} +1 -1
- package/package.json +1 -1
- package/dist/auth-BxxohyBj.js +0 -2
- package/dist/config-BAC1UYyJ.js.map +0 -1
- package/dist/server-DhaNHHv3.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { A as buildCodexRequestHeaders, B as state, C as compactAutoContinuePromptStarts, E as compactSystemPromptStarts, F as createResponsesSafeStream, H as forwardError, I as encodePoolKeyPart, L as isTerminalResponsesStreamChunk, M as generateTraceId, N as requestContext, P as resolveTraceId$1, R as createPooledWebSocketStream, V as HTTPError, b as prepareInteractionHeaders, c as getUUID, d as isResponsesStream, f as parseUserIdMetadata, g as copilotHeaders, h as copilotBaseUrl, j as forwardCodexResponses, k as CODEX_API_BASE_URL, l as isAsyncIterable, o as generateRequestIdFromPayload, p as getCopilotUsage, r as setupCodexToken, s as getRootSessionId, u as isNullish, v as copilotWebSocketHeaders, w as compactMessageSections, x as prepareMessageProxyHeaders, y as prepareForCompact, z as createWebSocketUrl } from "./token-
|
|
1
|
+
import { C as getClaudeTokenMultiplier, D as isMessagesApiEnabled, E as isAlphaSearchCodexPriorityEnabled, O as isResponsesApiWebSearchEnabled, S as getClaudeAutoModel, T as getMessageApiWebSearchModel, _ as resolveMappedModel, b as getAlphaSearchModel, d as getModelResponsesApiCompactThreshold$1, f as getReasoningEffortForModel, g as isGpt56OrAbove, h as isContextManagementEnabledForResponses, i as listEnabledProviders, j as PATHS, k as isResponsesApiWebSocketEnabled, l as getExtraPromptForModel, m as isContextManagementEnabledForMessages, n as getRawProviderConfig, o as resolveEffectiveProviderType, p as getSmallModel, s as resolveProviderAuthType, t as getProviderConfig, u as getModelMappings, v as setModelMappings, w as getConfig, x as getAnthropicApiKey } from "./config-CoMdcHDW.js";
|
|
2
|
+
import { A as buildCodexRequestHeaders, B as state, C as compactAutoContinuePromptStarts, D as compactTextOnlyGuard, E as compactSystemPromptStarts, F as createResponsesSafeStream, H as forwardError, I as encodePoolKeyPart, L as isTerminalResponsesStreamChunk, M as generateTraceId, N as requestContext, P as resolveTraceId$1, R as createPooledWebSocketStream, V as HTTPError, b as prepareInteractionHeaders, c as getUUID, d as isResponsesStream, f as parseUserIdMetadata, g as copilotHeaders, h as copilotBaseUrl, j as forwardCodexResponses, k as CODEX_API_BASE_URL, l as isAsyncIterable, o as generateRequestIdFromPayload, p as getCopilotUsage, r as setupCodexToken, s as getRootSessionId, u as isNullish, v as copilotWebSocketHeaders, w as compactMessageSections, x as prepareMessageProxyHeaders, y as prepareForCompact, z as createWebSocketUrl } from "./token-_ZvkUtOA.js";
|
|
3
3
|
import { a as isDeferredToolName, c as parseMcpToolSearchSentinel, d as shouldEnableResponsesToolSearch, i as isBridgeToolSearchName, l as resolveBridgeToolSearchName, o as listDeferredToolNames, r as formatToolSearchBridgeArguments, s as normalizeToolSearchBridgeArguments, t as BRIDGE_TOOL_SEARCH_NAME, u as selectDeferredToolsByNames } from "./tool-search-Ds1vbmGG.js";
|
|
4
|
-
import { i as toClientModelId, r as normalizeSdkModelId, t as findEndpointModel } from "./models-
|
|
4
|
+
import { i as toClientModelId, r as normalizeSdkModelId, t as findEndpointModel } from "./models-DUdPhOBN.js";
|
|
5
5
|
import consola from "consola";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
7
|
import fs, { readFileSync } from "node:fs";
|
|
@@ -1995,10 +1995,12 @@ async function forwardProviderResponses(providerConfig, payload, requestHeaders)
|
|
|
1995
1995
|
body: JSON.stringify(payload)
|
|
1996
1996
|
});
|
|
1997
1997
|
}
|
|
1998
|
+
const PROVIDER_MODELS_TIMEOUT_MS = 15e3;
|
|
1998
1999
|
async function forwardProviderModels(providerConfig, requestHeaders) {
|
|
1999
2000
|
return await fetch(`${providerConfig.baseUrl}/v1/models`, {
|
|
2000
2001
|
method: "GET",
|
|
2001
|
-
headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders)
|
|
2002
|
+
headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
|
|
2003
|
+
signal: AbortSignal.timeout(PROVIDER_MODELS_TIMEOUT_MS)
|
|
2002
2004
|
});
|
|
2003
2005
|
}
|
|
2004
2006
|
/** Align with Codex images: long-running generation/edits need a generous cap. */
|
|
@@ -2039,7 +2041,7 @@ async function forwardProviderImages(providerConfig, request, operation) {
|
|
|
2039
2041
|
}
|
|
2040
2042
|
//#endregion
|
|
2041
2043
|
//#region src/routes/alpha-search/alpha-search-responses.ts
|
|
2042
|
-
const logger$
|
|
2044
|
+
const logger$16 = createHandlerLogger("alpha-search-responses-handler");
|
|
2043
2045
|
const SESSION_TTL_MS = 3600 * 1e3;
|
|
2044
2046
|
const MAX_SESSIONS = 128;
|
|
2045
2047
|
const MAX_URL_REFERENCES = 256;
|
|
@@ -2395,14 +2397,14 @@ function createRemoteResponsesPayload(request, model, instruction) {
|
|
|
2395
2397
|
};
|
|
2396
2398
|
}
|
|
2397
2399
|
async function requestProviderSearch(c, providerConfig, payload, model, sessionId) {
|
|
2398
|
-
debugJson(logger$
|
|
2400
|
+
debugJson(logger$16, "Alpha search provider Responses request:", {
|
|
2399
2401
|
payload,
|
|
2400
2402
|
provider: providerConfig.name
|
|
2401
2403
|
});
|
|
2402
2404
|
const upstreamResponse = await forwardProviderResponses(providerConfig, payload, c.req.raw.headers);
|
|
2403
2405
|
if (!upstreamResponse.ok) throw new HTTPError(`Failed to create ${providerConfig.name} responses for alpha search`, upstreamResponse);
|
|
2404
2406
|
const result = await upstreamResponse.json();
|
|
2405
|
-
debugJson(logger$
|
|
2407
|
+
debugJson(logger$16, "Alpha search provider Responses result:", {
|
|
2406
2408
|
provider: providerConfig.name,
|
|
2407
2409
|
result
|
|
2408
2410
|
});
|
|
@@ -2418,7 +2420,7 @@ async function requestProviderSearch(c, providerConfig, payload, model, sessionI
|
|
|
2418
2420
|
return result;
|
|
2419
2421
|
}
|
|
2420
2422
|
async function requestCopilotSearch(payload, model, requestId, sessionId) {
|
|
2421
|
-
debugJson(logger$
|
|
2423
|
+
debugJson(logger$16, "Alpha search Copilot Responses request:", payload);
|
|
2422
2424
|
const result = await alphaSearchResponsesDependencies.createResponses(payload, {
|
|
2423
2425
|
vision: false,
|
|
2424
2426
|
initiator: "agent",
|
|
@@ -2426,7 +2428,7 @@ async function requestCopilotSearch(payload, model, requestId, sessionId) {
|
|
|
2426
2428
|
requestId,
|
|
2427
2429
|
sessionId
|
|
2428
2430
|
});
|
|
2429
|
-
debugJson(logger$
|
|
2431
|
+
debugJson(logger$16, "Alpha search Copilot Responses result:", result);
|
|
2430
2432
|
alphaSearchResponsesDependencies.createUsageRecorder(model, sessionId)({
|
|
2431
2433
|
...normalizeResponsesUsage(result.usage),
|
|
2432
2434
|
total_nano_aiu: normalizeOptionalToken(result.copilot_usage?.total_nano_aiu)
|
|
@@ -2541,7 +2543,7 @@ async function forwardCodexAlphaSearch(request) {
|
|
|
2541
2543
|
}
|
|
2542
2544
|
//#endregion
|
|
2543
2545
|
//#region src/routes/alpha-search/route.ts
|
|
2544
|
-
const logger$
|
|
2546
|
+
const logger$15 = createHandlerLogger("alpha-search-handler");
|
|
2545
2547
|
const alphaSearchRoutes = new Hono();
|
|
2546
2548
|
function parseDebugBody(body) {
|
|
2547
2549
|
try {
|
|
@@ -2551,9 +2553,9 @@ function parseDebugBody(body) {
|
|
|
2551
2553
|
}
|
|
2552
2554
|
}
|
|
2553
2555
|
async function forwardCodexAlphaSearchRequest(request) {
|
|
2554
|
-
await debugJsonAsync(logger$
|
|
2556
|
+
await debugJsonAsync(logger$15, "alpha_search.codex.request", async () => ({ body: parseDebugBody(await request.clone().text()) }));
|
|
2555
2557
|
const upstreamResponse = await forwardCodexAlphaSearch(request);
|
|
2556
|
-
await debugJsonAsync(logger$
|
|
2558
|
+
await debugJsonAsync(logger$15, "alpha_search.codex.response", async () => ({
|
|
2557
2559
|
body: parseDebugBody(await upstreamResponse.clone().text()),
|
|
2558
2560
|
statusCode: upstreamResponse.status
|
|
2559
2561
|
}));
|
|
@@ -2600,7 +2602,8 @@ async function handleAlphaSearchRequest(c, resolvedProviderConfig) {
|
|
|
2600
2602
|
const requestedModel = payload.model;
|
|
2601
2603
|
payload.model = resolveMappedModel(requestedModel);
|
|
2602
2604
|
if (payload.model !== requestedModel) consola.debug(`Resolved model mapping: ${requestedModel} -> ${payload.model}`);
|
|
2603
|
-
const
|
|
2605
|
+
const resolvedRequestedModel = payload.model;
|
|
2606
|
+
let providerModelAlias = parseProviderModelAlias(payload.model);
|
|
2604
2607
|
if (providerModelAlias) {
|
|
2605
2608
|
payload.model = providerModelAlias.model;
|
|
2606
2609
|
if (providerModelAlias.provider === "codex") return await handleCodexRequest(c, createAlphaSearchRequest(c.req.raw, payload));
|
|
@@ -2608,20 +2611,55 @@ async function handleAlphaSearchRequest(c, resolvedProviderConfig) {
|
|
|
2608
2611
|
if (isAlphaSearchCodexPriorityEnabled()) {
|
|
2609
2612
|
if (await resolveProviderConfig("codex")) return await forwardCodexAlphaSearchRequest(createAlphaSearchRequest(c.req.raw, payload));
|
|
2610
2613
|
}
|
|
2614
|
+
const messagesBackedModel = await isMessagesBackedModel(resolvedRequestedModel);
|
|
2615
|
+
if (messagesBackedModel) {
|
|
2616
|
+
const searchModel = getAlphaSearchModel();
|
|
2617
|
+
if (!searchModel) return invalidRequest(c, "alphaSearchModel is disabled; Messages-backed Codex models require a native Responses search model");
|
|
2618
|
+
const resolvedSearchModel = resolveMappedModel(searchModel);
|
|
2619
|
+
if (!await isNativeResponsesModel(resolvedSearchModel)) return invalidRequest(c, `Configured alphaSearchModel '${searchModel}' does not support the Responses endpoint required for alpha search`);
|
|
2620
|
+
consola.debug(`Redirected alpha search model: ${resolvedRequestedModel} -> ${resolvedSearchModel}`);
|
|
2621
|
+
payload.model = resolvedSearchModel;
|
|
2622
|
+
providerModelAlias = parseProviderModelAlias(payload.model);
|
|
2623
|
+
if (providerModelAlias) {
|
|
2624
|
+
payload.model = providerModelAlias.model;
|
|
2625
|
+
if (providerModelAlias.provider === "codex") return await handleCodexRequest(c, createAlphaSearchRequest(c.req.raw, payload));
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
const fallbackRequestedModel = messagesBackedModel ? payload.model : requestedModel;
|
|
2611
2629
|
if (providerModelAlias) return await handleAlphaSearchResponses(c, {
|
|
2612
2630
|
provider: providerModelAlias.provider,
|
|
2613
2631
|
request: payload
|
|
2614
2632
|
});
|
|
2615
2633
|
return await handleAlphaSearchResponses(c, { request: {
|
|
2616
2634
|
...payload,
|
|
2617
|
-
model:
|
|
2635
|
+
model: fallbackRequestedModel
|
|
2618
2636
|
} });
|
|
2619
2637
|
}
|
|
2638
|
+
async function isMessagesBackedModel(model) {
|
|
2639
|
+
const providerAlias = parseProviderModelAlias(model);
|
|
2640
|
+
if (providerAlias) {
|
|
2641
|
+
const providerConfig = await resolveProviderConfig(providerAlias.provider);
|
|
2642
|
+
if (!providerConfig) return false;
|
|
2643
|
+
const effectiveType = resolveEffectiveProviderType(providerConfig, providerAlias.model);
|
|
2644
|
+
return effectiveType === "anthropic" || effectiveType === "openai-compatible";
|
|
2645
|
+
}
|
|
2646
|
+
const endpoints = findEndpointModel(model)?.supported_endpoints ?? [];
|
|
2647
|
+
return (endpoints.includes("/v1/messages") || endpoints.includes("/chat/completions")) && !endpoints.includes("/responses") && !endpoints.includes("ws:/responses");
|
|
2648
|
+
}
|
|
2649
|
+
async function isNativeResponsesModel(model) {
|
|
2650
|
+
const providerAlias = parseProviderModelAlias(model);
|
|
2651
|
+
if (providerAlias) {
|
|
2652
|
+
const providerConfig = await resolveProviderConfig(providerAlias.provider);
|
|
2653
|
+
return providerConfig !== null && resolveEffectiveProviderType(providerConfig, providerAlias.model) === "openai-responses";
|
|
2654
|
+
}
|
|
2655
|
+
const endpoints = findEndpointModel(model)?.supported_endpoints ?? [];
|
|
2656
|
+
return endpoints.includes("/responses") || endpoints.includes("ws:/responses");
|
|
2657
|
+
}
|
|
2620
2658
|
alphaSearchRoutes.post("/", async (c) => {
|
|
2621
2659
|
try {
|
|
2622
2660
|
return await handleAlphaSearchRequest(c);
|
|
2623
2661
|
} catch (error) {
|
|
2624
|
-
logger$
|
|
2662
|
+
logger$15.error("alpha_search.error", { error });
|
|
2625
2663
|
return await forwardError(c, error);
|
|
2626
2664
|
}
|
|
2627
2665
|
});
|
|
@@ -2686,7 +2724,7 @@ const applyMissingExtraBody = (payload, options) => {
|
|
|
2686
2724
|
};
|
|
2687
2725
|
//#endregion
|
|
2688
2726
|
//#region src/routes/provider/chat-completions/handler.ts
|
|
2689
|
-
const logger$
|
|
2727
|
+
const logger$14 = createHandlerLogger("provider-chat-completions-handler");
|
|
2690
2728
|
async function handleProviderChatCompletionsForProvider(c, options) {
|
|
2691
2729
|
const { payload, provider } = options;
|
|
2692
2730
|
const providerConfig = await resolveProviderConfig(provider);
|
|
@@ -2700,13 +2738,13 @@ async function handleProviderChatCompletionsForProvider(c, options) {
|
|
|
2700
2738
|
applyProviderStreamOptions(payload);
|
|
2701
2739
|
applyDashScopePreserveThinkingDefault(payload, providerConfig);
|
|
2702
2740
|
applyProviderContextCache(payload, modelConfig, providerConfig);
|
|
2703
|
-
debugJson(logger$
|
|
2741
|
+
debugJson(logger$14, "provider.chat_completions.request", {
|
|
2704
2742
|
payload,
|
|
2705
2743
|
provider
|
|
2706
2744
|
});
|
|
2707
2745
|
const upstreamResponse = await forwardProviderChatCompletions(providerConfig, payload, c.req.raw.headers);
|
|
2708
2746
|
if (!upstreamResponse.ok) {
|
|
2709
|
-
logger$
|
|
2747
|
+
logger$14.error("Failed to create provider chat completions", {
|
|
2710
2748
|
provider,
|
|
2711
2749
|
statusCode: upstreamResponse.status
|
|
2712
2750
|
});
|
|
@@ -2720,7 +2758,7 @@ async function handleProviderChatCompletionsForProvider(c, options) {
|
|
|
2720
2758
|
});
|
|
2721
2759
|
const responseBody = await upstreamResponse.clone().json();
|
|
2722
2760
|
recordUsage(normalizeOpenAIUsage(responseBody.usage));
|
|
2723
|
-
debugJson(logger$
|
|
2761
|
+
debugJson(logger$14, "provider.chat_completions.response", responseBody);
|
|
2724
2762
|
return createProviderProxyResponse(upstreamResponse);
|
|
2725
2763
|
}
|
|
2726
2764
|
const applyProviderStreamOptions = (payload) => {
|
|
@@ -2742,12 +2780,12 @@ const createProviderChatCompletionsUsageRecorder = (payload, provider, modelConf
|
|
|
2742
2780
|
providerName: provider
|
|
2743
2781
|
});
|
|
2744
2782
|
const streamProviderChatCompletions = (c, upstreamResponse, options) => {
|
|
2745
|
-
logger$
|
|
2783
|
+
logger$14.debug("provider.chat_completions.streaming", { provider: options.provider });
|
|
2746
2784
|
return streamSSE(c, async (stream) => {
|
|
2747
2785
|
let usage = {};
|
|
2748
2786
|
try {
|
|
2749
2787
|
for await (const chunk of events(upstreamResponse)) {
|
|
2750
|
-
debugJson(logger$
|
|
2788
|
+
debugJson(logger$14, "provider.chat_completions.stream_chunk", chunk);
|
|
2751
2789
|
if (chunk.data && chunk.data !== "[DONE]") {
|
|
2752
2790
|
const parsedChunk = parseChatCompletionChunkData(chunk.data);
|
|
2753
2791
|
if (parsedChunk?.usage) usage = normalizeOpenAIUsage(parsedChunk.usage);
|
|
@@ -2801,7 +2839,7 @@ const createChatCompletions = async (payload, options) => {
|
|
|
2801
2839
|
};
|
|
2802
2840
|
//#endregion
|
|
2803
2841
|
//#region src/routes/chat-completions/handler.ts
|
|
2804
|
-
const logger$
|
|
2842
|
+
const logger$13 = createHandlerLogger("chat-completions-handler");
|
|
2805
2843
|
async function handleCompletion$1(c) {
|
|
2806
2844
|
let payload = await c.req.json();
|
|
2807
2845
|
const requestedModel = payload.model;
|
|
@@ -2815,23 +2853,23 @@ async function handleCompletion$1(c) {
|
|
|
2815
2853
|
provider: providerModelAlias.provider
|
|
2816
2854
|
});
|
|
2817
2855
|
}
|
|
2818
|
-
debugJson(logger$
|
|
2856
|
+
debugJson(logger$13, "Request payload:", payload);
|
|
2819
2857
|
const selectedModel = state.models?.data.find((model) => model.id === payload.model);
|
|
2820
2858
|
if (isNullish(payload.max_tokens) && isNullish(payload.max_completion_tokens)) {
|
|
2821
2859
|
payload = {
|
|
2822
2860
|
...payload,
|
|
2823
2861
|
max_tokens: selectedModel?.capabilities.limits.max_output_tokens
|
|
2824
2862
|
};
|
|
2825
|
-
debugJson(logger$
|
|
2863
|
+
debugJson(logger$13, "Set max_tokens to:", payload.max_tokens);
|
|
2826
2864
|
}
|
|
2827
2865
|
if (payload.model.includes("gpt")) {
|
|
2828
2866
|
if (isNullish(payload.max_completion_tokens)) payload.max_completion_tokens = payload.max_tokens;
|
|
2829
2867
|
delete payload.max_tokens;
|
|
2830
2868
|
}
|
|
2831
2869
|
const requestId = generateRequestIdFromPayload(payload);
|
|
2832
|
-
logger$
|
|
2870
|
+
logger$13.debug("Generated request ID:", requestId);
|
|
2833
2871
|
const sessionId = getUUID(requestId);
|
|
2834
|
-
logger$
|
|
2872
|
+
logger$13.debug("Extracted session ID:", sessionId);
|
|
2835
2873
|
const recordUsage = createCopilotTokenUsageRecorder({
|
|
2836
2874
|
endpoint: "chat_completions",
|
|
2837
2875
|
fallbackSessionId: sessionId,
|
|
@@ -2842,18 +2880,18 @@ async function handleCompletion$1(c) {
|
|
|
2842
2880
|
sessionId
|
|
2843
2881
|
});
|
|
2844
2882
|
if (isNonStreaming$1(response)) {
|
|
2845
|
-
debugJson(logger$
|
|
2883
|
+
debugJson(logger$13, "Non-streaming response:", response);
|
|
2846
2884
|
recordUsage({
|
|
2847
2885
|
...normalizeOpenAIUsage(response.usage),
|
|
2848
2886
|
total_nano_aiu: normalizeOptionalToken(response.copilot_usage?.total_nano_aiu)
|
|
2849
2887
|
});
|
|
2850
2888
|
return c.json(response);
|
|
2851
2889
|
}
|
|
2852
|
-
logger$
|
|
2890
|
+
logger$13.debug("Streaming response");
|
|
2853
2891
|
return streamSSE(c, async (stream) => {
|
|
2854
2892
|
let usage = {};
|
|
2855
2893
|
for await (const chunk of response) {
|
|
2856
|
-
debugJson(logger$
|
|
2894
|
+
debugJson(logger$13, "Streaming chunk:", chunk);
|
|
2857
2895
|
const parsedChunk = parseChatCompletionChunk(chunk);
|
|
2858
2896
|
if (parsedChunk?.usage || parsedChunk?.copilot_usage) usage = {
|
|
2859
2897
|
...normalizeOpenAIUsage(parsedChunk.usage),
|
|
@@ -2970,7 +3008,7 @@ async function forwardCodexImages(request, operation) {
|
|
|
2970
3008
|
}
|
|
2971
3009
|
//#endregion
|
|
2972
3010
|
//#region src/routes/images/route.ts
|
|
2973
|
-
const logger$
|
|
3011
|
+
const logger$12 = createHandlerLogger("images-handler");
|
|
2974
3012
|
const imageRoutes = new Hono();
|
|
2975
3013
|
const imageRouteDependencies = { debugJsonAsync };
|
|
2976
3014
|
function getContentMetadata$1(headers) {
|
|
@@ -2989,16 +3027,16 @@ async function handleCodexImages(c, operation, resolvedProviderConfig) {
|
|
|
2989
3027
|
message: "Provider 'codex' not found or disabled",
|
|
2990
3028
|
type: "invalid_request_error"
|
|
2991
3029
|
} }, 404);
|
|
2992
|
-
if (operation === "generations") await imageRouteDependencies.debugJsonAsync(logger$
|
|
2993
|
-
else debugJson(logger$
|
|
3030
|
+
if (operation === "generations") await imageRouteDependencies.debugJsonAsync(logger$12, "images.generations.codex.request", async () => ({ body: await c.req.raw.clone().text() }));
|
|
3031
|
+
else debugJson(logger$12, "images.edits.codex.request", getContentMetadata$1(c.req.raw.headers));
|
|
2994
3032
|
const upstreamResponse = await forwardCodexImages(c.req.raw, operation);
|
|
2995
|
-
debugJson(logger$
|
|
3033
|
+
debugJson(logger$12, `images.${operation}.codex.response`, {
|
|
2996
3034
|
...getContentMetadata$1(upstreamResponse.headers),
|
|
2997
3035
|
statusCode: upstreamResponse.status
|
|
2998
3036
|
});
|
|
2999
3037
|
return createProviderProxyResponse(upstreamResponse);
|
|
3000
3038
|
} catch (error) {
|
|
3001
|
-
logger$
|
|
3039
|
+
logger$12.error(`images.${operation}.codex.error`, { error });
|
|
3002
3040
|
return await forwardError(c, error);
|
|
3003
3041
|
}
|
|
3004
3042
|
}
|
|
@@ -3952,7 +3990,7 @@ const stripToolEagerInputStreaming = (payload) => {
|
|
|
3952
3990
|
const filterAssistantThinkingBlocks = (payload) => {
|
|
3953
3991
|
for (const msg of payload.messages) if (msg.role === "assistant" && Array.isArray(msg.content)) msg.content = msg.content.filter((block) => {
|
|
3954
3992
|
if (block.type !== "thinking") return true;
|
|
3955
|
-
return block.thinking
|
|
3993
|
+
return block.thinking !== "Thinking..." && block.signature && !block.signature.includes("@");
|
|
3956
3994
|
});
|
|
3957
3995
|
};
|
|
3958
3996
|
const prepareMessagesApiPayload = (payload, selectedModel) => {
|
|
@@ -3994,7 +4032,7 @@ const prepareMessagesApiPayload = (payload, selectedModel) => {
|
|
|
3994
4032
|
};
|
|
3995
4033
|
//#endregion
|
|
3996
4034
|
//#region src/routes/provider/messages/count-tokens-handler.ts
|
|
3997
|
-
const logger$
|
|
4035
|
+
const logger$11 = createHandlerLogger("provider-count-tokens-handler");
|
|
3998
4036
|
async function handleProviderCountTokens(c) {
|
|
3999
4037
|
const provider = c.req.param("provider");
|
|
4000
4038
|
return await handleProviderCountTokensForProvider(c, {
|
|
@@ -4017,7 +4055,7 @@ async function handleProviderCountTokensForProvider(c, options) {
|
|
|
4017
4055
|
toolContentSupportType: modelConfig?.toolContentSupportType ?? []
|
|
4018
4056
|
} : void 0), createFallbackModel(modelId));
|
|
4019
4057
|
const finalTokenCount = tokenCount.input + tokenCount.output;
|
|
4020
|
-
logger$
|
|
4058
|
+
logger$11.debug("provider.count_tokens.success", {
|
|
4021
4059
|
provider,
|
|
4022
4060
|
model: anthropicPayload.model,
|
|
4023
4061
|
input_tokens: finalTokenCount
|
|
@@ -5030,9 +5068,9 @@ const mapResponsesUsage = (response) => {
|
|
|
5030
5068
|
...cacheWriteTokens !== void 0 && { cache_creation_input_tokens: cacheWriteTokens }
|
|
5031
5069
|
};
|
|
5032
5070
|
};
|
|
5033
|
-
const isRecord$
|
|
5034
|
-
const isResponseOutputText = (block) => isRecord$
|
|
5035
|
-
const isResponseOutputRefusal = (block) => isRecord$
|
|
5071
|
+
const isRecord$3 = (value) => typeof value === "object" && value !== null;
|
|
5072
|
+
const isResponseOutputText = (block) => isRecord$3(block) && "type" in block && block.type === "output_text";
|
|
5073
|
+
const isResponseOutputRefusal = (block) => isRecord$3(block) && "type" in block && block.type === "refusal";
|
|
5036
5074
|
const convertToolResultContent = (content) => {
|
|
5037
5075
|
if (typeof content === "string") return content;
|
|
5038
5076
|
if (Array.isArray(content)) {
|
|
@@ -6116,6 +6154,7 @@ const CODEX_MODELS = [
|
|
|
6116
6154
|
}
|
|
6117
6155
|
];
|
|
6118
6156
|
const CODEX_MODELS_URL = `${CODEX_API_BASE_URL}/codex/models`;
|
|
6157
|
+
const CODEX_MODELS_TIMEOUT_MS = 15e3;
|
|
6119
6158
|
function resolveCodexModelsUrl(requestUrl) {
|
|
6120
6159
|
const upstreamUrl = new URL(CODEX_MODELS_URL);
|
|
6121
6160
|
upstreamUrl.search = new URL(requestUrl, "http://localhost").search;
|
|
@@ -6126,7 +6165,8 @@ async function forwardCodexModels(requestUrl, requestHeaders) {
|
|
|
6126
6165
|
if (!headers.has("accept")) headers.set("accept", "application/json");
|
|
6127
6166
|
return await fetch(resolveCodexModelsUrl(requestUrl), {
|
|
6128
6167
|
method: "GET",
|
|
6129
|
-
headers
|
|
6168
|
+
headers,
|
|
6169
|
+
signal: AbortSignal.timeout(CODEX_MODELS_TIMEOUT_MS)
|
|
6130
6170
|
});
|
|
6131
6171
|
}
|
|
6132
6172
|
function normalizeCodexModel(model) {
|
|
@@ -6175,7 +6215,7 @@ function getModels() {
|
|
|
6175
6215
|
}
|
|
6176
6216
|
//#endregion
|
|
6177
6217
|
//#region src/routes/provider/messages/handler.ts
|
|
6178
|
-
const logger$
|
|
6218
|
+
const logger$10 = createHandlerLogger("provider-messages-handler");
|
|
6179
6219
|
async function handleProviderMessages(c) {
|
|
6180
6220
|
const provider = c.req.param("provider");
|
|
6181
6221
|
const payload = await c.req.json();
|
|
@@ -6190,7 +6230,7 @@ async function handleProviderMessages(c) {
|
|
|
6190
6230
|
});
|
|
6191
6231
|
}
|
|
6192
6232
|
async function handleProviderMessagesForProvider(c, options) {
|
|
6193
|
-
const { payload, provider } = options;
|
|
6233
|
+
const { payload, provider, usageEndpoint } = options;
|
|
6194
6234
|
const providerConfig = await resolveProviderConfig(provider);
|
|
6195
6235
|
if (!providerConfig) return c.json({ error: {
|
|
6196
6236
|
message: `Provider '${provider}' not found or disabled`,
|
|
@@ -6199,7 +6239,7 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
6199
6239
|
try {
|
|
6200
6240
|
const modelConfig = providerConfig.models?.[payload.model];
|
|
6201
6241
|
const effectiveType = resolveEffectiveProviderType(providerConfig, payload.model);
|
|
6202
|
-
debugJson(logger$
|
|
6242
|
+
debugJson(logger$10, "provider.messages.request", {
|
|
6203
6243
|
payload,
|
|
6204
6244
|
provider
|
|
6205
6245
|
});
|
|
@@ -6211,7 +6251,8 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
6211
6251
|
modelConfig,
|
|
6212
6252
|
payload,
|
|
6213
6253
|
provider,
|
|
6214
|
-
providerConfig
|
|
6254
|
+
providerConfig,
|
|
6255
|
+
usageEndpoint
|
|
6215
6256
|
});
|
|
6216
6257
|
stripWebSearchServerTool(payload);
|
|
6217
6258
|
}
|
|
@@ -6219,7 +6260,8 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
6219
6260
|
modelConfig,
|
|
6220
6261
|
payload,
|
|
6221
6262
|
provider,
|
|
6222
|
-
providerConfig
|
|
6263
|
+
providerConfig,
|
|
6264
|
+
usageEndpoint
|
|
6223
6265
|
});
|
|
6224
6266
|
}
|
|
6225
6267
|
if (effectiveType === "openai-compatible") {
|
|
@@ -6228,11 +6270,12 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
6228
6270
|
modelConfig,
|
|
6229
6271
|
payload,
|
|
6230
6272
|
provider,
|
|
6231
|
-
providerConfig
|
|
6273
|
+
providerConfig,
|
|
6274
|
+
usageEndpoint
|
|
6232
6275
|
});
|
|
6233
6276
|
}
|
|
6234
6277
|
applyMissingExtraBody(payload, { extraBody: modelConfig?.extraBody });
|
|
6235
|
-
debugJson(logger$
|
|
6278
|
+
debugJson(logger$10, "Translated provider.messages.request", {
|
|
6236
6279
|
payload,
|
|
6237
6280
|
provider
|
|
6238
6281
|
});
|
|
@@ -6242,7 +6285,7 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
6242
6285
|
authType: resolveProviderAuthType(providerConfig.name, void 0, effectiveType)
|
|
6243
6286
|
}, payload, c.req.raw.headers);
|
|
6244
6287
|
if (!upstreamResponse.ok) {
|
|
6245
|
-
logger$
|
|
6288
|
+
logger$10.error("Failed to create responses", upstreamResponse);
|
|
6246
6289
|
throw new HTTPError("Failed to create responses", upstreamResponse);
|
|
6247
6290
|
}
|
|
6248
6291
|
const contentType = upstreamResponse.headers.get("content-type") ?? "";
|
|
@@ -6252,17 +6295,19 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
6252
6295
|
payload,
|
|
6253
6296
|
pricingCurrency: providerConfig.pricingCurrency,
|
|
6254
6297
|
provider,
|
|
6255
|
-
upstreamResponse
|
|
6298
|
+
upstreamResponse,
|
|
6299
|
+
usageEndpoint
|
|
6256
6300
|
});
|
|
6257
6301
|
return respondProviderMessagesJson(c, {
|
|
6258
6302
|
body: await upstreamResponse.json(),
|
|
6259
6303
|
modelConfig,
|
|
6260
6304
|
payload,
|
|
6261
6305
|
pricingCurrency: providerConfig.pricingCurrency,
|
|
6262
|
-
provider
|
|
6306
|
+
provider,
|
|
6307
|
+
usageEndpoint
|
|
6263
6308
|
});
|
|
6264
6309
|
} catch (error) {
|
|
6265
|
-
logger$
|
|
6310
|
+
logger$10.error("provider.messages.error", {
|
|
6266
6311
|
provider,
|
|
6267
6312
|
error
|
|
6268
6313
|
});
|
|
@@ -6270,9 +6315,9 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
6270
6315
|
}
|
|
6271
6316
|
}
|
|
6272
6317
|
const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
|
|
6273
|
-
const { modelConfig, payload, provider, providerConfig } = options;
|
|
6318
|
+
const { modelConfig, payload, provider, providerConfig, usageEndpoint } = options;
|
|
6274
6319
|
const responsesPayload = prepareWebSearchResponsesPayload(payload);
|
|
6275
|
-
debugJson(logger$
|
|
6320
|
+
debugJson(logger$10, "provider.messages.responses.web_search.request", {
|
|
6276
6321
|
payload: responsesPayload,
|
|
6277
6322
|
provider
|
|
6278
6323
|
});
|
|
@@ -6283,24 +6328,26 @@ const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
|
|
|
6283
6328
|
errorMessagePrefix: `${provider} web search responses stream`,
|
|
6284
6329
|
parseEvent: (data) => parseResponsesProviderStreamChunk(data, providerConfig),
|
|
6285
6330
|
upstreamResponse,
|
|
6286
|
-
logger: logger$
|
|
6331
|
+
logger: logger$10
|
|
6287
6332
|
}),
|
|
6288
6333
|
modelConfig,
|
|
6289
6334
|
payload,
|
|
6290
6335
|
pricingCurrency: providerConfig.pricingCurrency,
|
|
6291
|
-
provider
|
|
6336
|
+
provider,
|
|
6337
|
+
usageEndpoint
|
|
6292
6338
|
});
|
|
6293
6339
|
return respondWebSearchProviderMessagesJson(c, {
|
|
6294
6340
|
body: upstreamResponse,
|
|
6295
6341
|
modelConfig,
|
|
6296
6342
|
payload,
|
|
6297
6343
|
pricingCurrency: providerConfig.pricingCurrency,
|
|
6298
|
-
provider
|
|
6344
|
+
provider,
|
|
6345
|
+
usageEndpoint
|
|
6299
6346
|
});
|
|
6300
6347
|
}
|
|
6301
6348
|
const upstreamResponse = await forwardProviderResponses(providerConfig, responsesPayload, c.req.raw.headers);
|
|
6302
6349
|
if (!upstreamResponse.ok) {
|
|
6303
|
-
logger$
|
|
6350
|
+
logger$10.error("Failed to create provider web search responses", {
|
|
6304
6351
|
provider,
|
|
6305
6352
|
upstreamResponse
|
|
6306
6353
|
});
|
|
@@ -6311,29 +6358,31 @@ const handleOpenAIResponsesProviderWebSearchMessages = async (c, options) => {
|
|
|
6311
6358
|
errorMessagePrefix: `${provider} web search responses stream`,
|
|
6312
6359
|
parseEvent: (data) => parseResponsesProviderStreamChunk(data, providerConfig),
|
|
6313
6360
|
upstreamResponse: events(upstreamResponse),
|
|
6314
|
-
logger: logger$
|
|
6361
|
+
logger: logger$10
|
|
6315
6362
|
}),
|
|
6316
6363
|
modelConfig,
|
|
6317
6364
|
payload,
|
|
6318
6365
|
pricingCurrency: providerConfig.pricingCurrency,
|
|
6319
|
-
provider
|
|
6366
|
+
provider,
|
|
6367
|
+
usageEndpoint
|
|
6320
6368
|
});
|
|
6321
6369
|
return respondWebSearchProviderMessagesJson(c, {
|
|
6322
6370
|
body: await upstreamResponse.json(),
|
|
6323
6371
|
modelConfig,
|
|
6324
6372
|
payload,
|
|
6325
6373
|
pricingCurrency: providerConfig.pricingCurrency,
|
|
6326
|
-
provider
|
|
6374
|
+
provider,
|
|
6375
|
+
usageEndpoint
|
|
6327
6376
|
});
|
|
6328
6377
|
};
|
|
6329
6378
|
const handleOpenAIResponsesProviderMessages = async (c, options) => {
|
|
6330
|
-
const { modelConfig, payload, provider, providerConfig } = options;
|
|
6379
|
+
const { modelConfig, payload, provider, providerConfig, usageEndpoint } = options;
|
|
6331
6380
|
const selectedModel = providerConfig.name === "codex" ? getModels().data.find((model) => model.id === payload.model) : void 0;
|
|
6332
6381
|
const wantsStream = payload.stream === true;
|
|
6333
6382
|
const responsesPayload = translateAnthropicMessagesToResponsesPayload(payload);
|
|
6334
6383
|
if (providerConfig.name === "codex" && !wantsStream) responsesPayload.stream = true;
|
|
6335
6384
|
if (applyResponsesApiContextManagement(responsesPayload, selectedModel?.capabilities.limits.max_prompt_tokens, { source: "messages" })) compactInputByLatestCompaction(responsesPayload);
|
|
6336
|
-
debugJson(logger$
|
|
6385
|
+
debugJson(logger$10, "provider.messages.responses.request", {
|
|
6337
6386
|
payload: responsesPayload,
|
|
6338
6387
|
provider
|
|
6339
6388
|
});
|
|
@@ -6347,20 +6396,22 @@ const handleOpenAIResponsesProviderMessages = async (c, options) => {
|
|
|
6347
6396
|
pricingCurrency: providerConfig.pricingCurrency,
|
|
6348
6397
|
provider,
|
|
6349
6398
|
providerConfig,
|
|
6350
|
-
upstreamResponse
|
|
6399
|
+
upstreamResponse,
|
|
6400
|
+
usageEndpoint
|
|
6351
6401
|
});
|
|
6352
6402
|
return respondResponsesProviderMessagesJson(c, {
|
|
6353
6403
|
body: await collectResponsesStreamResult({
|
|
6354
6404
|
errorMessagePrefix: `${provider} messages responses stream`,
|
|
6355
6405
|
parseEvent: (data) => parseResponsesProviderStreamChunk(data, providerConfig),
|
|
6356
6406
|
upstreamResponse,
|
|
6357
|
-
logger: logger$
|
|
6407
|
+
logger: logger$10
|
|
6358
6408
|
}),
|
|
6359
6409
|
modelConfig,
|
|
6360
6410
|
payload,
|
|
6361
6411
|
pricingCurrency: providerConfig.pricingCurrency,
|
|
6362
6412
|
provider,
|
|
6363
|
-
providerConfig
|
|
6413
|
+
providerConfig,
|
|
6414
|
+
usageEndpoint
|
|
6364
6415
|
});
|
|
6365
6416
|
}
|
|
6366
6417
|
return respondResponsesProviderMessagesJson(c, {
|
|
@@ -6369,12 +6420,13 @@ const handleOpenAIResponsesProviderMessages = async (c, options) => {
|
|
|
6369
6420
|
payload,
|
|
6370
6421
|
pricingCurrency: providerConfig.pricingCurrency,
|
|
6371
6422
|
provider,
|
|
6372
|
-
providerConfig
|
|
6423
|
+
providerConfig,
|
|
6424
|
+
usageEndpoint
|
|
6373
6425
|
});
|
|
6374
6426
|
}
|
|
6375
6427
|
const upstreamResponse = await forwardProviderResponses(providerConfig, responsesPayload, c.req.raw.headers);
|
|
6376
6428
|
if (!upstreamResponse.ok) {
|
|
6377
|
-
logger$
|
|
6429
|
+
logger$10.error("Failed to create provider responses", upstreamResponse);
|
|
6378
6430
|
throw new HTTPError("Failed to create provider responses", upstreamResponse);
|
|
6379
6431
|
}
|
|
6380
6432
|
if (responsesPayload.stream) return streamResponsesProviderMessages({
|
|
@@ -6384,7 +6436,8 @@ const handleOpenAIResponsesProviderMessages = async (c, options) => {
|
|
|
6384
6436
|
pricingCurrency: providerConfig.pricingCurrency,
|
|
6385
6437
|
provider,
|
|
6386
6438
|
providerConfig,
|
|
6387
|
-
upstreamResponse: events(upstreamResponse)
|
|
6439
|
+
upstreamResponse: events(upstreamResponse),
|
|
6440
|
+
usageEndpoint
|
|
6388
6441
|
});
|
|
6389
6442
|
return respondResponsesProviderMessagesJson(c, {
|
|
6390
6443
|
body: await upstreamResponse.json(),
|
|
@@ -6392,7 +6445,8 @@ const handleOpenAIResponsesProviderMessages = async (c, options) => {
|
|
|
6392
6445
|
payload,
|
|
6393
6446
|
pricingCurrency: providerConfig.pricingCurrency,
|
|
6394
6447
|
provider,
|
|
6395
|
-
providerConfig
|
|
6448
|
+
providerConfig,
|
|
6449
|
+
usageEndpoint
|
|
6396
6450
|
});
|
|
6397
6451
|
};
|
|
6398
6452
|
const getRequestThinkingBudget = (payload) => {
|
|
@@ -6415,15 +6469,15 @@ const applyOpenAICompatibleExtraBodyThinkingBudget = (payload, options) => {
|
|
|
6415
6469
|
rawPayload.thinking_budget = extraBody.thinking_budget;
|
|
6416
6470
|
};
|
|
6417
6471
|
const handleOpenAICompatibleProviderMessages = async (c, options) => {
|
|
6418
|
-
const { modelConfig, payload, provider, providerConfig } = options;
|
|
6472
|
+
const { modelConfig, payload, provider, providerConfig, usageEndpoint } = options;
|
|
6419
6473
|
const openAIPayload = createOpenAICompatiblePayload(payload, modelConfig, providerConfig);
|
|
6420
|
-
debugJson(logger$
|
|
6474
|
+
debugJson(logger$10, "provider.messages.openai_compatible.request", {
|
|
6421
6475
|
payload: openAIPayload,
|
|
6422
6476
|
provider
|
|
6423
6477
|
});
|
|
6424
6478
|
const upstreamResponse = await forwardProviderChatCompletions(providerConfig, openAIPayload, c.req.raw.headers);
|
|
6425
6479
|
if (!upstreamResponse.ok) {
|
|
6426
|
-
logger$
|
|
6480
|
+
logger$10.error("Failed to create openai-compatible responses", upstreamResponse);
|
|
6427
6481
|
throw new HTTPError("Failed to create openai-compatible responses", upstreamResponse);
|
|
6428
6482
|
}
|
|
6429
6483
|
const contentType = upstreamResponse.headers.get("content-type") ?? "";
|
|
@@ -6433,14 +6487,16 @@ const handleOpenAICompatibleProviderMessages = async (c, options) => {
|
|
|
6433
6487
|
payload,
|
|
6434
6488
|
pricingCurrency: providerConfig.pricingCurrency,
|
|
6435
6489
|
provider,
|
|
6436
|
-
upstreamResponse
|
|
6490
|
+
upstreamResponse,
|
|
6491
|
+
usageEndpoint
|
|
6437
6492
|
});
|
|
6438
6493
|
return respondOpenAICompatibleProviderMessagesJson(c, {
|
|
6439
6494
|
body: await upstreamResponse.json(),
|
|
6440
6495
|
modelConfig,
|
|
6441
6496
|
payload,
|
|
6442
6497
|
pricingCurrency: providerConfig.pricingCurrency,
|
|
6443
|
-
provider
|
|
6498
|
+
provider,
|
|
6499
|
+
usageEndpoint
|
|
6444
6500
|
});
|
|
6445
6501
|
};
|
|
6446
6502
|
const createOpenAICompatiblePayload = (payload, modelConfig, providerConfig) => {
|
|
@@ -6477,9 +6533,9 @@ const applyOpenAICompatibleRequestOverrides = (payload, options) => {
|
|
|
6477
6533
|
const allowedKeys = new Set(Object.keys(options.extraBody ?? {}));
|
|
6478
6534
|
for (const key of allowedKeys) if (Object.hasOwn(options.source, key)) payload[key] = options.source[key];
|
|
6479
6535
|
};
|
|
6480
|
-
const streamProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, upstreamResponse }) => {
|
|
6481
|
-
logger$
|
|
6482
|
-
const recordUsage = createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency);
|
|
6536
|
+
const streamProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, upstreamResponse, usageEndpoint }) => {
|
|
6537
|
+
logger$10.debug("provider.messages.streaming");
|
|
6538
|
+
const recordUsage = createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency, usageEndpoint);
|
|
6483
6539
|
return streamSSE(c, async (stream) => {
|
|
6484
6540
|
let usage = {};
|
|
6485
6541
|
const openRouterThinkingState = {
|
|
@@ -6487,7 +6543,7 @@ const streamProviderMessages = ({ c, modelConfig, payload, pricingCurrency, prov
|
|
|
6487
6543
|
thinkingBlockIndexes: /* @__PURE__ */ new Set()
|
|
6488
6544
|
};
|
|
6489
6545
|
for await (const chunk of events(upstreamResponse)) {
|
|
6490
|
-
logger$
|
|
6546
|
+
logger$10.debug("provider.messages.raw_stream_event:", chunk.data);
|
|
6491
6547
|
const eventName = chunk.event;
|
|
6492
6548
|
if (eventName === "ping") {
|
|
6493
6549
|
await stream.writeSSE({
|
|
@@ -6516,9 +6572,9 @@ const streamProviderMessages = ({ c, modelConfig, payload, pricingCurrency, prov
|
|
|
6516
6572
|
recordUsage(usage);
|
|
6517
6573
|
});
|
|
6518
6574
|
};
|
|
6519
|
-
const streamOpenAICompatibleProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, upstreamResponse }) => {
|
|
6520
|
-
logger$
|
|
6521
|
-
const recordUsage = createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency);
|
|
6575
|
+
const streamOpenAICompatibleProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, upstreamResponse, usageEndpoint }) => {
|
|
6576
|
+
logger$10.debug("provider.messages.openai_compatible.streaming");
|
|
6577
|
+
const recordUsage = createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency, usageEndpoint);
|
|
6522
6578
|
return streamSSE(c, async (stream) => {
|
|
6523
6579
|
let usage = {};
|
|
6524
6580
|
const streamState = {
|
|
@@ -6529,7 +6585,7 @@ const streamOpenAICompatibleProviderMessages = ({ c, modelConfig, payload, prici
|
|
|
6529
6585
|
thinkingBlockOpen: false
|
|
6530
6586
|
};
|
|
6531
6587
|
for await (const chunk of events(upstreamResponse)) {
|
|
6532
|
-
logger$
|
|
6588
|
+
logger$10.debug("provider.messages.openai_compatible.raw_stream_event:", chunk.data);
|
|
6533
6589
|
if (chunk.event === "ping") {
|
|
6534
6590
|
await stream.writeSSE({
|
|
6535
6591
|
event: "ping",
|
|
@@ -6547,7 +6603,7 @@ const streamOpenAICompatibleProviderMessages = ({ c, modelConfig, payload, prici
|
|
|
6547
6603
|
const events = translateChunkToAnthropicEvents(parsed, streamState);
|
|
6548
6604
|
for (const event of events) {
|
|
6549
6605
|
const eventData = JSON.stringify(event);
|
|
6550
|
-
debugLazy(logger$
|
|
6606
|
+
debugLazy(logger$10, () => ["provider.messages.openai_compatible.translated_event:", eventData]);
|
|
6551
6607
|
await stream.writeSSE({
|
|
6552
6608
|
event: event.type,
|
|
6553
6609
|
data: eventData
|
|
@@ -6556,7 +6612,7 @@ const streamOpenAICompatibleProviderMessages = ({ c, modelConfig, payload, prici
|
|
|
6556
6612
|
}
|
|
6557
6613
|
for (const event of flushPendingAnthropicStreamEvents(streamState)) {
|
|
6558
6614
|
const eventData = JSON.stringify(event);
|
|
6559
|
-
debugLazy(logger$
|
|
6615
|
+
debugLazy(logger$10, () => ["provider.messages.openai_compatible.translated_event:", eventData]);
|
|
6560
6616
|
await stream.writeSSE({
|
|
6561
6617
|
event: event.type,
|
|
6562
6618
|
data: eventData
|
|
@@ -6565,14 +6621,14 @@ const streamOpenAICompatibleProviderMessages = ({ c, modelConfig, payload, prici
|
|
|
6565
6621
|
recordUsage(usage);
|
|
6566
6622
|
});
|
|
6567
6623
|
};
|
|
6568
|
-
const streamResponsesProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, providerConfig, upstreamResponse }) => {
|
|
6569
|
-
logger$
|
|
6570
|
-
const recordUsage = createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency);
|
|
6624
|
+
const streamResponsesProviderMessages = ({ c, modelConfig, payload, pricingCurrency, provider, providerConfig, upstreamResponse, usageEndpoint }) => {
|
|
6625
|
+
logger$10.debug("provider.messages.responses.streaming", { provider });
|
|
6626
|
+
const recordUsage = createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency, usageEndpoint);
|
|
6571
6627
|
return streamSSE(c, async (stream) => {
|
|
6572
6628
|
let usage = {};
|
|
6573
6629
|
const streamState = createResponsesStreamState({ toolSearchName: resolveBridgeToolSearchName(payload.tools) });
|
|
6574
6630
|
for await (const chunk of upstreamResponse) {
|
|
6575
|
-
logger$
|
|
6631
|
+
logger$10.debug("provider.messages.responses.raw_stream_event:", chunk.data);
|
|
6576
6632
|
if (chunk.event === "ping") {
|
|
6577
6633
|
await stream.writeSSE({
|
|
6578
6634
|
event: "ping",
|
|
@@ -6590,7 +6646,7 @@ const streamResponsesProviderMessages = ({ c, modelConfig, payload, pricingCurre
|
|
|
6590
6646
|
const events = translateResponsesStreamEvent(parsed, streamState);
|
|
6591
6647
|
for (const event of events) {
|
|
6592
6648
|
const eventData = JSON.stringify(event);
|
|
6593
|
-
debugLazy(logger$
|
|
6649
|
+
debugLazy(logger$10, () => ["provider.messages.responses.translated_event:", eventData]);
|
|
6594
6650
|
await stream.writeSSE({
|
|
6595
6651
|
event: event.type,
|
|
6596
6652
|
data: eventData
|
|
@@ -6611,7 +6667,7 @@ const parseOpenAICompatibleStreamChunk = (data) => {
|
|
|
6611
6667
|
try {
|
|
6612
6668
|
return JSON.parse(data);
|
|
6613
6669
|
} catch (error) {
|
|
6614
|
-
logger$
|
|
6670
|
+
logger$10.error("provider.messages.openai_compatible.parse_chunk_error", {
|
|
6615
6671
|
data,
|
|
6616
6672
|
error
|
|
6617
6673
|
});
|
|
@@ -6624,7 +6680,7 @@ const parseResponsesProviderStreamChunk = (data, providerConfig) => {
|
|
|
6624
6680
|
if (providerConfig.name === "codex") logCodexRateLimitsEvent(parsed);
|
|
6625
6681
|
return parsed;
|
|
6626
6682
|
} catch (error) {
|
|
6627
|
-
logger$
|
|
6683
|
+
logger$10.error("provider.messages.responses.parse_chunk_error", {
|
|
6628
6684
|
provider: providerConfig.name,
|
|
6629
6685
|
data,
|
|
6630
6686
|
error
|
|
@@ -6649,7 +6705,7 @@ const parseProviderStreamEvent = (data) => {
|
|
|
6649
6705
|
usage: {}
|
|
6650
6706
|
};
|
|
6651
6707
|
} catch (error) {
|
|
6652
|
-
logger$
|
|
6708
|
+
logger$10.error("provider.messages.streaming.adjust_tokens_error", {
|
|
6653
6709
|
error,
|
|
6654
6710
|
originalData: data
|
|
6655
6711
|
});
|
|
@@ -6708,37 +6764,37 @@ const normalizeOpenRouterStreamEvents = (eventName, data, state) => {
|
|
|
6708
6764
|
}];
|
|
6709
6765
|
};
|
|
6710
6766
|
const respondProviderMessagesJson = (c, options) => {
|
|
6711
|
-
const { body, modelConfig, payload, pricingCurrency, provider } = options;
|
|
6712
|
-
createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency)(normalizeAnthropicUsage(body.usage));
|
|
6767
|
+
const { body, modelConfig, payload, pricingCurrency, provider, usageEndpoint } = options;
|
|
6768
|
+
createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency, usageEndpoint)(normalizeAnthropicUsage(body.usage));
|
|
6713
6769
|
if (provider === "openrouter") normalizeOpenRouterThinkingSignatures(body);
|
|
6714
|
-
debugJson(logger$
|
|
6770
|
+
debugJson(logger$10, "provider.messages.no_stream result:", body);
|
|
6715
6771
|
return c.json(body);
|
|
6716
6772
|
};
|
|
6717
6773
|
const respondOpenAICompatibleProviderMessagesJson = (c, options) => {
|
|
6718
|
-
const { body, modelConfig, payload, pricingCurrency, provider } = options;
|
|
6719
|
-
createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency)(normalizeOpenAIUsage(body.usage));
|
|
6774
|
+
const { body, modelConfig, payload, pricingCurrency, provider, usageEndpoint } = options;
|
|
6775
|
+
createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency, usageEndpoint)(normalizeOpenAIUsage(body.usage));
|
|
6720
6776
|
const anthropicResponse = translateToAnthropic(body);
|
|
6721
|
-
debugJson(logger$
|
|
6777
|
+
debugJson(logger$10, "provider.messages.openai_compatible.no_stream result:", anthropicResponse);
|
|
6722
6778
|
return c.json(anthropicResponse);
|
|
6723
6779
|
};
|
|
6724
6780
|
const respondResponsesProviderMessagesJson = (c, options) => {
|
|
6725
|
-
const { body, modelConfig, payload, pricingCurrency, provider, providerConfig } = options;
|
|
6726
|
-
createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency)(normalizeResponsesUsage(body.usage));
|
|
6781
|
+
const { body, modelConfig, payload, pricingCurrency, provider, providerConfig, usageEndpoint } = options;
|
|
6782
|
+
createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency, usageEndpoint)(normalizeResponsesUsage(body.usage));
|
|
6727
6783
|
const anthropicResponse = translateResponsesResultToAnthropic(body, { toolSearchName: resolveBridgeToolSearchName(payload.tools) });
|
|
6728
|
-
debugJson(logger$
|
|
6729
|
-
if (providerConfig.name === "codex") logger$
|
|
6784
|
+
debugJson(logger$10, "provider.messages.responses.no_stream result:", anthropicResponse);
|
|
6785
|
+
if (providerConfig.name === "codex") logger$10.debug("provider.messages.codex.no_stream.result");
|
|
6730
6786
|
return c.json(anthropicResponse);
|
|
6731
6787
|
};
|
|
6732
6788
|
const respondWebSearchProviderMessagesJson = (c, options) => {
|
|
6733
|
-
const { body, modelConfig, payload, pricingCurrency, provider } = options;
|
|
6734
|
-
createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency)(normalizeResponsesUsage(body.usage));
|
|
6789
|
+
const { body, modelConfig, payload, pricingCurrency, provider, usageEndpoint } = options;
|
|
6790
|
+
createProviderMessagesUsageRecorder(payload, provider, modelConfig, pricingCurrency, usageEndpoint)(normalizeResponsesUsage(body.usage));
|
|
6735
6791
|
const { extract, response } = reconstructWebSearchResponse(payload, body, { requestId: body.id || `${provider}:${payload.model}` });
|
|
6736
|
-
debugJson(logger$
|
|
6792
|
+
debugJson(logger$10, `Web search via responses: ${extract.queries.length} quer(y/ies), ${extract.sources.length} source(s)`, body);
|
|
6737
6793
|
if (!payload.stream) return c.json(response);
|
|
6738
6794
|
return streamSSE(c, async (stream) => {
|
|
6739
6795
|
for (const event of buildSyntheticStreamEvents(response)) {
|
|
6740
6796
|
const data = JSON.stringify(event);
|
|
6741
|
-
logger$
|
|
6797
|
+
logger$10.debug(`Web search stream event`, data);
|
|
6742
6798
|
await stream.writeSSE({
|
|
6743
6799
|
event: event.type,
|
|
6744
6800
|
data
|
|
@@ -6746,8 +6802,8 @@ const respondWebSearchProviderMessagesJson = (c, options) => {
|
|
|
6746
6802
|
}
|
|
6747
6803
|
});
|
|
6748
6804
|
};
|
|
6749
|
-
const createProviderMessagesUsageRecorder = (payload, provider, modelConfig, pricingCurrency) => createProviderTokenUsageRecorder({
|
|
6750
|
-
endpoint
|
|
6805
|
+
const createProviderMessagesUsageRecorder = (payload, provider, modelConfig, pricingCurrency, endpoint = "provider_messages") => createProviderTokenUsageRecorder({
|
|
6806
|
+
endpoint,
|
|
6751
6807
|
model: payload.model,
|
|
6752
6808
|
pricing: modelConfig?.pricing,
|
|
6753
6809
|
pricingCurrency,
|
|
@@ -6822,7 +6878,7 @@ const handleWithChatCompletions = async (c, anthropicPayload, options) => {
|
|
|
6822
6878
|
});
|
|
6823
6879
|
prepareCopilotChatCompletionsPayload(openAIPayload);
|
|
6824
6880
|
const recordUsage = createCopilotUsageRecorder({
|
|
6825
|
-
endpoint: "chat_completions",
|
|
6881
|
+
endpoint: options.usageEndpoint ?? "chat_completions",
|
|
6826
6882
|
fallbackSessionId: sessionId,
|
|
6827
6883
|
model: openAIPayload.model,
|
|
6828
6884
|
payload: anthropicPayload
|
|
@@ -6888,7 +6944,7 @@ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
|
|
|
6888
6944
|
const { logger, selectedModel, ...requestOptions } = options;
|
|
6889
6945
|
const responsesPayload = translateAnthropicMessagesToResponsesPayload(anthropicPayload, requestOptions.subagentMarker?.agent_id);
|
|
6890
6946
|
const recordUsage = createCopilotUsageRecorder({
|
|
6891
|
-
endpoint: "responses",
|
|
6947
|
+
endpoint: options.usageEndpoint ?? "responses",
|
|
6892
6948
|
fallbackSessionId: requestOptions.sessionId,
|
|
6893
6949
|
model: responsesPayload.model,
|
|
6894
6950
|
payload: anthropicPayload
|
|
@@ -6963,7 +7019,7 @@ const handleWithMessagesApi = async (c, anthropicPayload, options) => {
|
|
|
6963
7019
|
const { logger, anthropicBetaHeader, subagentMarker, selectedModel, requestId, sessionId, compactType } = options;
|
|
6964
7020
|
prepareMessagesApiPayload(anthropicPayload, selectedModel);
|
|
6965
7021
|
const recordUsage = createCopilotUsageRecorder({
|
|
6966
|
-
endpoint: "messages",
|
|
7022
|
+
endpoint: options.usageEndpoint ?? "messages",
|
|
6967
7023
|
fallbackSessionId: sessionId,
|
|
6968
7024
|
model: anthropicPayload.model,
|
|
6969
7025
|
payload: anthropicPayload
|
|
@@ -7096,27 +7152,31 @@ const parseSubagentMarkerFromSystemReminder = (text) => {
|
|
|
7096
7152
|
};
|
|
7097
7153
|
//#endregion
|
|
7098
7154
|
//#region src/routes/messages/handler.ts
|
|
7099
|
-
const logger$
|
|
7155
|
+
const logger$9 = createHandlerLogger("messages-handler");
|
|
7100
7156
|
const messagesFlowHandlers = {
|
|
7101
7157
|
handleWithChatCompletions,
|
|
7102
7158
|
handleWithMessagesApi,
|
|
7103
7159
|
handleWithResponsesApi
|
|
7104
7160
|
};
|
|
7105
7161
|
async function handleCompletion(c) {
|
|
7106
|
-
|
|
7162
|
+
return await handleCompletionPayload(c, await c.req.json());
|
|
7163
|
+
}
|
|
7164
|
+
async function handleCompletionPayload(c, anthropicPayload, dispatchOptions = {}) {
|
|
7107
7165
|
const requestedModel = anthropicPayload.model;
|
|
7108
|
-
anthropicPayload.model = resolveMappedModel(anthropicPayload.model);
|
|
7166
|
+
if (!dispatchOptions.skipModelMapping) anthropicPayload.model = resolveMappedModel(anthropicPayload.model);
|
|
7109
7167
|
if (anthropicPayload.model !== requestedModel) consola.debug(`Resolved model mapping: ${requestedModel} -> ${anthropicPayload.model}`);
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
payload,
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7168
|
+
if (!dispatchOptions.skipWebSearch) {
|
|
7169
|
+
const webSearchResult = await tryHandleWebSearch(c, anthropicPayload, {
|
|
7170
|
+
logger: logger$9,
|
|
7171
|
+
forwardToProvider: (ctx, payload, provider) => handleProviderMessagesForProvider(ctx, {
|
|
7172
|
+
payload,
|
|
7173
|
+
provider
|
|
7174
|
+
})
|
|
7175
|
+
});
|
|
7176
|
+
if (webSearchResult) return webSearchResult;
|
|
7177
|
+
}
|
|
7118
7178
|
const claudeAutoModel = getClaudeAutoModel();
|
|
7119
|
-
const shouldUseClaudeAutoModel = Boolean(claudeAutoModel && isClaudeAutoModelRequest(anthropicPayload));
|
|
7179
|
+
const shouldUseClaudeAutoModel = Boolean(!dispatchOptions.skipClaudeAutoModel && claudeAutoModel && isClaudeAutoModelRequest(anthropicPayload));
|
|
7120
7180
|
if (claudeAutoModel && shouldUseClaudeAutoModel) {
|
|
7121
7181
|
consola.debug(`Claude auto model override: ${anthropicPayload.model} -> ${claudeAutoModel}`);
|
|
7122
7182
|
anthropicPayload.model = claudeAutoModel;
|
|
@@ -7126,24 +7186,25 @@ async function handleCompletion(c) {
|
|
|
7126
7186
|
anthropicPayload.model = providerModelAlias.model;
|
|
7127
7187
|
return await handleProviderMessagesForProvider(c, {
|
|
7128
7188
|
payload: anthropicPayload,
|
|
7129
|
-
provider: providerModelAlias.provider
|
|
7189
|
+
provider: providerModelAlias.provider,
|
|
7190
|
+
usageEndpoint: dispatchOptions.usageEndpoint
|
|
7130
7191
|
});
|
|
7131
7192
|
}
|
|
7132
|
-
debugJson(logger$
|
|
7193
|
+
debugJson(logger$9, "Anthropic request payload:", anthropicPayload);
|
|
7133
7194
|
normalizeSystemMessages(anthropicPayload);
|
|
7134
7195
|
sanitizeIdeTools(anthropicPayload);
|
|
7135
7196
|
const subagentMarker = parseSubagentMarkerFromFirstUser(anthropicPayload);
|
|
7136
|
-
if (subagentMarker) debugJson(logger$
|
|
7197
|
+
if (subagentMarker) debugJson(logger$9, "Detected Subagent marker:", subagentMarker);
|
|
7137
7198
|
let sessionId = getRootSessionId(anthropicPayload, c);
|
|
7138
|
-
const compactType = getCompactType(anthropicPayload);
|
|
7199
|
+
const compactType = dispatchOptions.compactType ?? getCompactType(anthropicPayload);
|
|
7139
7200
|
const anthropicBeta = c.req.header("anthropic-beta");
|
|
7140
|
-
logger$
|
|
7201
|
+
logger$9.debug("Anthropic Beta header:", anthropicBeta);
|
|
7141
7202
|
if (!state.tokenBasedBilling && !shouldUseClaudeAutoModel) {
|
|
7142
7203
|
const tools = anthropicPayload.tools;
|
|
7143
7204
|
const noTools = !tools || tools.length === 0;
|
|
7144
7205
|
if (anthropicBeta && noTools && compactType === 0) anthropicPayload.model = getSmallModel();
|
|
7145
7206
|
}
|
|
7146
|
-
if (compactType) logger$
|
|
7207
|
+
if (compactType) logger$9.debug("Compact request type:", compactType);
|
|
7147
7208
|
if (!state.tokenBasedBilling) {
|
|
7148
7209
|
const lastMessageCacheControl = getLastMessageContentCacheControl(anthropicPayload.messages.at(-1));
|
|
7149
7210
|
stripToolReferenceTurnBoundary(anthropicPayload);
|
|
@@ -7151,9 +7212,9 @@ async function handleCompletion(c) {
|
|
|
7151
7212
|
applyLastMessageCacheControl(anthropicPayload, lastMessageCacheControl);
|
|
7152
7213
|
}
|
|
7153
7214
|
const requestId = generateRequestIdFromPayload(anthropicPayload, sessionId);
|
|
7154
|
-
logger$
|
|
7215
|
+
logger$9.debug("Generated request ID:", requestId);
|
|
7155
7216
|
if (!sessionId) sessionId = getUUID(requestId);
|
|
7156
|
-
logger$
|
|
7217
|
+
logger$9.debug("Extracted session ID:", sessionId);
|
|
7157
7218
|
const selectedModel = findEndpointModel(anthropicPayload.model);
|
|
7158
7219
|
anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model;
|
|
7159
7220
|
if (shouldUseMessagesApi(selectedModel)) return await messagesFlowHandlers.handleWithMessagesApi(c, anthropicPayload, {
|
|
@@ -7163,7 +7224,8 @@ async function handleCompletion(c) {
|
|
|
7163
7224
|
requestId,
|
|
7164
7225
|
sessionId,
|
|
7165
7226
|
compactType,
|
|
7166
|
-
logger: logger$
|
|
7227
|
+
logger: logger$9,
|
|
7228
|
+
usageEndpoint: dispatchOptions.usageEndpoint
|
|
7167
7229
|
});
|
|
7168
7230
|
if (shouldUseResponsesApi(selectedModel, compactType)) return await messagesFlowHandlers.handleWithResponsesApi(c, anthropicPayload, {
|
|
7169
7231
|
subagentMarker,
|
|
@@ -7171,7 +7233,8 @@ async function handleCompletion(c) {
|
|
|
7171
7233
|
requestId,
|
|
7172
7234
|
sessionId,
|
|
7173
7235
|
compactType,
|
|
7174
|
-
logger: logger$
|
|
7236
|
+
logger: logger$9,
|
|
7237
|
+
usageEndpoint: dispatchOptions.usageEndpoint
|
|
7175
7238
|
});
|
|
7176
7239
|
return await messagesFlowHandlers.handleWithChatCompletions(c, anthropicPayload, {
|
|
7177
7240
|
subagentMarker,
|
|
@@ -7179,16 +7242,17 @@ async function handleCompletion(c) {
|
|
|
7179
7242
|
requestId,
|
|
7180
7243
|
sessionId,
|
|
7181
7244
|
compactType,
|
|
7182
|
-
logger: logger$
|
|
7245
|
+
logger: logger$9,
|
|
7246
|
+
usageEndpoint: dispatchOptions.usageEndpoint
|
|
7183
7247
|
});
|
|
7184
7248
|
}
|
|
7185
|
-
const MESSAGES_ENDPOINT = "/v1/messages";
|
|
7249
|
+
const MESSAGES_ENDPOINT$1 = "/v1/messages";
|
|
7186
7250
|
const shouldUseResponsesApi = (selectedModel, compactType) => {
|
|
7187
7251
|
return Boolean(getResponsesTransportForModel(selectedModel, { compactType }));
|
|
7188
7252
|
};
|
|
7189
7253
|
const shouldUseMessagesApi = (selectedModel) => {
|
|
7190
7254
|
if (!isMessagesApiEnabled()) return false;
|
|
7191
|
-
return selectedModel?.supported_endpoints?.includes(MESSAGES_ENDPOINT) ?? false;
|
|
7255
|
+
return selectedModel?.supported_endpoints?.includes(MESSAGES_ENDPOINT$1) ?? false;
|
|
7192
7256
|
};
|
|
7193
7257
|
//#endregion
|
|
7194
7258
|
//#region src/routes/messages/route.ts
|
|
@@ -7209,20 +7273,50 @@ messageRoutes.post("/count_tokens", async (c) => {
|
|
|
7209
7273
|
});
|
|
7210
7274
|
//#endregion
|
|
7211
7275
|
//#region src/routes/models/codex-models.ts
|
|
7212
|
-
const logger$
|
|
7276
|
+
const logger$8 = createHandlerLogger("codex-models-handler");
|
|
7213
7277
|
const CODEX_USER_AGENT_PATTERN = /^codex/iu;
|
|
7278
|
+
const FALLBACK_BASE_INSTRUCTIONS = "You are a coding agent. Follow the user's instructions, inspect the workspace as needed, use the available tools carefully, and continue until the task is complete.";
|
|
7279
|
+
const FALLBACK_AVAILABLE_IN_PLANS = [
|
|
7280
|
+
"business",
|
|
7281
|
+
"edu",
|
|
7282
|
+
"edu_plus",
|
|
7283
|
+
"edu_pro",
|
|
7284
|
+
"education",
|
|
7285
|
+
"enterprise",
|
|
7286
|
+
"enterprise_cbp_automation",
|
|
7287
|
+
"enterprise_cbp_usage_based",
|
|
7288
|
+
"finserv",
|
|
7289
|
+
"free",
|
|
7290
|
+
"free_workspace",
|
|
7291
|
+
"go",
|
|
7292
|
+
"hc",
|
|
7293
|
+
"k12",
|
|
7294
|
+
"plus",
|
|
7295
|
+
"pro",
|
|
7296
|
+
"prolite",
|
|
7297
|
+
"quorum",
|
|
7298
|
+
"sci",
|
|
7299
|
+
"self_serve_business_usage_based",
|
|
7300
|
+
"team"
|
|
7301
|
+
];
|
|
7302
|
+
const DEFAULT_REASONING_EFFORTS = [
|
|
7303
|
+
"high",
|
|
7304
|
+
"xhigh",
|
|
7305
|
+
"max",
|
|
7306
|
+
"ultra"
|
|
7307
|
+
];
|
|
7214
7308
|
function isCodexUserAgent(userAgent) {
|
|
7215
7309
|
return CODEX_USER_AGENT_PATTERN.test(userAgent?.trim() ?? "");
|
|
7216
7310
|
}
|
|
7217
7311
|
async function logCodexModelsResponse(response) {
|
|
7218
7312
|
try {
|
|
7219
7313
|
const models = await response.clone().json();
|
|
7220
|
-
debugJson(logger$
|
|
7314
|
+
debugJson(logger$8, "models.codex.response", {
|
|
7221
7315
|
statusCode: response.status,
|
|
7222
7316
|
models
|
|
7223
7317
|
});
|
|
7224
7318
|
} catch (error) {
|
|
7225
|
-
logger$
|
|
7319
|
+
logger$8.warn("models.codex.response_log_error", { error });
|
|
7226
7320
|
}
|
|
7227
7321
|
}
|
|
7228
7322
|
/**
|
|
@@ -7240,12 +7334,152 @@ async function handleCodexModelsProxy(c, resolvedProviderConfig) {
|
|
|
7240
7334
|
await logCodexModelsResponse(upstreamResponse);
|
|
7241
7335
|
return createProviderProxyResponse(upstreamResponse);
|
|
7242
7336
|
}
|
|
7337
|
+
async function handleMergedCodexModels(c, candidatesRequest, options = {}) {
|
|
7338
|
+
const [upstreamCatalog, candidates] = await Promise.all([tryGetCodexCatalog(c), Promise.resolve(candidatesRequest).catch((error) => {
|
|
7339
|
+
logger$8.warn("models.codex.candidates_error", { error });
|
|
7340
|
+
return [];
|
|
7341
|
+
})]);
|
|
7342
|
+
const upstreamModels = upstreamCatalog?.models ?? [];
|
|
7343
|
+
const template = selectTemplate(upstreamModels);
|
|
7344
|
+
const catalogModelsBySlug = new Map(upstreamModels.map((model) => [model.slug, model]));
|
|
7345
|
+
const seenSlugs = new Set(upstreamModels.map((model) => model.slug));
|
|
7346
|
+
const codexProviderAliases = options.includeCodexProviderAliases ? upstreamModels.flatMap((model) => {
|
|
7347
|
+
const slug = `codex/${model.slug}`;
|
|
7348
|
+
if (seenSlugs.has(slug)) return [];
|
|
7349
|
+
seenSlugs.add(slug);
|
|
7350
|
+
return [{
|
|
7351
|
+
...model,
|
|
7352
|
+
slug
|
|
7353
|
+
}];
|
|
7354
|
+
}) : [];
|
|
7355
|
+
const syntheticModels = candidates.filter((candidate) => !seenSlugs.has(candidate.slug)).flatMap((candidate, index) => {
|
|
7356
|
+
const catalogModel = candidate.catalogSlug ? catalogModelsBySlug.get(candidate.catalogSlug) : void 0;
|
|
7357
|
+
if (catalogModel) return [{
|
|
7358
|
+
...catalogModel,
|
|
7359
|
+
slug: candidate.slug
|
|
7360
|
+
}];
|
|
7361
|
+
if (candidate.catalogMatchRequired) return [];
|
|
7362
|
+
return [createSyntheticCodexModel(candidate, template, upstreamModels.length + index)];
|
|
7363
|
+
});
|
|
7364
|
+
const response = {
|
|
7365
|
+
...upstreamCatalog ?? {},
|
|
7366
|
+
models: [
|
|
7367
|
+
...upstreamModels,
|
|
7368
|
+
...codexProviderAliases,
|
|
7369
|
+
...syntheticModels
|
|
7370
|
+
]
|
|
7371
|
+
};
|
|
7372
|
+
debugJson(logger$8, "models.codex.merged_response", {
|
|
7373
|
+
upstreamCount: upstreamModels.length,
|
|
7374
|
+
codexProviderAliasCount: codexProviderAliases.length,
|
|
7375
|
+
syntheticCount: syntheticModels.length,
|
|
7376
|
+
models: response
|
|
7377
|
+
});
|
|
7378
|
+
return c.json(response);
|
|
7379
|
+
}
|
|
7380
|
+
function createSyntheticCodexModel(candidate, template, priority) {
|
|
7381
|
+
const reasoningEfforts = candidate.reasoningEfforts.length > 0 ? candidate.reasoningEfforts : DEFAULT_REASONING_EFFORTS;
|
|
7382
|
+
const defaultReasoningEffort = reasoningEfforts.includes(candidate.defaultReasoningEffort) ? candidate.defaultReasoningEffort : reasoningEfforts[0];
|
|
7383
|
+
const supportsReasoning = reasoningEfforts.some((effort) => effort !== "none");
|
|
7384
|
+
const inputModalities = [...new Set(candidate.inputModalities)];
|
|
7385
|
+
return {
|
|
7386
|
+
...template ?? {},
|
|
7387
|
+
slug: candidate.slug,
|
|
7388
|
+
display_name: candidate.displayName,
|
|
7389
|
+
description: candidate.description,
|
|
7390
|
+
priority,
|
|
7391
|
+
visibility: "list",
|
|
7392
|
+
supported_in_api: true,
|
|
7393
|
+
minimal_client_version: "0.0.0",
|
|
7394
|
+
prefer_websockets: false,
|
|
7395
|
+
support_verbosity: false,
|
|
7396
|
+
default_verbosity: "medium",
|
|
7397
|
+
apply_patch_tool_type: "freeform",
|
|
7398
|
+
web_search_tool_type: "text_and_image",
|
|
7399
|
+
supports_search_tool: false,
|
|
7400
|
+
use_responses_lite: true,
|
|
7401
|
+
tool_mode: "code_mode_only",
|
|
7402
|
+
multi_agent_version: "v2",
|
|
7403
|
+
shell_type: "shell_command",
|
|
7404
|
+
experimental_supported_tools: [],
|
|
7405
|
+
input_modalities: inputModalities,
|
|
7406
|
+
supports_image_detail_original: false,
|
|
7407
|
+
supports_parallel_tool_calls: candidate.supportsParallelToolCalls,
|
|
7408
|
+
context_window: candidate.contextWindow,
|
|
7409
|
+
max_context_window: candidate.contextWindow,
|
|
7410
|
+
max_output_tokens: candidate.maxOutputTokens,
|
|
7411
|
+
auto_compact_token_limit: null,
|
|
7412
|
+
comp_hash: null,
|
|
7413
|
+
effective_context_window_percent: 95,
|
|
7414
|
+
default_reasoning_level: defaultReasoningEffort,
|
|
7415
|
+
supported_reasoning_levels: reasoningEfforts.map((effort) => ({
|
|
7416
|
+
effort,
|
|
7417
|
+
description: `${effort} reasoning effort`
|
|
7418
|
+
})),
|
|
7419
|
+
supports_reasoning_summary_parameter: supportsReasoning,
|
|
7420
|
+
supports_reasoning_summaries: supportsReasoning,
|
|
7421
|
+
default_reasoning_summary: supportsReasoning ? "auto" : "none",
|
|
7422
|
+
reasoning_summary_format: "experimental",
|
|
7423
|
+
availability_nux: null,
|
|
7424
|
+
upgrade: null,
|
|
7425
|
+
available_in_plans: template?.available_in_plans ?? FALLBACK_AVAILABLE_IN_PLANS,
|
|
7426
|
+
model_messages: template?.model_messages ?? {
|
|
7427
|
+
instructions_template: FALLBACK_BASE_INSTRUCTIONS,
|
|
7428
|
+
instructions_variables: null,
|
|
7429
|
+
approvals: null,
|
|
7430
|
+
auto_review: null,
|
|
7431
|
+
permissions: null
|
|
7432
|
+
},
|
|
7433
|
+
auto_review_model_override: null,
|
|
7434
|
+
default_service_tier: null,
|
|
7435
|
+
service_tiers: [],
|
|
7436
|
+
additional_speed_tiers: [],
|
|
7437
|
+
include_skills_usage_instructions: false,
|
|
7438
|
+
truncation_policy: {
|
|
7439
|
+
mode: "tokens",
|
|
7440
|
+
limit: 1e4
|
|
7441
|
+
},
|
|
7442
|
+
base_instructions: template?.base_instructions?.trim() ? template.base_instructions : FALLBACK_BASE_INSTRUCTIONS
|
|
7443
|
+
};
|
|
7444
|
+
}
|
|
7445
|
+
async function tryGetCodexCatalog(c) {
|
|
7446
|
+
try {
|
|
7447
|
+
if (!await resolveProviderConfig("codex")) return null;
|
|
7448
|
+
const response = await forwardCodexModels(c.req.url, c.req.raw.headers);
|
|
7449
|
+
if (!response.ok) {
|
|
7450
|
+
logger$8.warn("models.codex.catalog_fallback", { statusCode: response.status });
|
|
7451
|
+
return null;
|
|
7452
|
+
}
|
|
7453
|
+
const body = await response.json();
|
|
7454
|
+
if (!isCodexModelsResponse(body)) {
|
|
7455
|
+
logger$8.warn("models.codex.catalog_invalid");
|
|
7456
|
+
return null;
|
|
7457
|
+
}
|
|
7458
|
+
return body;
|
|
7459
|
+
} catch (error) {
|
|
7460
|
+
logger$8.warn("models.codex.catalog_error", { error });
|
|
7461
|
+
return null;
|
|
7462
|
+
}
|
|
7463
|
+
}
|
|
7464
|
+
function selectTemplate(models) {
|
|
7465
|
+
return models.find((model) => model.visibility === "list" && model.supported_in_api !== false) ?? models[0];
|
|
7466
|
+
}
|
|
7467
|
+
function isCodexModelsResponse(value) {
|
|
7468
|
+
if (!isRecord$2(value) || !Array.isArray(value.models)) return false;
|
|
7469
|
+
return value.models.every((model) => isRecord$2(model) && typeof model.slug === "string");
|
|
7470
|
+
}
|
|
7471
|
+
function isRecord$2(value) {
|
|
7472
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7473
|
+
}
|
|
7243
7474
|
//#endregion
|
|
7244
7475
|
//#region src/routes/models/route.ts
|
|
7245
7476
|
const modelRoutes = new Hono();
|
|
7246
|
-
const logger$
|
|
7477
|
+
const logger$7 = createHandlerLogger("models-handler");
|
|
7247
7478
|
const EPOCH_ISO = (/* @__PURE__ */ new Date(0)).toISOString();
|
|
7248
|
-
|
|
7479
|
+
const RESPONSES_ENDPOINTS = new Set(["/responses", "ws:/responses"]);
|
|
7480
|
+
const MESSAGES_ENDPOINT = "/v1/messages";
|
|
7481
|
+
const CHAT_COMPLETIONS_ENDPOINT = "/chat/completions";
|
|
7482
|
+
function isRecord$1(value) {
|
|
7249
7483
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7250
7484
|
}
|
|
7251
7485
|
function normalizeCopilotModel(model) {
|
|
@@ -7263,24 +7497,24 @@ function normalizeCopilotModel(model) {
|
|
|
7263
7497
|
display_name: model.name
|
|
7264
7498
|
};
|
|
7265
7499
|
}
|
|
7266
|
-
function getStringField(model, field) {
|
|
7500
|
+
function getStringField$1(model, field) {
|
|
7267
7501
|
const value = model[field];
|
|
7268
7502
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
7269
7503
|
}
|
|
7270
7504
|
function normalizeProviderModel(provider, model) {
|
|
7271
|
-
if (!isRecord(model)) return null;
|
|
7272
|
-
const rawId = getStringField(model, "id");
|
|
7505
|
+
if (!isRecord$1(model)) return null;
|
|
7506
|
+
const rawId = getStringField$1(model, "id");
|
|
7273
7507
|
if (!rawId) return null;
|
|
7274
7508
|
const id = `${provider}/${rawId}`;
|
|
7275
|
-
const name = getStringField(model, "display_name") ?? getStringField(model, "name") ?? rawId;
|
|
7276
|
-
const ownedBy = getStringField(model, "owned_by") ?? getStringField(model, "vendor") ?? provider;
|
|
7509
|
+
const name = getStringField$1(model, "display_name") ?? getStringField$1(model, "name") ?? rawId;
|
|
7510
|
+
const ownedBy = getStringField$1(model, "owned_by") ?? getStringField$1(model, "vendor") ?? provider;
|
|
7277
7511
|
return {
|
|
7278
7512
|
...model,
|
|
7279
7513
|
id,
|
|
7280
|
-
object: getStringField(model, "object") ?? "model",
|
|
7281
|
-
type: getStringField(model, "type") ?? "model",
|
|
7514
|
+
object: getStringField$1(model, "object") ?? "model",
|
|
7515
|
+
type: getStringField$1(model, "type") ?? "model",
|
|
7282
7516
|
created: typeof model.created === "number" ? model.created : 0,
|
|
7283
|
-
created_at: getStringField(model, "created_at") ?? EPOCH_ISO,
|
|
7517
|
+
created_at: getStringField$1(model, "created_at") ?? EPOCH_ISO,
|
|
7284
7518
|
owned_by: ownedBy,
|
|
7285
7519
|
display_name: name
|
|
7286
7520
|
};
|
|
@@ -7292,20 +7526,20 @@ async function getProviderModels(provider, requestHeaders) {
|
|
|
7292
7526
|
if (providerConfig.name === "codex") return getModels().data.map((model) => normalizeProviderModel(providerConfig.name, model)).filter((model) => model !== null);
|
|
7293
7527
|
const response = await forwardProviderModels(providerConfig, requestHeaders);
|
|
7294
7528
|
if (!response.ok) {
|
|
7295
|
-
logger$
|
|
7529
|
+
logger$7.warn("models.provider.skip_non_ok", {
|
|
7296
7530
|
provider,
|
|
7297
7531
|
statusCode: response.status
|
|
7298
7532
|
});
|
|
7299
7533
|
return [];
|
|
7300
7534
|
}
|
|
7301
7535
|
const body = await response.json();
|
|
7302
|
-
if (!isRecord(body) || !Array.isArray(body.data)) {
|
|
7303
|
-
logger$
|
|
7536
|
+
if (!isRecord$1(body) || !Array.isArray(body.data)) {
|
|
7537
|
+
logger$7.warn("models.provider.skip_invalid_body", { provider });
|
|
7304
7538
|
return [];
|
|
7305
7539
|
}
|
|
7306
7540
|
return body.data.map((model) => normalizeProviderModel(providerConfig.name, model)).filter((model) => model !== null);
|
|
7307
7541
|
} catch (error) {
|
|
7308
|
-
logger$
|
|
7542
|
+
logger$7.warn("models.provider.skip_error", {
|
|
7309
7543
|
provider,
|
|
7310
7544
|
error
|
|
7311
7545
|
});
|
|
@@ -7323,9 +7557,183 @@ async function getAggregatedModels(requestHeaders) {
|
|
|
7323
7557
|
return true;
|
|
7324
7558
|
});
|
|
7325
7559
|
}
|
|
7560
|
+
const CODEX_REASONING_EFFORTS = new Set([
|
|
7561
|
+
"none",
|
|
7562
|
+
"minimal",
|
|
7563
|
+
"low",
|
|
7564
|
+
"medium",
|
|
7565
|
+
"high",
|
|
7566
|
+
"xhigh",
|
|
7567
|
+
"max",
|
|
7568
|
+
"ultra"
|
|
7569
|
+
]);
|
|
7570
|
+
async function getSyntheticCodexModels(requestHeaders, providers) {
|
|
7571
|
+
const copilotModels = getCopilotCodexCandidates();
|
|
7572
|
+
const providerModels = (await Promise.allSettled(providers.map((provider) => getProviderCodexCandidates(provider, requestHeaders)))).flatMap((result) => result.status === "fulfilled" ? result.value : []);
|
|
7573
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7574
|
+
return [...copilotModels, ...providerModels.flat()].filter((candidate) => {
|
|
7575
|
+
if (seen.has(candidate.slug)) return false;
|
|
7576
|
+
seen.add(candidate.slug);
|
|
7577
|
+
return true;
|
|
7578
|
+
});
|
|
7579
|
+
}
|
|
7580
|
+
function getCopilotCodexCandidates() {
|
|
7581
|
+
const candidates = [];
|
|
7582
|
+
for (const model of state.models?.data ?? []) try {
|
|
7583
|
+
if (isCopilotMessagesFallbackModel(model)) candidates.push(createCopilotCodexCandidate(model));
|
|
7584
|
+
} catch (error) {
|
|
7585
|
+
logger$7.warn("models.codex.copilot_skip_error", {
|
|
7586
|
+
modelId: model.id,
|
|
7587
|
+
error
|
|
7588
|
+
});
|
|
7589
|
+
}
|
|
7590
|
+
return candidates;
|
|
7591
|
+
}
|
|
7592
|
+
function isCopilotMessagesFallbackModel(model) {
|
|
7593
|
+
const endpoints = model.supported_endpoints ?? [];
|
|
7594
|
+
return endpoints.some((endpoint) => endpoint === MESSAGES_ENDPOINT || endpoint === CHAT_COMPLETIONS_ENDPOINT) && !endpoints.some((endpoint) => RESPONSES_ENDPOINTS.has(endpoint)) && model.capabilities.supports.tool_calls !== false;
|
|
7595
|
+
}
|
|
7596
|
+
function createCopilotCodexCandidate(model) {
|
|
7597
|
+
const reasoningEfforts = normalizeReasoningEfforts(model.capabilities.supports.reasoning_effort);
|
|
7598
|
+
const usesNativeMessages = model.supported_endpoints?.includes(MESSAGES_ENDPOINT);
|
|
7599
|
+
return {
|
|
7600
|
+
slug: toClientModelId(model.id),
|
|
7601
|
+
displayName: model.name,
|
|
7602
|
+
description: usesNativeMessages ? `${model.name} through the Copilot Messages adapter.` : `${model.name} through the Copilot Messages-to-Chat adapter.`,
|
|
7603
|
+
contextWindow: positiveNumber(model.capabilities.limits.max_context_window_tokens, 256e3),
|
|
7604
|
+
maxOutputTokens: positiveNumber(model.capabilities.limits.max_output_tokens, 32e3),
|
|
7605
|
+
inputModalities: model.capabilities.supports.vision ? ["text", "image"] : ["text"],
|
|
7606
|
+
reasoningEfforts,
|
|
7607
|
+
defaultReasoningEffort: selectDefaultReasoningEffort(reasoningEfforts),
|
|
7608
|
+
supportsParallelToolCalls: Boolean(model.capabilities.supports.parallel_tool_calls)
|
|
7609
|
+
};
|
|
7610
|
+
}
|
|
7611
|
+
async function getProviderCodexCandidates(provider, requestHeaders) {
|
|
7612
|
+
if (provider === "codex") return [];
|
|
7613
|
+
try {
|
|
7614
|
+
const providerConfig = await resolveProviderConfig(provider);
|
|
7615
|
+
if (!providerConfig || providerConfig.name === "codex") return [];
|
|
7616
|
+
const remoteModels = await getProviderModelRecords(providerConfig, requestHeaders);
|
|
7617
|
+
const remoteById = new Map(remoteModels.flatMap((model) => {
|
|
7618
|
+
const id = getStringField$1(model, "id");
|
|
7619
|
+
return id ? [[id, model]] : [];
|
|
7620
|
+
}));
|
|
7621
|
+
const modelIds = new Set([...remoteById.keys(), ...Object.keys(providerConfig.models ?? {})]);
|
|
7622
|
+
const candidates = [];
|
|
7623
|
+
for (const modelId of modelIds) {
|
|
7624
|
+
const effectiveType = resolveEffectiveProviderType(providerConfig, modelId);
|
|
7625
|
+
if (!isMessagesFallbackProviderType(effectiveType) && effectiveType !== "openai-responses") continue;
|
|
7626
|
+
const modelConfig = providerConfig.models?.[modelId];
|
|
7627
|
+
if (modelConfig?.codex?.enabled === false) continue;
|
|
7628
|
+
candidates.push(createProviderCodexCandidate(providerConfig, modelId, remoteById.get(modelId), modelConfig, effectiveType));
|
|
7629
|
+
}
|
|
7630
|
+
return candidates;
|
|
7631
|
+
} catch (error) {
|
|
7632
|
+
logger$7.warn("models.codex.provider_skip_error", {
|
|
7633
|
+
provider,
|
|
7634
|
+
error
|
|
7635
|
+
});
|
|
7636
|
+
return [];
|
|
7637
|
+
}
|
|
7638
|
+
}
|
|
7639
|
+
function isMessagesFallbackProviderType(type) {
|
|
7640
|
+
return type === "anthropic" || type === "openai-compatible";
|
|
7641
|
+
}
|
|
7642
|
+
async function getProviderModelRecords(providerConfig, requestHeaders) {
|
|
7643
|
+
try {
|
|
7644
|
+
const response = await forwardProviderModels(providerConfig, requestHeaders);
|
|
7645
|
+
if (!response.ok) {
|
|
7646
|
+
logger$7.warn("models.codex.provider_skip_non_ok", {
|
|
7647
|
+
provider: providerConfig.name,
|
|
7648
|
+
statusCode: response.status
|
|
7649
|
+
});
|
|
7650
|
+
return [];
|
|
7651
|
+
}
|
|
7652
|
+
const body = await response.json();
|
|
7653
|
+
if (!isRecord$1(body) || !Array.isArray(body.data)) return [];
|
|
7654
|
+
return body.data.filter(isRecord$1);
|
|
7655
|
+
} catch (error) {
|
|
7656
|
+
logger$7.warn("models.codex.provider_models_error", {
|
|
7657
|
+
provider: providerConfig.name,
|
|
7658
|
+
error
|
|
7659
|
+
});
|
|
7660
|
+
return [];
|
|
7661
|
+
}
|
|
7662
|
+
}
|
|
7663
|
+
function createProviderCodexCandidate(providerConfig, modelId, remoteModel, modelConfig, effectiveType) {
|
|
7664
|
+
const codexConfig = modelConfig?.codex;
|
|
7665
|
+
const configuredReasoningEfforts = normalizeReasoningEfforts(codexConfig?.reasoningEfforts);
|
|
7666
|
+
const reasoningEfforts = configuredReasoningEfforts.length > 0 ? configuredReasoningEfforts : normalizeRemoteReasoningEfforts(remoteModel);
|
|
7667
|
+
const configuredModalities = normalizeInputModalities(codexConfig?.inputModalities);
|
|
7668
|
+
const remoteModalities = normalizeInputModalities(remoteModel?.input_modalities ?? remoteModel?.modalities);
|
|
7669
|
+
const displayName = getStringField$1(remoteModel ?? {}, "display_name") ?? getStringField$1(remoteModel ?? {}, "name") ?? modelId;
|
|
7670
|
+
const adapterName = effectiveType === "anthropic" ? "Messages" : "Messages-to-Chat";
|
|
7671
|
+
return {
|
|
7672
|
+
slug: `${providerConfig.name}/${modelId}`,
|
|
7673
|
+
catalogSlug: modelId,
|
|
7674
|
+
catalogMatchRequired: effectiveType === "openai-responses",
|
|
7675
|
+
displayName: `${displayName} (${providerConfig.name})`,
|
|
7676
|
+
description: `${displayName} through the ${providerConfig.name} ${adapterName} adapter.`,
|
|
7677
|
+
contextWindow: positiveNumber(codexConfig?.contextWindow ?? getFirstPositiveNumber(remoteModel, [
|
|
7678
|
+
"context_window",
|
|
7679
|
+
"context_length",
|
|
7680
|
+
"max_context_length",
|
|
7681
|
+
"max_model_len"
|
|
7682
|
+
]), 256e3),
|
|
7683
|
+
maxOutputTokens: positiveNumber(codexConfig?.maxOutputTokens ?? getFirstPositiveNumber(remoteModel, ["max_output_tokens"]), 32e3),
|
|
7684
|
+
inputModalities: resolveInputModalities(providerConfig.name, configuredModalities, remoteModalities),
|
|
7685
|
+
reasoningEfforts,
|
|
7686
|
+
defaultReasoningEffort: selectDefaultReasoningEffort(reasoningEfforts, codexConfig?.defaultReasoningEffort),
|
|
7687
|
+
supportsParallelToolCalls: codexConfig?.supportsParallelToolCalls ?? getBooleanField(remoteModel, "supports_parallel_tool_calls") ?? false
|
|
7688
|
+
};
|
|
7689
|
+
}
|
|
7690
|
+
function normalizeRemoteReasoningEfforts(model) {
|
|
7691
|
+
if (!model) return [];
|
|
7692
|
+
const value = model.reasoning_efforts ?? model.supported_reasoning_levels;
|
|
7693
|
+
if (!Array.isArray(value)) return [];
|
|
7694
|
+
return normalizeReasoningEfforts(value.map((entry) => isRecord$1(entry) && typeof entry.effort === "string" ? entry.effort : entry));
|
|
7695
|
+
}
|
|
7696
|
+
function normalizeReasoningEfforts(value) {
|
|
7697
|
+
if (!Array.isArray(value)) return [];
|
|
7698
|
+
return [...new Set(value.filter((effort) => typeof effort === "string" && CODEX_REASONING_EFFORTS.has(effort)))];
|
|
7699
|
+
}
|
|
7700
|
+
function normalizeInputModalities(value) {
|
|
7701
|
+
if (!Array.isArray(value)) return [];
|
|
7702
|
+
return [...new Set(value.filter((modality) => modality === "text" || modality === "image"))];
|
|
7703
|
+
}
|
|
7704
|
+
function resolveInputModalities(providerName, configuredModalities, remoteModalities) {
|
|
7705
|
+
if (configuredModalities.length > 0) return configuredModalities;
|
|
7706
|
+
if (providerName === "kimi") {
|
|
7707
|
+
const modalities = remoteModalities.length > 0 ? remoteModalities : ["text"];
|
|
7708
|
+
return [...new Set([...modalities, "image"])];
|
|
7709
|
+
}
|
|
7710
|
+
return remoteModalities.length > 0 ? remoteModalities : ["text"];
|
|
7711
|
+
}
|
|
7712
|
+
function selectDefaultReasoningEffort(efforts, configured) {
|
|
7713
|
+
if (configured && efforts.includes(configured)) return configured;
|
|
7714
|
+
if (efforts.includes("max")) return "max";
|
|
7715
|
+
return efforts[0] ?? "max";
|
|
7716
|
+
}
|
|
7717
|
+
function positiveNumber(value, fallback) {
|
|
7718
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
|
|
7719
|
+
}
|
|
7720
|
+
function getFirstPositiveNumber(model, fields) {
|
|
7721
|
+
if (!model) return void 0;
|
|
7722
|
+
for (const field of fields) {
|
|
7723
|
+
const value = model[field];
|
|
7724
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
|
|
7725
|
+
}
|
|
7726
|
+
}
|
|
7727
|
+
function getBooleanField(model, field) {
|
|
7728
|
+
const value = model?.[field];
|
|
7729
|
+
return typeof value === "boolean" ? value : void 0;
|
|
7730
|
+
}
|
|
7326
7731
|
modelRoutes.get("/", async (c) => {
|
|
7327
7732
|
try {
|
|
7328
|
-
if (isCodexUserAgent(c.req.header("user-agent")))
|
|
7733
|
+
if (isCodexUserAgent(c.req.header("user-agent"))) {
|
|
7734
|
+
const enabledProviders = listEnabledProviders();
|
|
7735
|
+
return await handleMergedCodexModels(c, getSyntheticCodexModels(c.req.raw.headers, enabledProviders), { includeCodexProviderAliases: enabledProviders.includes("codex") });
|
|
7736
|
+
}
|
|
7329
7737
|
const models = await getAggregatedModels(c.req.raw.headers);
|
|
7330
7738
|
return c.json({
|
|
7331
7739
|
object: "list",
|
|
@@ -7338,7 +7746,7 @@ modelRoutes.get("/", async (c) => {
|
|
|
7338
7746
|
});
|
|
7339
7747
|
//#endregion
|
|
7340
7748
|
//#region src/routes/provider/alpha-search/route.ts
|
|
7341
|
-
const logger$
|
|
7749
|
+
const logger$6 = createHandlerLogger("provider-alpha-search-handler");
|
|
7342
7750
|
const providerAlphaSearchRoutes = new Hono();
|
|
7343
7751
|
providerAlphaSearchRoutes.post("/", async (c) => {
|
|
7344
7752
|
const provider = c.req.param("provider") ?? "";
|
|
@@ -7349,19 +7757,19 @@ providerAlphaSearchRoutes.post("/", async (c) => {
|
|
|
7349
7757
|
type: "invalid_request_error"
|
|
7350
7758
|
} }, 404);
|
|
7351
7759
|
if (providerConfig.name === "codex") return await handleAlphaSearchRequest(c, providerConfig);
|
|
7352
|
-
await debugJsonAsync(logger$
|
|
7760
|
+
await debugJsonAsync(logger$6, "provider.alpha_search.request", async () => ({
|
|
7353
7761
|
body: await c.req.raw.clone().text(),
|
|
7354
7762
|
provider
|
|
7355
7763
|
}));
|
|
7356
7764
|
const upstreamResponse = await forwardProviderAlphaSearch(providerConfig, c.req.raw);
|
|
7357
|
-
await debugJsonAsync(logger$
|
|
7765
|
+
await debugJsonAsync(logger$6, "provider.alpha_search.response", async () => ({
|
|
7358
7766
|
body: await upstreamResponse.clone().text(),
|
|
7359
7767
|
provider,
|
|
7360
7768
|
statusCode: upstreamResponse.status
|
|
7361
7769
|
}));
|
|
7362
7770
|
return createProviderProxyResponse(upstreamResponse);
|
|
7363
7771
|
} catch (error) {
|
|
7364
|
-
logger$
|
|
7772
|
+
logger$6.error("provider.alpha_search.error", {
|
|
7365
7773
|
provider,
|
|
7366
7774
|
error
|
|
7367
7775
|
});
|
|
@@ -7370,7 +7778,7 @@ providerAlphaSearchRoutes.post("/", async (c) => {
|
|
|
7370
7778
|
});
|
|
7371
7779
|
//#endregion
|
|
7372
7780
|
//#region src/routes/provider/images/route.ts
|
|
7373
|
-
const logger$
|
|
7781
|
+
const logger$5 = createHandlerLogger("provider-images-handler");
|
|
7374
7782
|
const providerImageRoutes = new Hono();
|
|
7375
7783
|
function getContentMetadata(headers) {
|
|
7376
7784
|
return {
|
|
@@ -7387,23 +7795,23 @@ async function handleProviderImages(c, operation) {
|
|
|
7387
7795
|
type: "invalid_request_error"
|
|
7388
7796
|
} }, 404);
|
|
7389
7797
|
if (providerConfig.name === "codex") return await handleCodexImages(c, operation, providerConfig);
|
|
7390
|
-
if (operation === "generations") await debugJsonAsync(logger$
|
|
7798
|
+
if (operation === "generations") await debugJsonAsync(logger$5, "provider.images.generations.request", async () => ({
|
|
7391
7799
|
body: await c.req.raw.clone().text(),
|
|
7392
7800
|
provider
|
|
7393
7801
|
}));
|
|
7394
|
-
else debugJson(logger$
|
|
7802
|
+
else debugJson(logger$5, "provider.images.edits.request", {
|
|
7395
7803
|
...getContentMetadata(c.req.raw.headers),
|
|
7396
7804
|
provider
|
|
7397
7805
|
});
|
|
7398
7806
|
const upstreamResponse = await forwardProviderImages(providerConfig, c.req.raw, operation);
|
|
7399
|
-
debugJson(logger$
|
|
7807
|
+
debugJson(logger$5, `provider.images.${operation}.response`, {
|
|
7400
7808
|
...getContentMetadata(upstreamResponse.headers),
|
|
7401
7809
|
provider,
|
|
7402
7810
|
statusCode: upstreamResponse.status
|
|
7403
7811
|
});
|
|
7404
7812
|
return createProviderProxyResponse(upstreamResponse);
|
|
7405
7813
|
} catch (error) {
|
|
7406
|
-
logger$
|
|
7814
|
+
logger$5.error(`provider.images.${operation}.error`, {
|
|
7407
7815
|
provider,
|
|
7408
7816
|
error
|
|
7409
7817
|
});
|
|
@@ -7431,7 +7839,7 @@ providerMessageRoutes.post("/count_tokens", async (c) => {
|
|
|
7431
7839
|
});
|
|
7432
7840
|
//#endregion
|
|
7433
7841
|
//#region src/routes/provider/models/route.ts
|
|
7434
|
-
const logger$
|
|
7842
|
+
const logger$4 = createHandlerLogger("provider-models-handler");
|
|
7435
7843
|
const providerModelRoutes = new Hono();
|
|
7436
7844
|
providerModelRoutes.get("/", async (c) => {
|
|
7437
7845
|
const provider = c.req.param("provider") ?? "";
|
|
@@ -7451,13 +7859,13 @@ providerModelRoutes.get("/", async (c) => {
|
|
|
7451
7859
|
});
|
|
7452
7860
|
}
|
|
7453
7861
|
const upstreamResponse = await forwardProviderModels(providerConfig, c.req.raw.headers);
|
|
7454
|
-
logger$
|
|
7862
|
+
logger$4.debug("provider.models.response", {
|
|
7455
7863
|
provider,
|
|
7456
7864
|
statusCode: upstreamResponse.status
|
|
7457
7865
|
});
|
|
7458
7866
|
return createProviderProxyResponse(upstreamResponse);
|
|
7459
7867
|
} catch (error) {
|
|
7460
|
-
logger$
|
|
7868
|
+
logger$4.error("provider.models.error", {
|
|
7461
7869
|
provider,
|
|
7462
7870
|
error
|
|
7463
7871
|
});
|
|
@@ -7465,6 +7873,1502 @@ providerModelRoutes.get("/", async (c) => {
|
|
|
7465
7873
|
}
|
|
7466
7874
|
});
|
|
7467
7875
|
//#endregion
|
|
7876
|
+
//#region src/routes/responses/messages-translation.ts
|
|
7877
|
+
const MESSAGES_COMPACTION_PREFIX = "copilot-api:messages-compaction:v1:";
|
|
7878
|
+
const MESSAGES_COMPACTION_PROMPT = [
|
|
7879
|
+
"You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.",
|
|
7880
|
+
"Do NOT continue the task, make changes, or call any tools. Your only output must be the handoff summary.",
|
|
7881
|
+
"",
|
|
7882
|
+
"Include:",
|
|
7883
|
+
"- Current progress and key decisions made",
|
|
7884
|
+
"- Important context, constraints, or user preferences",
|
|
7885
|
+
"- What remains to be done (clear next steps)",
|
|
7886
|
+
"- Any critical data, examples, or references needed to continue",
|
|
7887
|
+
"",
|
|
7888
|
+
"Be concise, structured, and focused on helping the next LLM seamlessly continue the work.",
|
|
7889
|
+
"",
|
|
7890
|
+
compactTextOnlyGuard
|
|
7891
|
+
].join("\n");
|
|
7892
|
+
const COMPACTION_REPLAY_PROMPT = "The previous conversation was compacted. Continue from this handoff summary:\n\n";
|
|
7893
|
+
const MAX_DEVELOPER_PROMPTS = 5;
|
|
7894
|
+
const TOOL_NAME_PATTERN = /^[A-Za-z0-9_-]{1,64}$/u;
|
|
7895
|
+
const CUSTOM_TOOL_INPUT_SCHEMA = {
|
|
7896
|
+
type: "object",
|
|
7897
|
+
properties: { input: { type: "string" } },
|
|
7898
|
+
required: ["input"],
|
|
7899
|
+
additionalProperties: false
|
|
7900
|
+
};
|
|
7901
|
+
var ResponsesMessagesTranslationError = class extends Error {
|
|
7902
|
+
status;
|
|
7903
|
+
constructor(message, status = 400) {
|
|
7904
|
+
super(message);
|
|
7905
|
+
this.name = "ResponsesMessagesTranslationError";
|
|
7906
|
+
this.status = status;
|
|
7907
|
+
}
|
|
7908
|
+
};
|
|
7909
|
+
function translateResponsesToMessages(payload, options) {
|
|
7910
|
+
const registry = createToolRegistry(payload);
|
|
7911
|
+
const normalized = normalizeResponsesInput(payload.input);
|
|
7912
|
+
const { messages, system } = translateInputToAnthropic(normalized.input, registry, payload.instructions, payload.input);
|
|
7913
|
+
if (normalized.compaction) messages.push({
|
|
7914
|
+
role: "user",
|
|
7915
|
+
content: MESSAGES_COMPACTION_PROMPT
|
|
7916
|
+
});
|
|
7917
|
+
if (messages.length === 0) throw new ResponsesMessagesTranslationError("Responses input must contain at least one translatable message");
|
|
7918
|
+
const reasoningEffort = translateReasoningEffort(payload.reasoning?.effort);
|
|
7919
|
+
const messagesPayload = {
|
|
7920
|
+
model: options.model,
|
|
7921
|
+
messages,
|
|
7922
|
+
max_tokens: Math.max(1, payload.max_output_tokens ?? 32e3),
|
|
7923
|
+
stream: payload.stream ?? false,
|
|
7924
|
+
temperature: payload.temperature ?? void 0,
|
|
7925
|
+
top_p: payload.top_p ?? void 0,
|
|
7926
|
+
system: system.length > 0 ? system : void 0,
|
|
7927
|
+
tools: normalized.compaction || registry.tools.length > 0 ? registry.tools : void 0,
|
|
7928
|
+
tool_choice: translateToolChoice(payload.tool_choice, registry),
|
|
7929
|
+
...reasoningEffort ? { output_config: { effort: reasoningEffort } } : {},
|
|
7930
|
+
...payload.service_tier === "auto" || payload.service_tier === "standard_only" ? { service_tier: payload.service_tier } : {},
|
|
7931
|
+
...resolveMetadataUserId(payload) ? { metadata: { user_id: resolveMetadataUserId(payload) } } : {}
|
|
7932
|
+
};
|
|
7933
|
+
return {
|
|
7934
|
+
compaction: normalized.compaction,
|
|
7935
|
+
messagesPayload,
|
|
7936
|
+
originalPayload: payload,
|
|
7937
|
+
publicModel: options.publicModel ?? payload.model,
|
|
7938
|
+
registry
|
|
7939
|
+
};
|
|
7940
|
+
}
|
|
7941
|
+
function translateAnthropicToResponses(response, context) {
|
|
7942
|
+
const finish = translateStopReason(response.stop_reason);
|
|
7943
|
+
const output = context.compaction ? translateCompactionOutput(response) : translateAssistantOutput(response, context.registry);
|
|
7944
|
+
const outputText = context.compaction ? "" : extractAnthropicResponseText(response);
|
|
7945
|
+
return createMessagesBackedResponsesResult({
|
|
7946
|
+
context,
|
|
7947
|
+
id: toResponseId(response.id),
|
|
7948
|
+
output,
|
|
7949
|
+
outputText,
|
|
7950
|
+
status: finish.status,
|
|
7951
|
+
incompleteReason: finish.incompleteReason,
|
|
7952
|
+
usage: translateAnthropicUsage(response.usage),
|
|
7953
|
+
copilotUsage: response.copilot_usage
|
|
7954
|
+
});
|
|
7955
|
+
}
|
|
7956
|
+
function createMessagesBackedResponsesResult(options) {
|
|
7957
|
+
const { context } = options;
|
|
7958
|
+
return {
|
|
7959
|
+
id: options.id,
|
|
7960
|
+
object: "response",
|
|
7961
|
+
created_at: options.createdAt ?? Math.floor(Date.now() / 1e3),
|
|
7962
|
+
model: context.publicModel,
|
|
7963
|
+
output: options.output,
|
|
7964
|
+
output_text: options.outputText,
|
|
7965
|
+
status: options.status,
|
|
7966
|
+
copilot_usage: options.copilotUsage ?? null,
|
|
7967
|
+
usage: options.usage ?? null,
|
|
7968
|
+
error: options.error ?? null,
|
|
7969
|
+
incomplete_details: options.incompleteReason ? { reason: options.incompleteReason } : null,
|
|
7970
|
+
instructions: context.originalPayload.instructions ?? null,
|
|
7971
|
+
metadata: context.originalPayload.metadata ?? null,
|
|
7972
|
+
parallel_tool_calls: Boolean(context.originalPayload.parallel_tool_calls),
|
|
7973
|
+
temperature: context.originalPayload.temperature ?? null,
|
|
7974
|
+
tool_choice: context.originalPayload.tool_choice ?? "auto",
|
|
7975
|
+
tools: context.originalPayload.tools ?? [],
|
|
7976
|
+
top_p: context.originalPayload.top_p ?? null
|
|
7977
|
+
};
|
|
7978
|
+
}
|
|
7979
|
+
function translateAnthropicUsage(usage) {
|
|
7980
|
+
if (!usage) return null;
|
|
7981
|
+
const cachedTokens = usage.cache_read_input_tokens ?? 0;
|
|
7982
|
+
const cacheWriteTokens = usage.cache_creation_input_tokens ?? 0;
|
|
7983
|
+
const inputTokens = usage.input_tokens + cachedTokens + cacheWriteTokens;
|
|
7984
|
+
const outputTokens = usage.output_tokens;
|
|
7985
|
+
return {
|
|
7986
|
+
input_tokens: inputTokens,
|
|
7987
|
+
output_tokens: outputTokens,
|
|
7988
|
+
total_tokens: inputTokens + outputTokens,
|
|
7989
|
+
input_tokens_details: {
|
|
7990
|
+
cached_tokens: cachedTokens,
|
|
7991
|
+
...cacheWriteTokens > 0 ? { cache_write_tokens: cacheWriteTokens } : {}
|
|
7992
|
+
},
|
|
7993
|
+
output_tokens_details: { reasoning_tokens: 0 }
|
|
7994
|
+
};
|
|
7995
|
+
}
|
|
7996
|
+
function encodeMessagesCompaction(summary) {
|
|
7997
|
+
const payload = `${MESSAGES_COMPACTION_PREFIX}${Buffer.from(summary, "utf8").toString("base64url")}`;
|
|
7998
|
+
return Buffer.from(payload, "utf8").toString("base64");
|
|
7999
|
+
}
|
|
8000
|
+
function decodeMessagesCompaction(value) {
|
|
8001
|
+
let payload = value;
|
|
8002
|
+
if (!payload.startsWith("copilot-api:messages-compaction:v1:")) {
|
|
8003
|
+
const decoded = Buffer.from(value, "base64");
|
|
8004
|
+
if (decoded.toString("base64") !== value) return null;
|
|
8005
|
+
payload = decoded.toString("utf8");
|
|
8006
|
+
}
|
|
8007
|
+
if (!payload.startsWith("copilot-api:messages-compaction:v1:")) return null;
|
|
8008
|
+
try {
|
|
8009
|
+
const encoded = payload.slice(35);
|
|
8010
|
+
if (!encoded) return null;
|
|
8011
|
+
return Buffer.from(encoded, "base64url").toString("utf8");
|
|
8012
|
+
} catch {
|
|
8013
|
+
return null;
|
|
8014
|
+
}
|
|
8015
|
+
}
|
|
8016
|
+
function resolveToolDescriptor(registry, alias) {
|
|
8017
|
+
return registry.byAlias.get(alias) ?? {
|
|
8018
|
+
alias,
|
|
8019
|
+
kind: "function",
|
|
8020
|
+
name: alias
|
|
8021
|
+
};
|
|
8022
|
+
}
|
|
8023
|
+
function decodeCustomToolInput(input) {
|
|
8024
|
+
if (isRecord(input) && typeof input.input === "string") return input.input;
|
|
8025
|
+
return typeof input === "string" ? input : JSON.stringify(input ?? {});
|
|
8026
|
+
}
|
|
8027
|
+
function toResponseId(messageId) {
|
|
8028
|
+
return `resp_${messageId.replace(/^msg[-_]?/u, "") || createStableHash(messageId)}`;
|
|
8029
|
+
}
|
|
8030
|
+
function normalizeResponsesInput(input) {
|
|
8031
|
+
if (!Array.isArray(input)) return {
|
|
8032
|
+
compaction: false,
|
|
8033
|
+
input
|
|
8034
|
+
};
|
|
8035
|
+
const triggerIndexes = input.flatMap((item, index) => getItemType(item) === "compaction_trigger" ? [index] : []);
|
|
8036
|
+
const compaction = triggerIndexes.length > 0;
|
|
8037
|
+
if (triggerIndexes.length > 1 || compaction && triggerIndexes[0] !== input.length - 1) throw new ResponsesMessagesTranslationError("compaction_trigger must be the final Responses input item");
|
|
8038
|
+
const withoutTrigger = compaction ? input.slice(0, -1) : [...input];
|
|
8039
|
+
let latestCompactionIndex = -1;
|
|
8040
|
+
for (let index = withoutTrigger.length - 1; index >= 0; index -= 1) if (getItemType(withoutTrigger[index]) === "compaction") {
|
|
8041
|
+
latestCompactionIndex = index;
|
|
8042
|
+
break;
|
|
8043
|
+
}
|
|
8044
|
+
if (latestCompactionIndex < 0) return {
|
|
8045
|
+
compaction,
|
|
8046
|
+
input: withoutTrigger
|
|
8047
|
+
};
|
|
8048
|
+
const carrier = withoutTrigger[latestCompactionIndex];
|
|
8049
|
+
const encryptedContent = getStringField(carrier, "encrypted_content");
|
|
8050
|
+
const summary = encryptedContent ? decodeMessagesCompaction(encryptedContent) : null;
|
|
8051
|
+
if (!summary) throw new ResponsesMessagesTranslationError("This Messages-backed model cannot replay a compaction created by another Responses backend; start a new conversation or switch back to the original model");
|
|
8052
|
+
return {
|
|
8053
|
+
compaction,
|
|
8054
|
+
input: [{
|
|
8055
|
+
type: "message",
|
|
8056
|
+
role: "user",
|
|
8057
|
+
content: `${COMPACTION_REPLAY_PROMPT}${summary}`
|
|
8058
|
+
}, ...withoutTrigger.slice(latestCompactionIndex + 1)]
|
|
8059
|
+
};
|
|
8060
|
+
}
|
|
8061
|
+
function createToolRegistry(payload) {
|
|
8062
|
+
const registry = {
|
|
8063
|
+
byAlias: /* @__PURE__ */ new Map(),
|
|
8064
|
+
byOriginal: /* @__PURE__ */ new Map(),
|
|
8065
|
+
tools: []
|
|
8066
|
+
};
|
|
8067
|
+
for (const tool of payload.tools ?? []) registerTool(tool, registry);
|
|
8068
|
+
if (Array.isArray(payload.input)) for (const item of payload.input) {
|
|
8069
|
+
if (getItemType(item) !== "additional_tools") continue;
|
|
8070
|
+
for (const tool of getArrayField(item, "tools")) registerTool(tool, registry);
|
|
8071
|
+
}
|
|
8072
|
+
return registry;
|
|
8073
|
+
}
|
|
8074
|
+
function registerTool(tool, registry, namespaces = []) {
|
|
8075
|
+
if (!isRecord(tool)) throw new ResponsesMessagesTranslationError("Invalid Responses tool definition");
|
|
8076
|
+
const type = getStringField(tool, "type");
|
|
8077
|
+
if (type === "namespace") {
|
|
8078
|
+
const namespaceTool = tool;
|
|
8079
|
+
const namespace = getStringField(namespaceTool, "name");
|
|
8080
|
+
if (!namespace || !Array.isArray(namespaceTool.tools)) throw new ResponsesMessagesTranslationError("Responses namespace tools require a name and tools array");
|
|
8081
|
+
for (const child of namespaceTool.tools) registerTool(child, registry, [...namespaces, namespace]);
|
|
8082
|
+
return;
|
|
8083
|
+
}
|
|
8084
|
+
if (type !== "function" && type !== "custom") throw new ResponsesMessagesTranslationError(`Responses Messages fallback does not support tool${type ? ` '${type}'` : " without a type"}`);
|
|
8085
|
+
const name = getStringField(tool, "name");
|
|
8086
|
+
if (!name) throw new ResponsesMessagesTranslationError(`Responses ${type} tools require a non-empty name`);
|
|
8087
|
+
registerMessagesTool({
|
|
8088
|
+
kind: type,
|
|
8089
|
+
name,
|
|
8090
|
+
namespace: namespaces.length > 0 ? namespaces.join(".") : void 0,
|
|
8091
|
+
description: getOptionalStringField(tool, "description"),
|
|
8092
|
+
parameters: type === "function" && isRecord(tool.parameters) ? tool.parameters : null
|
|
8093
|
+
}, registry);
|
|
8094
|
+
}
|
|
8095
|
+
function registerMessagesTool(registration, registry) {
|
|
8096
|
+
const originalKey = createOriginalToolKey(registration);
|
|
8097
|
+
const existing = registry.byOriginal.get(originalKey);
|
|
8098
|
+
if (existing) return existing;
|
|
8099
|
+
const alias = createToolAlias(registration.namespace ? `${registration.namespace.replaceAll(".", "_")}__${registration.name}` : registration.name, originalKey, registry);
|
|
8100
|
+
const descriptor = {
|
|
8101
|
+
alias,
|
|
8102
|
+
kind: registration.kind,
|
|
8103
|
+
name: registration.name,
|
|
8104
|
+
...registration.namespace ? { namespace: registration.namespace } : {}
|
|
8105
|
+
};
|
|
8106
|
+
registry.byAlias.set(alias, descriptor);
|
|
8107
|
+
registry.byOriginal.set(originalKey, descriptor);
|
|
8108
|
+
registry.tools.push({
|
|
8109
|
+
name: alias,
|
|
8110
|
+
...registration.description ? { description: registration.description } : {},
|
|
8111
|
+
input_schema: registration.kind === "custom" ? CUSTOM_TOOL_INPUT_SCHEMA : registration.parameters ?? {
|
|
8112
|
+
type: "object",
|
|
8113
|
+
properties: {}
|
|
8114
|
+
}
|
|
8115
|
+
});
|
|
8116
|
+
return descriptor;
|
|
8117
|
+
}
|
|
8118
|
+
function translateInputToAnthropic(input, registry, instructions, originalInput) {
|
|
8119
|
+
const messages = [];
|
|
8120
|
+
const system = [];
|
|
8121
|
+
if (instructions?.trim()) system.push({
|
|
8122
|
+
type: "text",
|
|
8123
|
+
text: instructions
|
|
8124
|
+
});
|
|
8125
|
+
appendDeveloperPrompts(system, originalInput);
|
|
8126
|
+
if (typeof input === "string") {
|
|
8127
|
+
messages.push({
|
|
8128
|
+
role: "user",
|
|
8129
|
+
content: input
|
|
8130
|
+
});
|
|
8131
|
+
return {
|
|
8132
|
+
messages,
|
|
8133
|
+
system
|
|
8134
|
+
};
|
|
8135
|
+
}
|
|
8136
|
+
if (!Array.isArray(input)) return {
|
|
8137
|
+
messages,
|
|
8138
|
+
system
|
|
8139
|
+
};
|
|
8140
|
+
let userMessageSeen = false;
|
|
8141
|
+
for (const item of input) {
|
|
8142
|
+
const type = getItemType(item);
|
|
8143
|
+
switch (type) {
|
|
8144
|
+
case void 0:
|
|
8145
|
+
case "message":
|
|
8146
|
+
translateInputMessage(item, messages, system, userMessageSeen);
|
|
8147
|
+
if (getStringField(item, "role") === "user") userMessageSeen = true;
|
|
8148
|
+
break;
|
|
8149
|
+
case "agent_message":
|
|
8150
|
+
translateInputAgentMessage(item, messages);
|
|
8151
|
+
userMessageSeen = true;
|
|
8152
|
+
break;
|
|
8153
|
+
case "reasoning":
|
|
8154
|
+
translateInputReasoning(item, messages);
|
|
8155
|
+
break;
|
|
8156
|
+
case "function_call":
|
|
8157
|
+
translateInputToolCall(item, "function", messages, registry);
|
|
8158
|
+
break;
|
|
8159
|
+
case "custom_tool_call":
|
|
8160
|
+
translateInputToolCall(item, "custom", messages, registry);
|
|
8161
|
+
break;
|
|
8162
|
+
case "function_call_output":
|
|
8163
|
+
case "custom_tool_call_output":
|
|
8164
|
+
appendUserBlock(messages, {
|
|
8165
|
+
type: "tool_result",
|
|
8166
|
+
tool_use_id: requireStringField(item, "call_id", type),
|
|
8167
|
+
content: translateToolResultContent(item.output, `${type}.output`),
|
|
8168
|
+
is_error: getStringField(item, "status") === "incomplete"
|
|
8169
|
+
});
|
|
8170
|
+
break;
|
|
8171
|
+
case "additional_tools": break;
|
|
8172
|
+
default: throw new ResponsesMessagesTranslationError(`Responses Messages fallback does not support input item type '${type}'`);
|
|
8173
|
+
}
|
|
8174
|
+
}
|
|
8175
|
+
return {
|
|
8176
|
+
messages,
|
|
8177
|
+
system
|
|
8178
|
+
};
|
|
8179
|
+
}
|
|
8180
|
+
function translateInputMessage(item, messages, system, userMessageSeen) {
|
|
8181
|
+
if (!isRecord(item)) throw new ResponsesMessagesTranslationError("Invalid Responses message item");
|
|
8182
|
+
const role = getStringField(item, "role");
|
|
8183
|
+
if (role !== "user" && role !== "assistant" && role !== "system" && role !== "developer") throw new ResponsesMessagesTranslationError("Responses message items require a supported role");
|
|
8184
|
+
if (role === "developer" && !userMessageSeen) return;
|
|
8185
|
+
if (role === "system") {
|
|
8186
|
+
const text = translateSystemContent(item.content, "message.content");
|
|
8187
|
+
if (text) system.push({
|
|
8188
|
+
type: "text",
|
|
8189
|
+
text
|
|
8190
|
+
});
|
|
8191
|
+
return;
|
|
8192
|
+
}
|
|
8193
|
+
if (role === "assistant") {
|
|
8194
|
+
const blocks = translateAssistantContent(item.content, "message.content");
|
|
8195
|
+
for (const block of blocks) appendAssistantBlock(messages, block);
|
|
8196
|
+
return;
|
|
8197
|
+
}
|
|
8198
|
+
const content = translateUserContent(item.content, "message.content");
|
|
8199
|
+
messages.push({
|
|
8200
|
+
role: "user",
|
|
8201
|
+
content
|
|
8202
|
+
});
|
|
8203
|
+
}
|
|
8204
|
+
function translateInputAgentMessage(item, messages) {
|
|
8205
|
+
const content = translateUserContent(item.content, "agent_message.content");
|
|
8206
|
+
messages.push({
|
|
8207
|
+
role: "user",
|
|
8208
|
+
content
|
|
8209
|
+
});
|
|
8210
|
+
}
|
|
8211
|
+
function appendDeveloperPrompts(system, input) {
|
|
8212
|
+
if (!Array.isArray(input)) return;
|
|
8213
|
+
const prompts = [];
|
|
8214
|
+
for (const item of input) {
|
|
8215
|
+
if (prompts.length >= MAX_DEVELOPER_PROMPTS) break;
|
|
8216
|
+
const type = getItemType(item);
|
|
8217
|
+
const role = getStringField(item, "role");
|
|
8218
|
+
if (type === "agent_message") break;
|
|
8219
|
+
if ((type === void 0 || type === "message") && role === "user") break;
|
|
8220
|
+
if (type !== void 0 && type !== "message" || role !== "developer") continue;
|
|
8221
|
+
prompts.push(translateSystemContent(isRecord(item) ? item.content : void 0, "message.content"));
|
|
8222
|
+
}
|
|
8223
|
+
const [firstPrompt, ...remainingPrompts] = prompts;
|
|
8224
|
+
if (firstPrompt) system.push({
|
|
8225
|
+
type: "text",
|
|
8226
|
+
text: firstPrompt
|
|
8227
|
+
});
|
|
8228
|
+
const mergedPrompts = remainingPrompts.filter(Boolean).join("\n\n");
|
|
8229
|
+
if (mergedPrompts) system.push({
|
|
8230
|
+
type: "text",
|
|
8231
|
+
text: mergedPrompts
|
|
8232
|
+
});
|
|
8233
|
+
}
|
|
8234
|
+
function translateInputReasoning(item, messages) {
|
|
8235
|
+
appendAssistantBlock(messages, {
|
|
8236
|
+
type: "thinking",
|
|
8237
|
+
thinking: (Array.isArray(item.summary) ? item.summary.map((part) => typeof part?.text === "string" ? part.text : "").filter(Boolean).join("\n\n") : "") || "Thinking...",
|
|
8238
|
+
signature: item.encrypted_content ?? ""
|
|
8239
|
+
});
|
|
8240
|
+
}
|
|
8241
|
+
function translateInputToolCall(item, kind, messages, registry) {
|
|
8242
|
+
if (!isRecord(item)) throw new ResponsesMessagesTranslationError("Invalid Responses tool call item");
|
|
8243
|
+
const descriptor = registerMessagesTool({
|
|
8244
|
+
kind,
|
|
8245
|
+
name: requireStringField(item, "name", `${kind}_tool_call`),
|
|
8246
|
+
namespace: getOptionalStringField(item, "namespace") ?? void 0
|
|
8247
|
+
}, registry);
|
|
8248
|
+
const input = kind === "custom" ? { input: getStringField(item, "input") ?? "" } : parseFunctionArguments(getStringField(item, "arguments") ?? "{}", `${kind}_tool_call.arguments`);
|
|
8249
|
+
appendAssistantBlock(messages, {
|
|
8250
|
+
type: "tool_use",
|
|
8251
|
+
id: requireStringField(item, "call_id", `${kind}_tool_call`),
|
|
8252
|
+
name: descriptor.alias,
|
|
8253
|
+
input
|
|
8254
|
+
});
|
|
8255
|
+
}
|
|
8256
|
+
function translateUserContent(value, path) {
|
|
8257
|
+
if (value === void 0 || value === null) return "";
|
|
8258
|
+
if (typeof value === "string") return value;
|
|
8259
|
+
if (!Array.isArray(value)) throw new ResponsesMessagesTranslationError(`${path} must be text or an array`);
|
|
8260
|
+
return value.map((part, index) => translateUserContentPart(part, `${path}[${index}]`));
|
|
8261
|
+
}
|
|
8262
|
+
function translateAssistantContent(value, path) {
|
|
8263
|
+
if (value === void 0 || value === null) return [];
|
|
8264
|
+
if (typeof value === "string") return value ? [{
|
|
8265
|
+
type: "text",
|
|
8266
|
+
text: value
|
|
8267
|
+
}] : [];
|
|
8268
|
+
if (!Array.isArray(value)) throw new ResponsesMessagesTranslationError(`${path} must be text or an array`);
|
|
8269
|
+
return value.map((part, index) => {
|
|
8270
|
+
if (!isRecord(part)) throw new ResponsesMessagesTranslationError(`${path}[${index}] must be an object`);
|
|
8271
|
+
const type = getStringField(part, "type");
|
|
8272
|
+
if (type !== "input_text" && type !== "output_text" && type !== "text") throw new ResponsesMessagesTranslationError(`${path}[${index}] has unsupported assistant content type '${type ?? "unknown"}'`);
|
|
8273
|
+
return {
|
|
8274
|
+
type: "text",
|
|
8275
|
+
text: requireStringField(part, "text", `${path}[${index}]`)
|
|
8276
|
+
};
|
|
8277
|
+
});
|
|
8278
|
+
}
|
|
8279
|
+
function translateSystemContent(value, path) {
|
|
8280
|
+
if (value === void 0 || value === null) return "";
|
|
8281
|
+
if (typeof value === "string") return value;
|
|
8282
|
+
if (!Array.isArray(value)) throw new ResponsesMessagesTranslationError(`${path} must be text or an array`);
|
|
8283
|
+
return value.map((part, index) => {
|
|
8284
|
+
if (!isRecord(part)) throw new ResponsesMessagesTranslationError(`${path}[${index}] must be an object`);
|
|
8285
|
+
const type = getStringField(part, "type");
|
|
8286
|
+
if (type !== "input_text" && type !== "output_text" && type !== "text") throw new ResponsesMessagesTranslationError(`${path}[${index}] has unsupported system content type '${type ?? "unknown"}'`);
|
|
8287
|
+
return requireStringField(part, "text", `${path}[${index}]`);
|
|
8288
|
+
}).join("\n\n");
|
|
8289
|
+
}
|
|
8290
|
+
function translateUserContentPart(part, path) {
|
|
8291
|
+
if (!isRecord(part)) throw new ResponsesMessagesTranslationError(`${path} must be an object`);
|
|
8292
|
+
const type = getStringField(part, "type");
|
|
8293
|
+
if (type === "input_text" || type === "output_text" || type === "text") return {
|
|
8294
|
+
type: "text",
|
|
8295
|
+
text: requireStringField(part, "text", path)
|
|
8296
|
+
};
|
|
8297
|
+
if (type === "encrypted_content") return {
|
|
8298
|
+
type: "text",
|
|
8299
|
+
text: requireStringField(part, "encrypted_content", path)
|
|
8300
|
+
};
|
|
8301
|
+
if (type === "input_image") return translateImagePart(part, path);
|
|
8302
|
+
if (type === "input_file") return translateFilePart(part, path);
|
|
8303
|
+
throw new ResponsesMessagesTranslationError(`${path} has unsupported content type '${type ?? "unknown"}'`);
|
|
8304
|
+
}
|
|
8305
|
+
function translateToolResultContent(value, path) {
|
|
8306
|
+
if (value === void 0 || value === null) return "";
|
|
8307
|
+
if (typeof value === "string") return value;
|
|
8308
|
+
if (!Array.isArray(value)) throw new ResponsesMessagesTranslationError(`${path} must be text or an array`);
|
|
8309
|
+
return value.map((part, index) => translateUserContentPart(part, `${path}[${index}]`));
|
|
8310
|
+
}
|
|
8311
|
+
function translateImagePart(part, path) {
|
|
8312
|
+
const imageUrl = getStringField(part, "image_url");
|
|
8313
|
+
if (!imageUrl) throw new ResponsesMessagesTranslationError(`${path} requires image_url; file_id-only images cannot be sent to Messages`);
|
|
8314
|
+
const parsed = parseDataUrl(imageUrl);
|
|
8315
|
+
if (!parsed || parsed.mediaType !== "image/jpeg" && parsed.mediaType !== "image/png" && parsed.mediaType !== "image/gif" && parsed.mediaType !== "image/webp") throw new ResponsesMessagesTranslationError(`${path} requires a base64 JPEG, PNG, GIF, or WebP data URL`);
|
|
8316
|
+
return {
|
|
8317
|
+
type: "image",
|
|
8318
|
+
source: {
|
|
8319
|
+
type: "base64",
|
|
8320
|
+
media_type: parsed.mediaType,
|
|
8321
|
+
data: parsed.data
|
|
8322
|
+
}
|
|
8323
|
+
};
|
|
8324
|
+
}
|
|
8325
|
+
function translateFilePart(part, path) {
|
|
8326
|
+
const fileData = getStringField(part, "file_data");
|
|
8327
|
+
if (!fileData) throw new ResponsesMessagesTranslationError(`${path} requires file_data; file_id-only files cannot be sent to Messages`);
|
|
8328
|
+
const parsed = parseDataUrl(fileData);
|
|
8329
|
+
if (parsed?.mediaType !== "application/pdf") throw new ResponsesMessagesTranslationError(`${path} requires a base64 PDF data URL`);
|
|
8330
|
+
return {
|
|
8331
|
+
type: "document",
|
|
8332
|
+
source: {
|
|
8333
|
+
type: "base64",
|
|
8334
|
+
media_type: "application/pdf",
|
|
8335
|
+
data: parsed.data
|
|
8336
|
+
},
|
|
8337
|
+
title: getOptionalStringField(part, "filename") ?? "document.pdf"
|
|
8338
|
+
};
|
|
8339
|
+
}
|
|
8340
|
+
function translateToolChoice(toolChoice, registry) {
|
|
8341
|
+
if (!toolChoice) return void 0;
|
|
8342
|
+
if (typeof toolChoice === "string") {
|
|
8343
|
+
if (toolChoice === "required") return { type: "any" };
|
|
8344
|
+
return { type: toolChoice };
|
|
8345
|
+
}
|
|
8346
|
+
const kind = toolChoice.type;
|
|
8347
|
+
if (kind !== "function" && kind !== "custom") throw new ResponsesMessagesTranslationError(`Responses Messages fallback does not support tool_choice type '${String(kind)}'`);
|
|
8348
|
+
const rawName = toolChoice.name;
|
|
8349
|
+
const descriptor = findOriginalDescriptor(registry, kind, rawName, getOptionalStringField(toolChoice, "namespace") ?? void 0);
|
|
8350
|
+
if (!descriptor) throw new ResponsesMessagesTranslationError(`tool_choice references unknown ${kind} tool '${rawName}'`);
|
|
8351
|
+
return {
|
|
8352
|
+
type: "tool",
|
|
8353
|
+
name: descriptor.alias
|
|
8354
|
+
};
|
|
8355
|
+
}
|
|
8356
|
+
function translateAssistantOutput(response, registry) {
|
|
8357
|
+
const output = [];
|
|
8358
|
+
for (const [index, block] of response.content.entries()) {
|
|
8359
|
+
if (block.type === "thinking") {
|
|
8360
|
+
output.push({
|
|
8361
|
+
id: `rs_${createStableHash(`${response.id}:${index}:reasoning`)}`,
|
|
8362
|
+
type: "reasoning",
|
|
8363
|
+
status: "completed",
|
|
8364
|
+
...block.thinking && block.thinking !== "Thinking..." ? { summary: [{
|
|
8365
|
+
type: "summary_text",
|
|
8366
|
+
text: block.thinking
|
|
8367
|
+
}] } : {},
|
|
8368
|
+
...block.signature ? { encrypted_content: block.signature } : {}
|
|
8369
|
+
});
|
|
8370
|
+
continue;
|
|
8371
|
+
}
|
|
8372
|
+
if (block.type === "text") {
|
|
8373
|
+
output.push({
|
|
8374
|
+
id: `msg_${createStableHash(`${response.id}:${index}:message`)}`,
|
|
8375
|
+
type: "message",
|
|
8376
|
+
role: "assistant",
|
|
8377
|
+
status: "completed",
|
|
8378
|
+
content: [{
|
|
8379
|
+
type: "output_text",
|
|
8380
|
+
text: block.text,
|
|
8381
|
+
annotations: []
|
|
8382
|
+
}]
|
|
8383
|
+
});
|
|
8384
|
+
continue;
|
|
8385
|
+
}
|
|
8386
|
+
if (block.type === "tool_use") output.push(translateToolUseOutput(block, registry, `${response.id}:${index}:tool`));
|
|
8387
|
+
}
|
|
8388
|
+
return output;
|
|
8389
|
+
}
|
|
8390
|
+
function translateToolUseOutput(block, registry, idSeed) {
|
|
8391
|
+
const descriptor = resolveToolDescriptor(registry, block.name);
|
|
8392
|
+
const common = {
|
|
8393
|
+
id: `fc_${createStableHash(idSeed)}`,
|
|
8394
|
+
call_id: block.id,
|
|
8395
|
+
name: descriptor.name,
|
|
8396
|
+
status: "completed",
|
|
8397
|
+
...descriptor.namespace ? { namespace: descriptor.namespace } : {}
|
|
8398
|
+
};
|
|
8399
|
+
if (descriptor.kind === "custom") return {
|
|
8400
|
+
...common,
|
|
8401
|
+
type: "custom_tool_call",
|
|
8402
|
+
input: decodeCustomToolInput(block.input)
|
|
8403
|
+
};
|
|
8404
|
+
return {
|
|
8405
|
+
...common,
|
|
8406
|
+
type: "function_call",
|
|
8407
|
+
arguments: JSON.stringify(block.input)
|
|
8408
|
+
};
|
|
8409
|
+
}
|
|
8410
|
+
function translateCompactionOutput(response) {
|
|
8411
|
+
if (response.content.some((block) => block.type === "tool_use")) throw new ResponsesMessagesTranslationError("Messages API attempted a tool call during compaction", 502);
|
|
8412
|
+
const summary = extractAnthropicResponseText(response).trim();
|
|
8413
|
+
if (!summary) throw new ResponsesMessagesTranslationError("Messages API compaction response did not contain a text summary", 502);
|
|
8414
|
+
return [{
|
|
8415
|
+
id: `cmp_${createStableHash(summary)}`,
|
|
8416
|
+
type: "compaction",
|
|
8417
|
+
encrypted_content: encodeMessagesCompaction(summary)
|
|
8418
|
+
}];
|
|
8419
|
+
}
|
|
8420
|
+
function extractAnthropicResponseText(response) {
|
|
8421
|
+
return response.content.flatMap((block) => block.type === "text" ? [block.text] : []).join("");
|
|
8422
|
+
}
|
|
8423
|
+
function translateStopReason(stopReason) {
|
|
8424
|
+
if (stopReason === "max_tokens") return {
|
|
8425
|
+
status: "incomplete",
|
|
8426
|
+
incompleteReason: "max_output_tokens"
|
|
8427
|
+
};
|
|
8428
|
+
if (stopReason === "refusal") return {
|
|
8429
|
+
status: "incomplete",
|
|
8430
|
+
incompleteReason: "content_filter"
|
|
8431
|
+
};
|
|
8432
|
+
return { status: "completed" };
|
|
8433
|
+
}
|
|
8434
|
+
function translateReasoningEffort(effort) {
|
|
8435
|
+
if (effort === "minimal") return "low";
|
|
8436
|
+
if (effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max") return effort;
|
|
8437
|
+
}
|
|
8438
|
+
function resolveMetadataUserId(payload) {
|
|
8439
|
+
const metadataUserId = payload.metadata?.user_id;
|
|
8440
|
+
if (metadataUserId?.trim()) return metadataUserId;
|
|
8441
|
+
if (payload.safety_identifier?.trim()) return payload.safety_identifier;
|
|
8442
|
+
if (payload.prompt_cache_key?.trim()) return payload.prompt_cache_key;
|
|
8443
|
+
}
|
|
8444
|
+
function appendAssistantBlock(messages, block) {
|
|
8445
|
+
const last = messages.at(-1);
|
|
8446
|
+
if (last?.role === "assistant" && Array.isArray(last.content)) {
|
|
8447
|
+
last.content.push(block);
|
|
8448
|
+
return;
|
|
8449
|
+
}
|
|
8450
|
+
const message = {
|
|
8451
|
+
role: "assistant",
|
|
8452
|
+
content: [block]
|
|
8453
|
+
};
|
|
8454
|
+
messages.push(message);
|
|
8455
|
+
}
|
|
8456
|
+
function appendUserBlock(messages, block) {
|
|
8457
|
+
const last = messages.at(-1);
|
|
8458
|
+
if (last?.role === "user" && Array.isArray(last.content)) {
|
|
8459
|
+
last.content.push(block);
|
|
8460
|
+
return;
|
|
8461
|
+
}
|
|
8462
|
+
const message = {
|
|
8463
|
+
role: "user",
|
|
8464
|
+
content: [block]
|
|
8465
|
+
};
|
|
8466
|
+
messages.push(message);
|
|
8467
|
+
}
|
|
8468
|
+
function parseFunctionArguments(value, path) {
|
|
8469
|
+
try {
|
|
8470
|
+
const parsed = JSON.parse(value);
|
|
8471
|
+
if (isRecord(parsed)) return parsed;
|
|
8472
|
+
} catch {}
|
|
8473
|
+
throw new ResponsesMessagesTranslationError(`${path} must be a JSON object string`);
|
|
8474
|
+
}
|
|
8475
|
+
function parseDataUrl(value) {
|
|
8476
|
+
const match = /^data:([^;,]+);base64,(.*)$/su.exec(value);
|
|
8477
|
+
if (!match) return null;
|
|
8478
|
+
return {
|
|
8479
|
+
mediaType: match[1].toLowerCase(),
|
|
8480
|
+
data: match[2]
|
|
8481
|
+
};
|
|
8482
|
+
}
|
|
8483
|
+
function findOriginalDescriptor(registry, kind, name, namespace) {
|
|
8484
|
+
const matches = [];
|
|
8485
|
+
for (const descriptor of registry.byOriginal.values()) {
|
|
8486
|
+
if (descriptor.kind !== kind || descriptor.name !== name) continue;
|
|
8487
|
+
if (namespace !== void 0) {
|
|
8488
|
+
if (descriptor.namespace === namespace) return descriptor;
|
|
8489
|
+
continue;
|
|
8490
|
+
}
|
|
8491
|
+
matches.push(descriptor);
|
|
8492
|
+
}
|
|
8493
|
+
return matches.find((descriptor) => descriptor.namespace === void 0) ?? (matches.length === 1 ? matches[0] : void 0);
|
|
8494
|
+
}
|
|
8495
|
+
function createOriginalToolKey(tool) {
|
|
8496
|
+
return [
|
|
8497
|
+
tool.kind,
|
|
8498
|
+
tool.namespace ?? "",
|
|
8499
|
+
tool.name
|
|
8500
|
+
].join("\0");
|
|
8501
|
+
}
|
|
8502
|
+
function createToolAlias(preferredName, originalKey, registry) {
|
|
8503
|
+
if (TOOL_NAME_PATTERN.test(preferredName) && !registry.byAlias.has(preferredName)) return preferredName;
|
|
8504
|
+
const sanitized = preferredName.replace(/[^A-Za-z0-9_-]+/gu, "_");
|
|
8505
|
+
const alias = `${`tool_${createStableHash(originalKey).slice(0, 12)}_`}${sanitized}`.slice(0, 64);
|
|
8506
|
+
if (!registry.byAlias.has(alias)) return alias;
|
|
8507
|
+
return `tool_${createStableHash(`${originalKey}:collision`)}`.slice(0, 64);
|
|
8508
|
+
}
|
|
8509
|
+
function createStableHash(value) {
|
|
8510
|
+
return createHash("sha256").update(value).digest("hex").slice(0, 24);
|
|
8511
|
+
}
|
|
8512
|
+
function getItemType(value) {
|
|
8513
|
+
return isRecord(value) && typeof value.type === "string" ? value.type : void 0;
|
|
8514
|
+
}
|
|
8515
|
+
function getStringField(value, field) {
|
|
8516
|
+
if (!isRecord(value)) return void 0;
|
|
8517
|
+
const fieldValue = value[field];
|
|
8518
|
+
return typeof fieldValue === "string" ? fieldValue : void 0;
|
|
8519
|
+
}
|
|
8520
|
+
function getOptionalStringField(value, field) {
|
|
8521
|
+
if (!isRecord(value)) return void 0;
|
|
8522
|
+
const fieldValue = value[field];
|
|
8523
|
+
return typeof fieldValue === "string" || fieldValue === null ? fieldValue : void 0;
|
|
8524
|
+
}
|
|
8525
|
+
function requireStringField(value, field, path) {
|
|
8526
|
+
const result = getStringField(value, field);
|
|
8527
|
+
if (!result) throw new ResponsesMessagesTranslationError(`${path}.${field} is required`);
|
|
8528
|
+
return result;
|
|
8529
|
+
}
|
|
8530
|
+
function getArrayField(value, field) {
|
|
8531
|
+
if (!isRecord(value)) return [];
|
|
8532
|
+
return Array.isArray(value[field]) ? value[field] : [];
|
|
8533
|
+
}
|
|
8534
|
+
function isRecord(value) {
|
|
8535
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8536
|
+
}
|
|
8537
|
+
//#endregion
|
|
8538
|
+
//#region src/routes/responses/custom-tool-input-stream-decoder.ts
|
|
8539
|
+
const CUSTOM_TOOL_INPUT_PREFIX_TOKENS = [
|
|
8540
|
+
"{",
|
|
8541
|
+
"\"input\"",
|
|
8542
|
+
":",
|
|
8543
|
+
"\""
|
|
8544
|
+
];
|
|
8545
|
+
var CustomToolInputStreamDecoder = class {
|
|
8546
|
+
inputParts = new Array();
|
|
8547
|
+
encodedInput = "";
|
|
8548
|
+
escapeState = "plain";
|
|
8549
|
+
failed = false;
|
|
8550
|
+
finished = false;
|
|
8551
|
+
offset = 0;
|
|
8552
|
+
prefixCharOffset = 0;
|
|
8553
|
+
prefixTokenOffset = 0;
|
|
8554
|
+
safeInputLength = 0;
|
|
8555
|
+
state = "prefix";
|
|
8556
|
+
unicodeDigitsRemaining = 0;
|
|
8557
|
+
append(partialJson) {
|
|
8558
|
+
if (this.failed) return this.fail("decoder is already in a failed state");
|
|
8559
|
+
if (this.finished) return this.fail("data arrived after the input was done");
|
|
8560
|
+
const deltaParts = new Array();
|
|
8561
|
+
for (const char of partialJson) {
|
|
8562
|
+
this.offset += char.length;
|
|
8563
|
+
this.consume(char, deltaParts);
|
|
8564
|
+
}
|
|
8565
|
+
this.flushSafeInput(deltaParts);
|
|
8566
|
+
const delta = deltaParts.join("");
|
|
8567
|
+
if (delta) this.inputParts.push(delta);
|
|
8568
|
+
return delta;
|
|
8569
|
+
}
|
|
8570
|
+
finish() {
|
|
8571
|
+
if (this.failed) return this.fail("decoder is already in a failed state");
|
|
8572
|
+
if (this.finished) return this.fail("input was already completed");
|
|
8573
|
+
if (this.state !== "done" || this.escapeState !== "plain" || this.encodedInput) return this.fail("input ended before the wrapper was complete");
|
|
8574
|
+
this.finished = true;
|
|
8575
|
+
return this.inputParts.join("");
|
|
8576
|
+
}
|
|
8577
|
+
consume(char, deltaParts) {
|
|
8578
|
+
if (this.state === "prefix") {
|
|
8579
|
+
const token = CUSTOM_TOOL_INPUT_PREFIX_TOKENS[this.prefixTokenOffset];
|
|
8580
|
+
if (this.prefixCharOffset === 0 && isJsonWhitespace(char)) return;
|
|
8581
|
+
if (!token || char !== token[this.prefixCharOffset]) return this.fail("unexpected custom tool input prefix");
|
|
8582
|
+
this.prefixCharOffset += 1;
|
|
8583
|
+
if (this.prefixCharOffset < token.length) return;
|
|
8584
|
+
this.prefixTokenOffset += 1;
|
|
8585
|
+
this.prefixCharOffset = 0;
|
|
8586
|
+
if (this.prefixTokenOffset === CUSTOM_TOOL_INPUT_PREFIX_TOKENS.length) this.state = "input";
|
|
8587
|
+
return;
|
|
8588
|
+
}
|
|
8589
|
+
if (this.state === "suffix") {
|
|
8590
|
+
if (isJsonWhitespace(char)) return;
|
|
8591
|
+
if (char !== "}") return this.fail("expected \"}\" after the input string");
|
|
8592
|
+
this.state = "done";
|
|
8593
|
+
return;
|
|
8594
|
+
}
|
|
8595
|
+
if (this.state === "done") {
|
|
8596
|
+
if (!isJsonWhitespace(char)) return this.fail("unexpected data after the input wrapper");
|
|
8597
|
+
return;
|
|
8598
|
+
}
|
|
8599
|
+
if (this.escapeState === "unicode") {
|
|
8600
|
+
if (!/^[0-9A-Fa-f]$/u.test(char)) return this.fail("invalid Unicode escape");
|
|
8601
|
+
this.encodedInput += char;
|
|
8602
|
+
this.unicodeDigitsRemaining -= 1;
|
|
8603
|
+
if (this.unicodeDigitsRemaining === 0) {
|
|
8604
|
+
this.escapeState = "plain";
|
|
8605
|
+
this.safeInputLength = this.encodedInput.length;
|
|
8606
|
+
}
|
|
8607
|
+
return;
|
|
8608
|
+
}
|
|
8609
|
+
if (this.escapeState === "escaped") {
|
|
8610
|
+
if (!"\"\\/bfnrtu".includes(char)) return this.fail("invalid JSON escape");
|
|
8611
|
+
this.encodedInput += char;
|
|
8612
|
+
if (char === "u") {
|
|
8613
|
+
this.escapeState = "unicode";
|
|
8614
|
+
this.unicodeDigitsRemaining = 4;
|
|
8615
|
+
} else {
|
|
8616
|
+
this.escapeState = "plain";
|
|
8617
|
+
this.safeInputLength = this.encodedInput.length;
|
|
8618
|
+
}
|
|
8619
|
+
return;
|
|
8620
|
+
}
|
|
8621
|
+
if (char === "\\") {
|
|
8622
|
+
this.encodedInput += char;
|
|
8623
|
+
this.escapeState = "escaped";
|
|
8624
|
+
return;
|
|
8625
|
+
}
|
|
8626
|
+
if (char === "\"") {
|
|
8627
|
+
this.flushSafeInput(deltaParts);
|
|
8628
|
+
this.state = "suffix";
|
|
8629
|
+
return;
|
|
8630
|
+
}
|
|
8631
|
+
if (char.charCodeAt(0) < 32) return this.fail("unescaped control character in custom tool input");
|
|
8632
|
+
this.encodedInput += char;
|
|
8633
|
+
this.safeInputLength = this.encodedInput.length;
|
|
8634
|
+
}
|
|
8635
|
+
flushSafeInput(deltaParts) {
|
|
8636
|
+
if (this.safeInputLength === 0) return;
|
|
8637
|
+
const encoded = this.encodedInput.slice(0, this.safeInputLength);
|
|
8638
|
+
const decoded = JSON.parse(`"${encoded}"`);
|
|
8639
|
+
if (decoded) deltaParts.push(decoded);
|
|
8640
|
+
this.encodedInput = this.encodedInput.slice(this.safeInputLength);
|
|
8641
|
+
this.safeInputLength = 0;
|
|
8642
|
+
}
|
|
8643
|
+
fail(reason) {
|
|
8644
|
+
this.failed = true;
|
|
8645
|
+
throw new ResponsesMessagesTranslationError(`Messages API returned invalid custom tool input JSON at offset ${this.offset}: ${reason}`, 502);
|
|
8646
|
+
}
|
|
8647
|
+
};
|
|
8648
|
+
function isJsonWhitespace(char) {
|
|
8649
|
+
return char === " " || char === " " || char === "\r" || char === "\n";
|
|
8650
|
+
}
|
|
8651
|
+
//#endregion
|
|
8652
|
+
//#region src/routes/responses/messages-stream-translation.ts
|
|
8653
|
+
const EMPTY_SIGNATURE_ENCRYPTED_CONTENT = "Y29waWxvdC1hcGk6bWVzc2FnZXMtZW1wdHktc2lnbmF0dXJlOnYx";
|
|
8654
|
+
async function* translateMessagesStream(chunks, context) {
|
|
8655
|
+
const state = createTranslationState(context);
|
|
8656
|
+
try {
|
|
8657
|
+
for await (const chunk of chunks) {
|
|
8658
|
+
if (!chunk.data || chunk.data === "[DONE]") continue;
|
|
8659
|
+
const event = parseAnthropicEvent(chunk.data);
|
|
8660
|
+
if (event.type === "ping") continue;
|
|
8661
|
+
if (event.type === "error") throw new ResponsesMessagesTranslationError(event.error.message, 502);
|
|
8662
|
+
if (!state.initialized) {
|
|
8663
|
+
initializeState(state, event);
|
|
8664
|
+
yield createLifecycleEvent(state, "response.created");
|
|
8665
|
+
yield createLifecycleEvent(state, "response.in_progress");
|
|
8666
|
+
}
|
|
8667
|
+
for (const translated of translateEvent(state, event)) yield translated;
|
|
8668
|
+
if (state.messageStopped) break;
|
|
8669
|
+
}
|
|
8670
|
+
if (!state.initialized) throw new ResponsesMessagesTranslationError("Messages API returned an empty stream", 502);
|
|
8671
|
+
if (!state.messageStopped) {
|
|
8672
|
+
for (const translated of closeAllBlocks(state)) yield translated;
|
|
8673
|
+
for (const translated of finishCompaction(state)) yield translated;
|
|
8674
|
+
state.messageStopped = true;
|
|
8675
|
+
yield createTerminalEvent(state);
|
|
8676
|
+
}
|
|
8677
|
+
} catch (error) {
|
|
8678
|
+
if (!state.initialized) throw error;
|
|
8679
|
+
yield createErrorEvent(state, error);
|
|
8680
|
+
yield createFailedEvent(state, error);
|
|
8681
|
+
}
|
|
8682
|
+
}
|
|
8683
|
+
function responsesResultToStreamEvents(result) {
|
|
8684
|
+
let sequence = 0;
|
|
8685
|
+
const next = (value) => ({
|
|
8686
|
+
...value,
|
|
8687
|
+
sequence_number: sequence++
|
|
8688
|
+
});
|
|
8689
|
+
const inProgress = {
|
|
8690
|
+
...result,
|
|
8691
|
+
output: [],
|
|
8692
|
+
output_text: "",
|
|
8693
|
+
status: "in_progress",
|
|
8694
|
+
usage: null
|
|
8695
|
+
};
|
|
8696
|
+
const events = [next({
|
|
8697
|
+
type: "response.created",
|
|
8698
|
+
response: inProgress
|
|
8699
|
+
}), next({
|
|
8700
|
+
type: "response.in_progress",
|
|
8701
|
+
response: inProgress
|
|
8702
|
+
})];
|
|
8703
|
+
for (const [outputIndex, item] of result.output.entries()) {
|
|
8704
|
+
events.push(next({
|
|
8705
|
+
type: "response.output_item.added",
|
|
8706
|
+
output_index: outputIndex,
|
|
8707
|
+
item: {
|
|
8708
|
+
...structuredClone(item),
|
|
8709
|
+
status: "in_progress"
|
|
8710
|
+
}
|
|
8711
|
+
}));
|
|
8712
|
+
if (item.type === "message") {
|
|
8713
|
+
const textPart = item.content?.find((part) => part.type === "output_text");
|
|
8714
|
+
if (textPart?.type === "output_text") events.push(next({
|
|
8715
|
+
type: "response.content_part.added",
|
|
8716
|
+
item_id: item.id,
|
|
8717
|
+
output_index: outputIndex,
|
|
8718
|
+
content_index: 0,
|
|
8719
|
+
part: {
|
|
8720
|
+
type: "output_text",
|
|
8721
|
+
text: "",
|
|
8722
|
+
annotations: []
|
|
8723
|
+
}
|
|
8724
|
+
}), next({
|
|
8725
|
+
type: "response.output_text.delta",
|
|
8726
|
+
item_id: item.id,
|
|
8727
|
+
output_index: outputIndex,
|
|
8728
|
+
content_index: 0,
|
|
8729
|
+
delta: textPart.text
|
|
8730
|
+
}), next({
|
|
8731
|
+
type: "response.output_text.done",
|
|
8732
|
+
item_id: item.id,
|
|
8733
|
+
output_index: outputIndex,
|
|
8734
|
+
content_index: 0,
|
|
8735
|
+
text: textPart.text
|
|
8736
|
+
}), next({
|
|
8737
|
+
type: "response.content_part.done",
|
|
8738
|
+
item_id: item.id,
|
|
8739
|
+
output_index: outputIndex,
|
|
8740
|
+
content_index: 0,
|
|
8741
|
+
part: textPart
|
|
8742
|
+
}));
|
|
8743
|
+
} else if (item.type === "reasoning") {
|
|
8744
|
+
const text = item.summary?.[0]?.text;
|
|
8745
|
+
if (text) {
|
|
8746
|
+
const part = {
|
|
8747
|
+
type: "summary_text",
|
|
8748
|
+
text
|
|
8749
|
+
};
|
|
8750
|
+
events.push(next({
|
|
8751
|
+
type: "response.reasoning_summary_part.added",
|
|
8752
|
+
item_id: item.id,
|
|
8753
|
+
output_index: outputIndex,
|
|
8754
|
+
summary_index: 0,
|
|
8755
|
+
part: {
|
|
8756
|
+
type: "summary_text",
|
|
8757
|
+
text: ""
|
|
8758
|
+
}
|
|
8759
|
+
}), next({
|
|
8760
|
+
type: "response.reasoning_summary_text.delta",
|
|
8761
|
+
item_id: item.id,
|
|
8762
|
+
output_index: outputIndex,
|
|
8763
|
+
summary_index: 0,
|
|
8764
|
+
delta: text
|
|
8765
|
+
}), next({
|
|
8766
|
+
type: "response.reasoning_summary_text.done",
|
|
8767
|
+
item_id: item.id,
|
|
8768
|
+
output_index: outputIndex,
|
|
8769
|
+
summary_index: 0,
|
|
8770
|
+
text
|
|
8771
|
+
}), next({
|
|
8772
|
+
type: "response.reasoning_summary_part.done",
|
|
8773
|
+
item_id: item.id,
|
|
8774
|
+
output_index: outputIndex,
|
|
8775
|
+
summary_index: 0,
|
|
8776
|
+
part
|
|
8777
|
+
}));
|
|
8778
|
+
}
|
|
8779
|
+
} else if (item.type === "function_call") {
|
|
8780
|
+
if (item.arguments) events.push(next({
|
|
8781
|
+
type: "response.function_call_arguments.delta",
|
|
8782
|
+
item_id: item.id,
|
|
8783
|
+
output_index: outputIndex,
|
|
8784
|
+
delta: item.arguments
|
|
8785
|
+
}));
|
|
8786
|
+
events.push(next({
|
|
8787
|
+
type: "response.function_call_arguments.done",
|
|
8788
|
+
item_id: item.id,
|
|
8789
|
+
output_index: outputIndex,
|
|
8790
|
+
name: item.name,
|
|
8791
|
+
arguments: item.arguments
|
|
8792
|
+
}));
|
|
8793
|
+
} else if (item.type === "custom_tool_call") {
|
|
8794
|
+
if (item.input) events.push(next({
|
|
8795
|
+
type: "response.custom_tool_call_input.delta",
|
|
8796
|
+
item_id: item.id,
|
|
8797
|
+
output_index: outputIndex,
|
|
8798
|
+
delta: item.input
|
|
8799
|
+
}));
|
|
8800
|
+
events.push(next({
|
|
8801
|
+
type: "response.custom_tool_call_input.done",
|
|
8802
|
+
item_id: item.id,
|
|
8803
|
+
output_index: outputIndex,
|
|
8804
|
+
name: item.name,
|
|
8805
|
+
input: item.input
|
|
8806
|
+
}));
|
|
8807
|
+
}
|
|
8808
|
+
events.push(next({
|
|
8809
|
+
type: "response.output_item.done",
|
|
8810
|
+
output_index: outputIndex,
|
|
8811
|
+
item
|
|
8812
|
+
}));
|
|
8813
|
+
}
|
|
8814
|
+
events.push(next({
|
|
8815
|
+
type: result.status === "incomplete" ? "response.incomplete" : result.status === "failed" ? "response.failed" : "response.completed",
|
|
8816
|
+
response: {
|
|
8817
|
+
...result,
|
|
8818
|
+
output: []
|
|
8819
|
+
},
|
|
8820
|
+
copilot_usage: result.copilot_usage
|
|
8821
|
+
}));
|
|
8822
|
+
return events;
|
|
8823
|
+
}
|
|
8824
|
+
function createTranslationState(context) {
|
|
8825
|
+
return {
|
|
8826
|
+
blocks: /* @__PURE__ */ new Map(),
|
|
8827
|
+
compactionText: "",
|
|
8828
|
+
compactionToolCall: false,
|
|
8829
|
+
context,
|
|
8830
|
+
copilotUsage: null,
|
|
8831
|
+
createdAt: Math.floor(Date.now() / 1e3),
|
|
8832
|
+
initialized: false,
|
|
8833
|
+
messageStopped: false,
|
|
8834
|
+
model: context.publicModel,
|
|
8835
|
+
nextOutputIndex: 0,
|
|
8836
|
+
outputText: "",
|
|
8837
|
+
responseId: `resp_${Date.now().toString(36)}`,
|
|
8838
|
+
sequence: 0,
|
|
8839
|
+
stopReason: null,
|
|
8840
|
+
usage: {
|
|
8841
|
+
input_tokens: 0,
|
|
8842
|
+
output_tokens: 0
|
|
8843
|
+
}
|
|
8844
|
+
};
|
|
8845
|
+
}
|
|
8846
|
+
function initializeState(state, event) {
|
|
8847
|
+
if (event.type === "message_start") {
|
|
8848
|
+
state.responseId = toResponseId(event.message.id);
|
|
8849
|
+
state.model = event.message.model;
|
|
8850
|
+
state.usage = { ...event.message.usage };
|
|
8851
|
+
state.copilotUsage = event.message.copilot_usage ?? null;
|
|
8852
|
+
}
|
|
8853
|
+
state.initialized = true;
|
|
8854
|
+
}
|
|
8855
|
+
function* translateEvent(state, event) {
|
|
8856
|
+
switch (event.type) {
|
|
8857
|
+
case "message_start":
|
|
8858
|
+
state.usage = mergeUsage(state.usage, event.message.usage);
|
|
8859
|
+
state.copilotUsage = event.message.copilot_usage ?? state.copilotUsage;
|
|
8860
|
+
break;
|
|
8861
|
+
case "content_block_start":
|
|
8862
|
+
for (const translated of startContentBlock(state, event)) yield translated;
|
|
8863
|
+
break;
|
|
8864
|
+
case "content_block_delta":
|
|
8865
|
+
for (const translated of translateContentDelta(state, event)) yield translated;
|
|
8866
|
+
break;
|
|
8867
|
+
case "content_block_stop":
|
|
8868
|
+
for (const translated of closeContentBlock(state, event.index)) yield translated;
|
|
8869
|
+
break;
|
|
8870
|
+
case "message_delta":
|
|
8871
|
+
if (event.delta.stop_reason !== void 0) state.stopReason = event.delta.stop_reason;
|
|
8872
|
+
if (event.usage) state.usage = mergeUsage(state.usage, event.usage);
|
|
8873
|
+
state.copilotUsage = event.copilot_usage ?? state.copilotUsage;
|
|
8874
|
+
break;
|
|
8875
|
+
case "message_stop":
|
|
8876
|
+
for (const translated of closeAllBlocks(state)) yield translated;
|
|
8877
|
+
for (const translated of finishCompaction(state)) yield translated;
|
|
8878
|
+
state.messageStopped = true;
|
|
8879
|
+
yield createTerminalEvent(state);
|
|
8880
|
+
break;
|
|
8881
|
+
}
|
|
8882
|
+
}
|
|
8883
|
+
function* startContentBlock(state, event) {
|
|
8884
|
+
const block = event.content_block;
|
|
8885
|
+
if (state.context.compaction) {
|
|
8886
|
+
if (block.type === "text") state.compactionText += block.text;
|
|
8887
|
+
if (block.type === "tool_use" || block.type === "server_tool_use") state.compactionToolCall = true;
|
|
8888
|
+
return;
|
|
8889
|
+
}
|
|
8890
|
+
if (block.type === "text") {
|
|
8891
|
+
const item = {
|
|
8892
|
+
id: `msg_${state.responseId.slice(-18)}_${event.index}`,
|
|
8893
|
+
type: "message",
|
|
8894
|
+
role: "assistant",
|
|
8895
|
+
status: "in_progress",
|
|
8896
|
+
content: [{
|
|
8897
|
+
type: "output_text",
|
|
8898
|
+
text: block.text,
|
|
8899
|
+
annotations: []
|
|
8900
|
+
}]
|
|
8901
|
+
};
|
|
8902
|
+
const output = addOutput(state, item);
|
|
8903
|
+
state.blocks.set(event.index, {
|
|
8904
|
+
...output,
|
|
8905
|
+
type: "message",
|
|
8906
|
+
text: block.text,
|
|
8907
|
+
done: false
|
|
8908
|
+
});
|
|
8909
|
+
state.outputText += block.text;
|
|
8910
|
+
yield createEvent(state, {
|
|
8911
|
+
type: "response.output_item.added",
|
|
8912
|
+
output_index: output.outputIndex,
|
|
8913
|
+
item: structuredClone(item)
|
|
8914
|
+
});
|
|
8915
|
+
yield createEvent(state, {
|
|
8916
|
+
type: "response.content_part.added",
|
|
8917
|
+
item_id: item.id,
|
|
8918
|
+
output_index: output.outputIndex,
|
|
8919
|
+
content_index: 0,
|
|
8920
|
+
part: {
|
|
8921
|
+
type: "output_text",
|
|
8922
|
+
text: "",
|
|
8923
|
+
annotations: []
|
|
8924
|
+
}
|
|
8925
|
+
});
|
|
8926
|
+
if (block.text) yield createEvent(state, {
|
|
8927
|
+
type: "response.output_text.delta",
|
|
8928
|
+
item_id: item.id,
|
|
8929
|
+
output_index: output.outputIndex,
|
|
8930
|
+
content_index: 0,
|
|
8931
|
+
delta: block.text
|
|
8932
|
+
});
|
|
8933
|
+
return;
|
|
8934
|
+
}
|
|
8935
|
+
if (block.type === "thinking") {
|
|
8936
|
+
const item = {
|
|
8937
|
+
id: `rs_${state.responseId.slice(-18)}_${event.index}`,
|
|
8938
|
+
type: "reasoning",
|
|
8939
|
+
status: "in_progress",
|
|
8940
|
+
summary: [],
|
|
8941
|
+
encrypted_content: EMPTY_SIGNATURE_ENCRYPTED_CONTENT
|
|
8942
|
+
};
|
|
8943
|
+
const output = addOutput(state, item);
|
|
8944
|
+
const reasoning = {
|
|
8945
|
+
...output,
|
|
8946
|
+
type: "reasoning",
|
|
8947
|
+
signature: "",
|
|
8948
|
+
summaryStarted: false,
|
|
8949
|
+
text: "",
|
|
8950
|
+
done: false
|
|
8951
|
+
};
|
|
8952
|
+
state.blocks.set(event.index, reasoning);
|
|
8953
|
+
yield createEvent(state, {
|
|
8954
|
+
type: "response.output_item.added",
|
|
8955
|
+
output_index: output.outputIndex,
|
|
8956
|
+
item: structuredClone(item)
|
|
8957
|
+
});
|
|
8958
|
+
if (block.thinking) for (const translated of appendReasoningText(state, reasoning, block.thinking)) yield translated;
|
|
8959
|
+
return;
|
|
8960
|
+
}
|
|
8961
|
+
if (block.type === "tool_use") {
|
|
8962
|
+
const descriptor = resolveToolDescriptor(state.context.registry, block.name);
|
|
8963
|
+
const common = {
|
|
8964
|
+
id: `fc_${state.responseId.slice(-18)}_${event.index}`,
|
|
8965
|
+
call_id: block.id,
|
|
8966
|
+
name: descriptor.name,
|
|
8967
|
+
status: "in_progress",
|
|
8968
|
+
...descriptor.namespace ? { namespace: descriptor.namespace } : {}
|
|
8969
|
+
};
|
|
8970
|
+
if (descriptor.kind === "custom") {
|
|
8971
|
+
const item = {
|
|
8972
|
+
...common,
|
|
8973
|
+
type: "custom_tool_call",
|
|
8974
|
+
input: ""
|
|
8975
|
+
};
|
|
8976
|
+
const output = addOutput(state, item);
|
|
8977
|
+
const decoder = new CustomToolInputStreamDecoder();
|
|
8978
|
+
state.blocks.set(event.index, {
|
|
8979
|
+
...output,
|
|
8980
|
+
type: "custom_tool",
|
|
8981
|
+
decoder,
|
|
8982
|
+
done: false
|
|
8983
|
+
});
|
|
8984
|
+
yield createEvent(state, {
|
|
8985
|
+
type: "response.output_item.added",
|
|
8986
|
+
output_index: output.outputIndex,
|
|
8987
|
+
item: structuredClone(item)
|
|
8988
|
+
});
|
|
8989
|
+
if (Object.keys(block.input).length > 0) {
|
|
8990
|
+
const delta = decoder.append(JSON.stringify(block.input));
|
|
8991
|
+
if (delta) yield createEvent(state, {
|
|
8992
|
+
type: "response.custom_tool_call_input.delta",
|
|
8993
|
+
item_id: item.id,
|
|
8994
|
+
output_index: output.outputIndex,
|
|
8995
|
+
delta
|
|
8996
|
+
});
|
|
8997
|
+
}
|
|
8998
|
+
return;
|
|
8999
|
+
}
|
|
9000
|
+
const item = {
|
|
9001
|
+
...common,
|
|
9002
|
+
type: "function_call",
|
|
9003
|
+
arguments: ""
|
|
9004
|
+
};
|
|
9005
|
+
const output = addOutput(state, item);
|
|
9006
|
+
const initialInput = Object.keys(block.input).length > 0 ? JSON.stringify(block.input) : "";
|
|
9007
|
+
state.blocks.set(event.index, {
|
|
9008
|
+
...output,
|
|
9009
|
+
type: "function_tool",
|
|
9010
|
+
done: false
|
|
9011
|
+
});
|
|
9012
|
+
yield createEvent(state, {
|
|
9013
|
+
type: "response.output_item.added",
|
|
9014
|
+
output_index: output.outputIndex,
|
|
9015
|
+
item: structuredClone(item)
|
|
9016
|
+
});
|
|
9017
|
+
if (initialInput) {
|
|
9018
|
+
item.arguments = initialInput;
|
|
9019
|
+
yield createEvent(state, {
|
|
9020
|
+
type: "response.function_call_arguments.delta",
|
|
9021
|
+
item_id: item.id,
|
|
9022
|
+
output_index: output.outputIndex,
|
|
9023
|
+
delta: initialInput
|
|
9024
|
+
});
|
|
9025
|
+
}
|
|
9026
|
+
}
|
|
9027
|
+
}
|
|
9028
|
+
function* translateContentDelta(state, event) {
|
|
9029
|
+
if (state.context.compaction) {
|
|
9030
|
+
if (event.delta.type === "text_delta") state.compactionText += event.delta.text;
|
|
9031
|
+
return;
|
|
9032
|
+
}
|
|
9033
|
+
const block = state.blocks.get(event.index);
|
|
9034
|
+
if (!block) return;
|
|
9035
|
+
if (event.delta.type === "text_delta" && block.type === "message") {
|
|
9036
|
+
block.text += event.delta.text;
|
|
9037
|
+
const part = block.item.content?.[0];
|
|
9038
|
+
if (part?.type === "output_text") part.text = block.text;
|
|
9039
|
+
state.outputText += event.delta.text;
|
|
9040
|
+
yield createEvent(state, {
|
|
9041
|
+
type: "response.output_text.delta",
|
|
9042
|
+
item_id: block.item.id,
|
|
9043
|
+
output_index: block.outputIndex,
|
|
9044
|
+
content_index: 0,
|
|
9045
|
+
delta: event.delta.text
|
|
9046
|
+
});
|
|
9047
|
+
return;
|
|
9048
|
+
}
|
|
9049
|
+
if (event.delta.type === "thinking_delta" && block.type === "reasoning") {
|
|
9050
|
+
for (const translated of appendReasoningText(state, block, event.delta.thinking)) yield translated;
|
|
9051
|
+
return;
|
|
9052
|
+
}
|
|
9053
|
+
if (event.delta.type === "signature_delta" && block.type === "reasoning") {
|
|
9054
|
+
block.signature += event.delta.signature;
|
|
9055
|
+
block.item.encrypted_content = block.signature || EMPTY_SIGNATURE_ENCRYPTED_CONTENT;
|
|
9056
|
+
return;
|
|
9057
|
+
}
|
|
9058
|
+
if (event.delta.type === "input_json_delta" && block.type === "function_tool") {
|
|
9059
|
+
block.item.arguments += event.delta.partial_json;
|
|
9060
|
+
yield createEvent(state, {
|
|
9061
|
+
type: "response.function_call_arguments.delta",
|
|
9062
|
+
item_id: block.item.id,
|
|
9063
|
+
output_index: block.outputIndex,
|
|
9064
|
+
delta: event.delta.partial_json
|
|
9065
|
+
});
|
|
9066
|
+
return;
|
|
9067
|
+
}
|
|
9068
|
+
if (event.delta.type === "input_json_delta" && block.type === "custom_tool") {
|
|
9069
|
+
const delta = block.decoder.append(event.delta.partial_json);
|
|
9070
|
+
if (delta) yield createEvent(state, {
|
|
9071
|
+
type: "response.custom_tool_call_input.delta",
|
|
9072
|
+
item_id: block.item.id,
|
|
9073
|
+
output_index: block.outputIndex,
|
|
9074
|
+
delta
|
|
9075
|
+
});
|
|
9076
|
+
}
|
|
9077
|
+
}
|
|
9078
|
+
function* appendReasoningText(state, block, text) {
|
|
9079
|
+
if (!text) return;
|
|
9080
|
+
if (!block.summaryStarted) {
|
|
9081
|
+
block.summaryStarted = true;
|
|
9082
|
+
yield createEvent(state, {
|
|
9083
|
+
type: "response.reasoning_summary_part.added",
|
|
9084
|
+
item_id: block.item.id,
|
|
9085
|
+
output_index: block.outputIndex,
|
|
9086
|
+
summary_index: 0,
|
|
9087
|
+
part: {
|
|
9088
|
+
type: "summary_text",
|
|
9089
|
+
text: ""
|
|
9090
|
+
}
|
|
9091
|
+
});
|
|
9092
|
+
}
|
|
9093
|
+
block.text += text;
|
|
9094
|
+
block.item.summary = [{
|
|
9095
|
+
type: "summary_text",
|
|
9096
|
+
text: block.text
|
|
9097
|
+
}];
|
|
9098
|
+
yield createEvent(state, {
|
|
9099
|
+
type: "response.reasoning_summary_text.delta",
|
|
9100
|
+
item_id: block.item.id,
|
|
9101
|
+
output_index: block.outputIndex,
|
|
9102
|
+
summary_index: 0,
|
|
9103
|
+
delta: text
|
|
9104
|
+
});
|
|
9105
|
+
}
|
|
9106
|
+
function* closeContentBlock(state, index) {
|
|
9107
|
+
const block = state.blocks.get(index);
|
|
9108
|
+
if (!block || block.done) return;
|
|
9109
|
+
if (block.type === "message") {
|
|
9110
|
+
yield createEvent(state, {
|
|
9111
|
+
type: "response.output_text.done",
|
|
9112
|
+
item_id: block.item.id,
|
|
9113
|
+
output_index: block.outputIndex,
|
|
9114
|
+
content_index: 0,
|
|
9115
|
+
text: block.text
|
|
9116
|
+
});
|
|
9117
|
+
const part = block.item.content?.[0];
|
|
9118
|
+
if (part) yield createEvent(state, {
|
|
9119
|
+
type: "response.content_part.done",
|
|
9120
|
+
item_id: block.item.id,
|
|
9121
|
+
output_index: block.outputIndex,
|
|
9122
|
+
content_index: 0,
|
|
9123
|
+
part: structuredClone(part)
|
|
9124
|
+
});
|
|
9125
|
+
} else if (block.type === "reasoning") {
|
|
9126
|
+
if (block.text) {
|
|
9127
|
+
const part = {
|
|
9128
|
+
type: "summary_text",
|
|
9129
|
+
text: block.text
|
|
9130
|
+
};
|
|
9131
|
+
yield createEvent(state, {
|
|
9132
|
+
type: "response.reasoning_summary_text.done",
|
|
9133
|
+
item_id: block.item.id,
|
|
9134
|
+
output_index: block.outputIndex,
|
|
9135
|
+
summary_index: 0,
|
|
9136
|
+
text: block.text
|
|
9137
|
+
});
|
|
9138
|
+
yield createEvent(state, {
|
|
9139
|
+
type: "response.reasoning_summary_part.done",
|
|
9140
|
+
item_id: block.item.id,
|
|
9141
|
+
output_index: block.outputIndex,
|
|
9142
|
+
summary_index: 0,
|
|
9143
|
+
part
|
|
9144
|
+
});
|
|
9145
|
+
}
|
|
9146
|
+
block.item.encrypted_content = block.signature || EMPTY_SIGNATURE_ENCRYPTED_CONTENT;
|
|
9147
|
+
} else if (block.type === "custom_tool") {
|
|
9148
|
+
const input = block.decoder.finish();
|
|
9149
|
+
block.item.input = input;
|
|
9150
|
+
yield createEvent(state, {
|
|
9151
|
+
type: "response.custom_tool_call_input.done",
|
|
9152
|
+
item_id: block.item.id,
|
|
9153
|
+
output_index: block.outputIndex,
|
|
9154
|
+
name: block.item.name,
|
|
9155
|
+
input
|
|
9156
|
+
});
|
|
9157
|
+
} else yield createEvent(state, {
|
|
9158
|
+
type: "response.function_call_arguments.done",
|
|
9159
|
+
item_id: block.item.id,
|
|
9160
|
+
output_index: block.outputIndex,
|
|
9161
|
+
name: block.item.name,
|
|
9162
|
+
arguments: block.item.arguments
|
|
9163
|
+
});
|
|
9164
|
+
block.item.status = "completed";
|
|
9165
|
+
block.done = true;
|
|
9166
|
+
yield createEvent(state, {
|
|
9167
|
+
type: "response.output_item.done",
|
|
9168
|
+
output_index: block.outputIndex,
|
|
9169
|
+
item: structuredClone(block.item)
|
|
9170
|
+
});
|
|
9171
|
+
state.blocks.delete(index);
|
|
9172
|
+
}
|
|
9173
|
+
function* closeAllBlocks(state) {
|
|
9174
|
+
for (const index of [...state.blocks.keys()].sort((left, right) => left - right)) for (const translated of closeContentBlock(state, index)) yield translated;
|
|
9175
|
+
}
|
|
9176
|
+
function* finishCompaction(state) {
|
|
9177
|
+
if (!state.context.compaction) return;
|
|
9178
|
+
if (state.compactionToolCall) throw new ResponsesMessagesTranslationError("Messages API attempted a tool call during compaction", 502);
|
|
9179
|
+
const summary = state.compactionText.trim();
|
|
9180
|
+
if (!summary) throw new ResponsesMessagesTranslationError("Messages API compaction stream did not contain a text summary", 502);
|
|
9181
|
+
const item = {
|
|
9182
|
+
id: `cmp_${state.responseId.slice(-24)}`,
|
|
9183
|
+
type: "compaction",
|
|
9184
|
+
encrypted_content: encodeMessagesCompaction(summary)
|
|
9185
|
+
};
|
|
9186
|
+
const output = addOutput(state, item);
|
|
9187
|
+
yield createEvent(state, {
|
|
9188
|
+
type: "response.output_item.added",
|
|
9189
|
+
output_index: output.outputIndex,
|
|
9190
|
+
item
|
|
9191
|
+
});
|
|
9192
|
+
yield createEvent(state, {
|
|
9193
|
+
type: "response.output_item.done",
|
|
9194
|
+
output_index: output.outputIndex,
|
|
9195
|
+
item
|
|
9196
|
+
});
|
|
9197
|
+
}
|
|
9198
|
+
function addOutput(state, item) {
|
|
9199
|
+
const outputIndex = state.nextOutputIndex;
|
|
9200
|
+
state.nextOutputIndex += 1;
|
|
9201
|
+
return {
|
|
9202
|
+
item,
|
|
9203
|
+
outputIndex,
|
|
9204
|
+
done: false
|
|
9205
|
+
};
|
|
9206
|
+
}
|
|
9207
|
+
function createLifecycleEvent(state, type) {
|
|
9208
|
+
return createEvent(state, {
|
|
9209
|
+
type,
|
|
9210
|
+
response: createMessagesBackedResponsesResult({
|
|
9211
|
+
context: state.context,
|
|
9212
|
+
createdAt: state.createdAt,
|
|
9213
|
+
id: state.responseId,
|
|
9214
|
+
output: [],
|
|
9215
|
+
outputText: "",
|
|
9216
|
+
status: "in_progress",
|
|
9217
|
+
usage: null
|
|
9218
|
+
})
|
|
9219
|
+
});
|
|
9220
|
+
}
|
|
9221
|
+
function createTerminalEvent(state) {
|
|
9222
|
+
const finish = resolveFinish(state.stopReason);
|
|
9223
|
+
const response = createMessagesBackedResponsesResult({
|
|
9224
|
+
context: state.context,
|
|
9225
|
+
createdAt: state.createdAt,
|
|
9226
|
+
id: state.responseId,
|
|
9227
|
+
output: [],
|
|
9228
|
+
outputText: state.context.compaction ? "" : state.outputText,
|
|
9229
|
+
status: finish.status,
|
|
9230
|
+
incompleteReason: finish.incompleteReason,
|
|
9231
|
+
usage: translateAnthropicUsage(state.usage),
|
|
9232
|
+
copilotUsage: state.copilotUsage
|
|
9233
|
+
});
|
|
9234
|
+
return createEvent(state, {
|
|
9235
|
+
type: finish.status === "incomplete" ? "response.incomplete" : "response.completed",
|
|
9236
|
+
response,
|
|
9237
|
+
copilot_usage: state.copilotUsage
|
|
9238
|
+
});
|
|
9239
|
+
}
|
|
9240
|
+
function createErrorEvent(state, error) {
|
|
9241
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
9242
|
+
return createEvent(state, {
|
|
9243
|
+
type: "error",
|
|
9244
|
+
code: "messages_translation_error",
|
|
9245
|
+
message,
|
|
9246
|
+
param: null,
|
|
9247
|
+
error: {
|
|
9248
|
+
type: "api_error",
|
|
9249
|
+
code: "messages_translation_error",
|
|
9250
|
+
message
|
|
9251
|
+
}
|
|
9252
|
+
});
|
|
9253
|
+
}
|
|
9254
|
+
function createFailedEvent(state, error) {
|
|
9255
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
9256
|
+
return createEvent(state, {
|
|
9257
|
+
type: "response.failed",
|
|
9258
|
+
response: createMessagesBackedResponsesResult({
|
|
9259
|
+
context: state.context,
|
|
9260
|
+
createdAt: state.createdAt,
|
|
9261
|
+
id: state.responseId,
|
|
9262
|
+
output: [],
|
|
9263
|
+
outputText: state.outputText,
|
|
9264
|
+
status: "failed",
|
|
9265
|
+
usage: translateAnthropicUsage(state.usage),
|
|
9266
|
+
copilotUsage: state.copilotUsage,
|
|
9267
|
+
error: {
|
|
9268
|
+
code: "messages_translation_error",
|
|
9269
|
+
message
|
|
9270
|
+
}
|
|
9271
|
+
}),
|
|
9272
|
+
copilot_usage: state.copilotUsage
|
|
9273
|
+
});
|
|
9274
|
+
}
|
|
9275
|
+
function createEvent(state, value) {
|
|
9276
|
+
return {
|
|
9277
|
+
...value,
|
|
9278
|
+
sequence_number: state.sequence++
|
|
9279
|
+
};
|
|
9280
|
+
}
|
|
9281
|
+
function resolveFinish(stopReason) {
|
|
9282
|
+
if (stopReason === "max_tokens") return {
|
|
9283
|
+
status: "incomplete",
|
|
9284
|
+
incompleteReason: "max_output_tokens"
|
|
9285
|
+
};
|
|
9286
|
+
if (stopReason === "refusal") return {
|
|
9287
|
+
status: "incomplete",
|
|
9288
|
+
incompleteReason: "content_filter"
|
|
9289
|
+
};
|
|
9290
|
+
return { status: "completed" };
|
|
9291
|
+
}
|
|
9292
|
+
function mergeUsage(current, incoming) {
|
|
9293
|
+
return {
|
|
9294
|
+
...current,
|
|
9295
|
+
...incoming,
|
|
9296
|
+
input_tokens: incoming.input_tokens ?? current.input_tokens,
|
|
9297
|
+
output_tokens: incoming.output_tokens ?? current.output_tokens
|
|
9298
|
+
};
|
|
9299
|
+
}
|
|
9300
|
+
function parseAnthropicEvent(data) {
|
|
9301
|
+
try {
|
|
9302
|
+
const parsed = JSON.parse(data);
|
|
9303
|
+
if (typeof parsed === "object" && parsed !== null && "type" in parsed && typeof parsed.type === "string") return parsed;
|
|
9304
|
+
} catch {}
|
|
9305
|
+
throw new ResponsesMessagesTranslationError("Messages API returned malformed streaming JSON", 502);
|
|
9306
|
+
}
|
|
9307
|
+
//#endregion
|
|
9308
|
+
//#region src/routes/responses/messages-handler.ts
|
|
9309
|
+
const logger$3 = createHandlerLogger("responses-messages-handler");
|
|
9310
|
+
const responsesMessagesDependencies = { handleCompletionPayload };
|
|
9311
|
+
async function handleResponsesViaMessages(c, options) {
|
|
9312
|
+
try {
|
|
9313
|
+
const translation = translateResponsesToMessages({
|
|
9314
|
+
...options.payload,
|
|
9315
|
+
model: options.publicModel
|
|
9316
|
+
}, {
|
|
9317
|
+
model: options.targetModel,
|
|
9318
|
+
publicModel: options.publicModel
|
|
9319
|
+
});
|
|
9320
|
+
const context = translation;
|
|
9321
|
+
debugJson(logger$3, "Translated Messages request:", {
|
|
9322
|
+
payload: translation.messagesPayload,
|
|
9323
|
+
publicModel: options.publicModel,
|
|
9324
|
+
targetModel: options.targetModel
|
|
9325
|
+
});
|
|
9326
|
+
const messagesResponse = await responsesMessagesDependencies.handleCompletionPayload(c, translation.messagesPayload, {
|
|
9327
|
+
compactType: translation.compaction ? 1 : void 0,
|
|
9328
|
+
skipClaudeAutoModel: true,
|
|
9329
|
+
skipModelMapping: true,
|
|
9330
|
+
skipWebSearch: true,
|
|
9331
|
+
usageEndpoint: "responses"
|
|
9332
|
+
});
|
|
9333
|
+
if (!messagesResponse.ok) return messagesResponse;
|
|
9334
|
+
if ((messagesResponse.headers.get("content-type") ?? "").includes("text/event-stream")) {
|
|
9335
|
+
if (!translation.messagesPayload.stream) throw new ResponsesMessagesTranslationError("Messages API returned a stream for a non-streaming Responses request", 502);
|
|
9336
|
+
return streamTranslatedMessagesEvents(c, messagesResponse, context);
|
|
9337
|
+
}
|
|
9338
|
+
const body = await messagesResponse.json();
|
|
9339
|
+
if (!isAnthropicResponse(body)) throw new ResponsesMessagesTranslationError("Messages API returned an invalid response body", 502);
|
|
9340
|
+
const result = translateAnthropicToResponses(body, context);
|
|
9341
|
+
debugJson(logger$3, "Translated Responses result:", result);
|
|
9342
|
+
if (!translation.messagesPayload.stream) return c.json(result);
|
|
9343
|
+
return streamSSE(c, async (stream) => {
|
|
9344
|
+
for (const event of responsesResultToStreamEvents(result)) await stream.writeSSE({
|
|
9345
|
+
event: event.type,
|
|
9346
|
+
data: JSON.stringify(event)
|
|
9347
|
+
});
|
|
9348
|
+
});
|
|
9349
|
+
} catch (error) {
|
|
9350
|
+
if (error instanceof ResponsesMessagesTranslationError) return c.json({ error: {
|
|
9351
|
+
message: error.message,
|
|
9352
|
+
type: "invalid_request_error"
|
|
9353
|
+
} }, error.status);
|
|
9354
|
+
throw error;
|
|
9355
|
+
}
|
|
9356
|
+
}
|
|
9357
|
+
function streamTranslatedMessagesEvents(c, response, context) {
|
|
9358
|
+
return streamSSE(c, async (stream) => {
|
|
9359
|
+
for await (const event of translateMessagesStream(events(response), context)) {
|
|
9360
|
+
debugJson(logger$3, "Translated Responses stream event:", event);
|
|
9361
|
+
await stream.writeSSE({
|
|
9362
|
+
event: event.type,
|
|
9363
|
+
data: JSON.stringify(event)
|
|
9364
|
+
});
|
|
9365
|
+
}
|
|
9366
|
+
});
|
|
9367
|
+
}
|
|
9368
|
+
function isAnthropicResponse(value) {
|
|
9369
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "message" && "content" in value && Array.isArray(value.content);
|
|
9370
|
+
}
|
|
9371
|
+
//#endregion
|
|
7468
9372
|
//#region src/routes/provider/responses/handler.ts
|
|
7469
9373
|
const logger$2 = createHandlerLogger("provider-responses-handler");
|
|
7470
9374
|
async function handleProviderResponsesForProvider(c, options) {
|
|
@@ -7474,7 +9378,17 @@ async function handleProviderResponsesForProvider(c, options) {
|
|
|
7474
9378
|
provider
|
|
7475
9379
|
});
|
|
7476
9380
|
const providerConfig = await resolveProviderConfig(provider);
|
|
7477
|
-
if (!providerConfig
|
|
9381
|
+
if (!providerConfig) return c.json({ error: {
|
|
9382
|
+
message: `Provider '${provider}' does not support the /v1/responses endpoint`,
|
|
9383
|
+
type: "invalid_request_error"
|
|
9384
|
+
} }, 400);
|
|
9385
|
+
const effectiveType = resolveEffectiveProviderType(providerConfig, payload.model);
|
|
9386
|
+
if (effectiveType === "anthropic" || effectiveType === "openai-compatible") return await handleResponsesViaMessages(c, {
|
|
9387
|
+
payload,
|
|
9388
|
+
publicModel: options.publicModel ?? payload.model,
|
|
9389
|
+
targetModel: `${provider}/${payload.model}`
|
|
9390
|
+
});
|
|
9391
|
+
if (effectiveType !== "openai-responses") return c.json({ error: {
|
|
7478
9392
|
message: `Provider '${provider}' does not support the /v1/responses endpoint`,
|
|
7479
9393
|
type: "invalid_request_error"
|
|
7480
9394
|
} }, 400);
|
|
@@ -7648,19 +9562,22 @@ const handleItemId = (parsed, tracker) => {
|
|
|
7648
9562
|
const logger$1 = createHandlerLogger("responses-handler");
|
|
7649
9563
|
const responsesHandlerDependencies = {
|
|
7650
9564
|
createResponses,
|
|
7651
|
-
|
|
9565
|
+
findEndpointModel,
|
|
9566
|
+
isResponsesApiWebSearchEnabled,
|
|
9567
|
+
resolveMappedModel
|
|
7652
9568
|
};
|
|
7653
9569
|
const handleResponses = async (c) => {
|
|
7654
9570
|
const payload = await c.req.json();
|
|
7655
9571
|
const requestedModel = payload.model;
|
|
7656
|
-
payload.model = resolveMappedModel(payload.model);
|
|
9572
|
+
payload.model = responsesHandlerDependencies.resolveMappedModel(payload.model);
|
|
7657
9573
|
if (payload.model !== requestedModel) consola.debug(`Resolved model mapping: ${requestedModel} -> ${payload.model}`);
|
|
7658
9574
|
const providerModelAlias = parseProviderModelAlias(payload.model);
|
|
7659
9575
|
if (providerModelAlias) {
|
|
7660
9576
|
payload.model = providerModelAlias.model;
|
|
7661
9577
|
return await handleProviderResponsesForProvider(c, {
|
|
7662
9578
|
payload,
|
|
7663
|
-
provider: providerModelAlias.provider
|
|
9579
|
+
provider: providerModelAlias.provider,
|
|
9580
|
+
publicModel: requestedModel
|
|
7664
9581
|
});
|
|
7665
9582
|
}
|
|
7666
9583
|
debugJson(logger$1, "Responses request payload:", payload);
|
|
@@ -7672,6 +9589,21 @@ const handleResponses = async (c) => {
|
|
|
7672
9589
|
logger$1.debug("Generated request ID:", requestId);
|
|
7673
9590
|
const fallbackSessionId = sessionId ?? getUUID(requestId);
|
|
7674
9591
|
logger$1.debug("Extracted session ID:", fallbackSessionId);
|
|
9592
|
+
const selectedModel = responsesHandlerDependencies.findEndpointModel(payload.model);
|
|
9593
|
+
payload.model = selectedModel?.id ?? payload.model;
|
|
9594
|
+
const responsesTransport = getResponsesTransportForModel(selectedModel);
|
|
9595
|
+
if (!responsesTransport) {
|
|
9596
|
+
const supportedEndpoints = selectedModel?.supported_endpoints ?? [];
|
|
9597
|
+
if (supportedEndpoints.includes("/v1/messages") || supportedEndpoints.includes("/chat/completions")) return await handleResponsesViaMessages(c, {
|
|
9598
|
+
payload,
|
|
9599
|
+
publicModel: requestedModel,
|
|
9600
|
+
targetModel: payload.model
|
|
9601
|
+
});
|
|
9602
|
+
return c.json({ error: {
|
|
9603
|
+
message: "This model does not support the responses endpoint. Please choose a different model.",
|
|
9604
|
+
type: "invalid_request_error"
|
|
9605
|
+
} }, 400);
|
|
9606
|
+
}
|
|
7675
9607
|
const recordUsage = createCopilotTokenUsageRecorder({
|
|
7676
9608
|
endpoint: "responses",
|
|
7677
9609
|
fallbackSessionId,
|
|
@@ -7679,12 +9611,6 @@ const handleResponses = async (c) => {
|
|
|
7679
9611
|
});
|
|
7680
9612
|
removeUnsupportedTools(payload);
|
|
7681
9613
|
if (!responsesHandlerDependencies.isResponsesApiWebSearchEnabled()) removeWebSearchTool(payload);
|
|
7682
|
-
const selectedModel = state.models?.data.find((model) => model.id === payload.model);
|
|
7683
|
-
const responsesTransport = getResponsesTransportForModel(selectedModel);
|
|
7684
|
-
if (!responsesTransport) return c.json({ error: {
|
|
7685
|
-
message: "This model does not support the responses endpoint. Please choose a different model.",
|
|
7686
|
-
type: "invalid_request_error"
|
|
7687
|
-
} }, 400);
|
|
7688
9614
|
const sanitizedImageCount = sanitizeOversizedInputImages(payload, selectedModel?.capabilities.limits.vision?.max_prompt_image_size);
|
|
7689
9615
|
if (sanitizedImageCount > 0) logger$1.warn(`Omitted ${sanitizedImageCount} oversized input image(s) before forwarding to Copilot Responses`);
|
|
7690
9616
|
const maxPromptTokens = selectedModel?.capabilities.limits.max_prompt_tokens;
|
|
@@ -7917,4 +9843,4 @@ server.route("/:provider/images", providerImageRoutes);
|
|
|
7917
9843
|
//#endregion
|
|
7918
9844
|
export { server };
|
|
7919
9845
|
|
|
7920
|
-
//# sourceMappingURL=server-
|
|
9846
|
+
//# sourceMappingURL=server-BdY9JFbK.js.map
|