@jeffreycao/copilot-api 2.7.16 → 2.7.18
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/{auth-sKq0qru1.js → auth-BI9j5Vof.js} +10 -5
- package/dist/auth-BI9j5Vof.js.map +1 -0
- package/dist/auth-Dv6K056n.js +2 -0
- package/dist/{config-BKA4Y1t8.js → config-0pYepRvK.js} +15 -8
- package/dist/config-0pYepRvK.js.map +1 -0
- package/dist/{config-store-CC5TNG7V.js → config-store-DeipVulH.js} +3 -2
- package/dist/config-store-DeipVulH.js.map +1 -0
- package/dist/{copilot-runtime-XKDhY-sV.js → copilot-runtime-D7uXIiMk.js} +3 -3
- package/dist/{copilot-runtime-XKDhY-sV.js.map → copilot-runtime-D7uXIiMk.js.map} +1 -1
- package/dist/{debug-BPNjSHgl.js → debug-C26JAmhE.js} +3 -3
- package/dist/{debug-BPNjSHgl.js.map → debug-C26JAmhE.js.map} +1 -1
- package/dist/main.js +4 -4
- package/dist/{provider-Dg-3-rrN.js → provider-BkN9E04x.js} +2 -2
- package/dist/{provider-Dg-3-rrN.js.map → provider-BkN9E04x.js.map} +1 -1
- package/dist/{provider-management-CBrc2nDg.js → provider-management-CLV6-gBT.js} +2 -2
- package/dist/{provider-management-CBrc2nDg.js.map → provider-management-CLV6-gBT.js.map} +1 -1
- package/dist/{server-04fZfBz1.js → server-D8LzQcmu.js} +644 -73
- package/dist/server-D8LzQcmu.js.map +1 -0
- package/dist/{start-qcGeG0TU.js → start-Xf1MJrNI.js} +7 -7
- package/dist/{start-qcGeG0TU.js.map → start-Xf1MJrNI.js.map} +1 -1
- package/dist/{token-CWFRUUIv.js → token-OftpnSxC.js} +3 -3
- package/dist/{token-CWFRUUIv.js.map → token-OftpnSxC.js.map} +1 -1
- package/package.json +1 -1
- package/pages/index.html +4 -4
- package/dist/auth-DuGyJdjW.js +0 -2
- package/dist/auth-sKq0qru1.js.map +0 -1
- package/dist/config-BKA4Y1t8.js.map +0 -1
- package/dist/config-store-CC5TNG7V.js.map +0 -1
- package/dist/server-04fZfBz1.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { D as state, E as isGitHubCopilotEnabled, O as HTTPError, S as PATHS, a as getAnthropicApiKey, c as getConfig, d as getUpstreamTransportConfig, g as isResponsesApiWebSocketEnabled, h as isResponsesApiWebSearchEnabled, i as getAlphaSearchModel, j as forwardError, l as getMessageApiWebSearchModel, m as isMessagesApiEnabled, o as getClaudeAutoModel, p as isAlphaSearchCodexPriorityEnabled, s as getClaudeTokenMultiplier, u as getOpencodeModelContextWindow, w as GITHUB_COPILOT_PROVIDER, y as reloadConfig } from "./config-store-
|
|
2
|
-
import { A as resolveMappedModel, C as getModelResponsesApiCompactThreshold$1, D as isContextManagementEnabledForMessages, E as getSmallModelForProvider, O as isContextManagementEnabledForResponses, S as getModelMappings, T as getSmallModel, _ as getModelsDevModelMaxOutputTokens, d as isProviderModelVisible, f as resolveProviderModelsDevId, g as getModelsDevModel, h as getBuiltinProviderModelRecords, i as listEnabledProviders, j as setModelMappings, k as isGpt56OrAbove, l as getLocalProviderModelRecords, m as builtinProviderModelRegistry, n as getRawProviderConfig, o as resolveEffectiveProviderType, p as usesModelsDevModelCatalog, s as resolveProviderConfigForModel, t as getProviderConfig, u as getProviderModelConfig, v as getModelsDevModelPricing, w as getReasoningEffortForModel, x as getExtraPromptForModel } from "./config-
|
|
3
|
-
import { $ as resolveTraceId$1, C as isOpencodeOauthApp, E as prepareMessageProxyHeaders, G as XAI_API_BASE_URL, J as CODEX_API_BASE_URL, L as getXaiAccessToken, M as compactTextOnlyGuard, N as createAuthMiddleware, O as compactAutoContinuePromptStarts, P as getConfiguredAdminApiKeys, Q as requestContext, S as copilotWebSocketHeaders, T as prepareInteractionHeaders, U as readGitHubToken, W as readGitHubTokenFromEnv, X as forwardCodexResponses, Y as buildCodexRequestHeaders, Z as generateTraceId, _ as parseUserIdMetadata, at as createPooledWebSocketStream, b as copilotHeaders, ct as stripInternalRequestHeaders, d as generateRequestIdFromPayload, et as fetchUpstreamWithLifecycle, f as getRootSessionId, g as isResponsesStream, h as isNullish, it as getResponsesStreamTerminalDisposition, j as compactSystemPromptStarts, k as compactMessageSections, m as isAsyncIterable, n as invalidateCodexRuntime, nt as createResponsesSafeStream, ot as createWebSocketUrl, p as getUUID, rt as encodePoolKeyPart, s as setupCodexToken, tt as createResponsesHttpEventStream, u as stopCopilotRefreshLoop, v as getCopilotUsage, w as prepareForCompact, y as copilotBaseUrl } from "./token-
|
|
1
|
+
import { D as state, E as isGitHubCopilotEnabled, O as HTTPError, S as PATHS, a as getAnthropicApiKey, c as getConfig, d as getUpstreamTransportConfig, g as isResponsesApiWebSocketEnabled, h as isResponsesApiWebSearchEnabled, i as getAlphaSearchModel, j as forwardError, l as getMessageApiWebSearchModel, m as isMessagesApiEnabled, o as getClaudeAutoModel, p as isAlphaSearchCodexPriorityEnabled, s as getClaudeTokenMultiplier, u as getOpencodeModelContextWindow, w as GITHUB_COPILOT_PROVIDER, y as reloadConfig } from "./config-store-DeipVulH.js";
|
|
2
|
+
import { A as resolveMappedModel, C as getModelResponsesApiCompactThreshold$1, D as isContextManagementEnabledForMessages, E as getSmallModelForProvider, O as isContextManagementEnabledForResponses, S as getModelMappings, T as getSmallModel, _ as getModelsDevModelMaxOutputTokens, a as normalizeProviderBaseUrl, d as isProviderModelVisible, f as resolveProviderModelsDevId, g as getModelsDevModel, h as getBuiltinProviderModelRecords, i as listEnabledProviders, j as setModelMappings, k as isGpt56OrAbove, l as getLocalProviderModelRecords, m as builtinProviderModelRegistry, n as getRawProviderConfig, o as resolveEffectiveProviderType, p as usesModelsDevModelCatalog, s as resolveProviderConfigForModel, t as getProviderConfig, u as getProviderModelConfig, v as getModelsDevModelPricing, w as getReasoningEffortForModel, x as getExtraPromptForModel } from "./config-0pYepRvK.js";
|
|
3
|
+
import { $ as resolveTraceId$1, C as isOpencodeOauthApp, E as prepareMessageProxyHeaders, G as XAI_API_BASE_URL, J as CODEX_API_BASE_URL, L as getXaiAccessToken, M as compactTextOnlyGuard, N as createAuthMiddleware, O as compactAutoContinuePromptStarts, P as getConfiguredAdminApiKeys, Q as requestContext, S as copilotWebSocketHeaders, T as prepareInteractionHeaders, U as readGitHubToken, W as readGitHubTokenFromEnv, X as forwardCodexResponses, Y as buildCodexRequestHeaders, Z as generateTraceId, _ as parseUserIdMetadata, at as createPooledWebSocketStream, b as copilotHeaders, ct as stripInternalRequestHeaders, d as generateRequestIdFromPayload, et as fetchUpstreamWithLifecycle, f as getRootSessionId, g as isResponsesStream, h as isNullish, it as getResponsesStreamTerminalDisposition, j as compactSystemPromptStarts, k as compactMessageSections, m as isAsyncIterable, n as invalidateCodexRuntime, nt as createResponsesSafeStream, ot as createWebSocketUrl, p as getUUID, rt as encodePoolKeyPart, s as setupCodexToken, tt as createResponsesHttpEventStream, u as stopCopilotRefreshLoop, v as getCopilotUsage, w as prepareForCompact, y as copilotBaseUrl } from "./token-OftpnSxC.js";
|
|
4
4
|
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-CcvaqM03.js";
|
|
5
|
-
import { n as isProviderAgentModelVisible, t as getProviderAgentModels } from "./provider-management-
|
|
6
|
-
import { n as stopModelsRefreshLoop, t as setupCopilotRuntime } from "./copilot-runtime-
|
|
5
|
+
import { n as isProviderAgentModelVisible, t as getProviderAgentModels } from "./provider-management-CLV6-gBT.js";
|
|
6
|
+
import { n as stopModelsRefreshLoop, t as setupCopilotRuntime } from "./copilot-runtime-D7uXIiMk.js";
|
|
7
7
|
import consola from "consola";
|
|
8
8
|
import { createHash, randomUUID } from "node:crypto";
|
|
9
9
|
import fs, { createWriteStream, readFileSync, rmSync } from "node:fs";
|
|
@@ -1966,6 +1966,8 @@ const createTimeoutDispatcher = (timeoutMs) => ({ dispatch(options, handler) {
|
|
|
1966
1966
|
} });
|
|
1967
1967
|
//#endregion
|
|
1968
1968
|
//#region src/services/providers/provider-proxy.ts
|
|
1969
|
+
const OPENCODE_GO_PROVIDER_NAME = "opencode-go";
|
|
1970
|
+
const OPENCODE_SESSION_HEADER = "x-opencode-session";
|
|
1969
1971
|
const SHARED_FORWARDABLE_HEADERS = ["accept", "user-agent"];
|
|
1970
1972
|
const ANTHROPIC_FORWARDABLE_HEADERS = ["anthropic-version", "anthropic-beta"];
|
|
1971
1973
|
const STRIPPED_RESPONSE_HEADERS = [
|
|
@@ -1981,11 +1983,19 @@ const STRIPPED_RESPONSE_HEADERS = [
|
|
|
1981
1983
|
"upgrade"
|
|
1982
1984
|
];
|
|
1983
1985
|
function resolveProviderEndpointUrl(providerConfig, endpoint) {
|
|
1986
|
+
if (providerConfig.name === OPENCODE_GO_PROVIDER_NAME) {
|
|
1987
|
+
const base = normalizeProviderBaseUrl(providerConfig.baseUrl);
|
|
1988
|
+
return `${/\/v\d+(?:alpha|beta)?$/u.test(base) ? base : `${base}/v1`}/${endpoint}`;
|
|
1989
|
+
}
|
|
1990
|
+
if (providerConfig.type === "google") {
|
|
1991
|
+
const base = providerConfig.baseUrl.replace(/\/+$/u, "");
|
|
1992
|
+
return `${/\/v\d+(?:alpha|beta)?$/u.test(base) ? base : `${base}/v1beta`}/${endpoint}`;
|
|
1993
|
+
}
|
|
1984
1994
|
return `${providerConfig.modelsDevProviderId ? providerConfig.baseUrl.replace(/\/(?:chat\/completions|responses)$/u, "") : `${providerConfig.baseUrl}/v1`}/${endpoint}`;
|
|
1985
1995
|
}
|
|
1986
1996
|
function buildProviderUpstreamHeaders(providerConfig, requestHeaders) {
|
|
1987
1997
|
const authHeaders = {};
|
|
1988
|
-
if (providerConfig.authType === "x-api-key"
|
|
1998
|
+
if (providerConfig.authType === "x-api-key" || providerConfig.authType === "x-goog-api-key") authHeaders[providerConfig.authType] = providerConfig.apiKey;
|
|
1989
1999
|
else authHeaders.authorization = `Bearer ${providerConfig.apiKey}`;
|
|
1990
2000
|
const headers = {
|
|
1991
2001
|
"content-type": "application/json",
|
|
@@ -2004,8 +2014,6 @@ function buildProviderUpstreamHeaders(providerConfig, requestHeaders) {
|
|
|
2004
2014
|
}
|
|
2005
2015
|
return headers;
|
|
2006
2016
|
}
|
|
2007
|
-
const OPENCODE_GO_PROVIDER_NAME = "opencode-go";
|
|
2008
|
-
const OPENCODE_SESSION_HEADER = "x-opencode-session";
|
|
2009
2017
|
const resolveOpencodeMessagesSession = (payload) => {
|
|
2010
2018
|
const sessionAffinity = requestContext.getStore()?.sessionAffinity?.trim();
|
|
2011
2019
|
if (sessionAffinity) return sessionAffinity;
|
|
@@ -2093,12 +2101,51 @@ async function forwardProviderResponses(providerConfig, payload, requestHeaders,
|
|
|
2093
2101
|
}
|
|
2094
2102
|
const PROVIDER_MODELS_TIMEOUT_MS = 15e3;
|
|
2095
2103
|
async function forwardProviderModels(providerConfig, requestHeaders) {
|
|
2104
|
+
if (providerConfig.type === "google") return await forwardGoogleModels(providerConfig, requestHeaders);
|
|
2096
2105
|
return await fetch(resolveProviderEndpointUrl(providerConfig, "models"), {
|
|
2097
2106
|
method: "GET",
|
|
2098
2107
|
headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
|
|
2099
2108
|
signal: AbortSignal.timeout(PROVIDER_MODELS_TIMEOUT_MS)
|
|
2100
2109
|
});
|
|
2101
2110
|
}
|
|
2111
|
+
async function forwardGoogleModels(provider, requestHeaders) {
|
|
2112
|
+
const data = [];
|
|
2113
|
+
const pageTokens = /* @__PURE__ */ new Set();
|
|
2114
|
+
let pageToken;
|
|
2115
|
+
const signal = AbortSignal.timeout(PROVIDER_MODELS_TIMEOUT_MS);
|
|
2116
|
+
do {
|
|
2117
|
+
const url = new URL(resolveProviderEndpointUrl(provider, "models"));
|
|
2118
|
+
url.searchParams.set("pageSize", "1000");
|
|
2119
|
+
if (pageToken) url.searchParams.set("pageToken", pageToken);
|
|
2120
|
+
const upstream = await fetch(url, {
|
|
2121
|
+
headers: buildProviderUpstreamHeaders(provider, requestHeaders),
|
|
2122
|
+
signal
|
|
2123
|
+
});
|
|
2124
|
+
if (!upstream.ok) return upstream;
|
|
2125
|
+
const body = await upstream.json();
|
|
2126
|
+
for (const model of body.models ?? []) {
|
|
2127
|
+
if (!model.supportedGenerationMethods?.includes("generateContent")) continue;
|
|
2128
|
+
data.push({
|
|
2129
|
+
id: model.name.replace(/^models\//u, ""),
|
|
2130
|
+
object: "model",
|
|
2131
|
+
owned_by: provider.name,
|
|
2132
|
+
name: model.displayName,
|
|
2133
|
+
display_name: model.displayName,
|
|
2134
|
+
description: model.description,
|
|
2135
|
+
context_window: model.inputTokenLimit,
|
|
2136
|
+
max_output_tokens: model.outputTokenLimit
|
|
2137
|
+
});
|
|
2138
|
+
}
|
|
2139
|
+
pageToken = body.nextPageToken;
|
|
2140
|
+
if (pageToken && pageTokens.has(pageToken)) throw new Error("Google models returned a repeated page token");
|
|
2141
|
+
if (pageToken) pageTokens.add(pageToken);
|
|
2142
|
+
} while (pageToken);
|
|
2143
|
+
return Response.json({
|
|
2144
|
+
object: "list",
|
|
2145
|
+
data,
|
|
2146
|
+
has_more: false
|
|
2147
|
+
});
|
|
2148
|
+
}
|
|
2102
2149
|
/** Align with Codex images: long-running generation/edits need a generous cap. */
|
|
2103
2150
|
const PROVIDER_IMAGES_TIMEOUT_MS = 9e5;
|
|
2104
2151
|
const providerImagesDispatcher = createTimeoutDispatcher(PROVIDER_IMAGES_TIMEOUT_MS);
|
|
@@ -2142,7 +2189,7 @@ async function forwardProviderImages(providerConfig, request, operation) {
|
|
|
2142
2189
|
}
|
|
2143
2190
|
//#endregion
|
|
2144
2191
|
//#region src/routes/alpha-search/alpha-search-responses.ts
|
|
2145
|
-
const logger$
|
|
2192
|
+
const logger$19 = createHandlerLogger("alpha-search-responses-handler");
|
|
2146
2193
|
const SESSION_TTL_MS = 36e5;
|
|
2147
2194
|
const MAX_SESSIONS = 128;
|
|
2148
2195
|
const MAX_URL_REFERENCES = 256;
|
|
@@ -2329,7 +2376,7 @@ function buildInstruction(operations, responseLength) {
|
|
|
2329
2376
|
function unavailableReference(refId) {
|
|
2330
2377
|
return `Reference ${JSON.stringify(refId)} is unavailable or expired. Search or open the URL again.`;
|
|
2331
2378
|
}
|
|
2332
|
-
function invalidRequest$
|
|
2379
|
+
function invalidRequest$2(c, message) {
|
|
2333
2380
|
return c.json({ error: {
|
|
2334
2381
|
message,
|
|
2335
2382
|
type: "invalid_request_error"
|
|
@@ -2472,13 +2519,13 @@ async function resolveRemoteModel(c, request, provider) {
|
|
|
2472
2519
|
message: `Provider '${provider}' not found or disabled`,
|
|
2473
2520
|
type: "invalid_request_error"
|
|
2474
2521
|
} }, 404);
|
|
2475
|
-
if (alphaSearchResponsesDependencies.resolveEffectiveProviderType(providerConfig, model) !== "openai-responses") return invalidRequest$
|
|
2522
|
+
if (alphaSearchResponsesDependencies.resolveEffectiveProviderType(providerConfig, model) !== "openai-responses") return invalidRequest$2(c, `Provider '${provider}' does not support the /v1/responses endpoint required for alpha search`);
|
|
2476
2523
|
return {
|
|
2477
2524
|
model,
|
|
2478
2525
|
providerConfig: resolveProviderConfigForModel(providerConfig, model)
|
|
2479
2526
|
};
|
|
2480
2527
|
}
|
|
2481
|
-
if (!alphaSearchResponsesDependencies.findEndpointModel(model)?.supported_endpoints?.includes("/responses")) return invalidRequest$
|
|
2528
|
+
if (!alphaSearchResponsesDependencies.findEndpointModel(model)?.supported_endpoints?.includes("/responses")) return invalidRequest$2(c, `Model '${model}' does not support the Copilot Responses endpoint required for alpha search`);
|
|
2482
2529
|
return { model };
|
|
2483
2530
|
}
|
|
2484
2531
|
function createRemoteResponsesPayload(request, model, instruction) {
|
|
@@ -2500,14 +2547,14 @@ function createRemoteResponsesPayload(request, model, instruction) {
|
|
|
2500
2547
|
};
|
|
2501
2548
|
}
|
|
2502
2549
|
async function requestProviderSearch(c, providerConfig, payload, model, sessionId) {
|
|
2503
|
-
debugJson(logger$
|
|
2550
|
+
debugJson(logger$19, "Alpha search provider Responses request:", {
|
|
2504
2551
|
payload,
|
|
2505
2552
|
provider: providerConfig.name
|
|
2506
2553
|
});
|
|
2507
2554
|
const upstreamResponse = await forwardProviderResponses(providerConfig, payload, c.req.raw.headers, { clientSignal: c.req.raw.signal });
|
|
2508
2555
|
if (!upstreamResponse.ok) throw new HTTPError(`Failed to create ${providerConfig.name} responses for alpha search`, upstreamResponse);
|
|
2509
2556
|
const result = await upstreamResponse.json();
|
|
2510
|
-
debugJson(logger$
|
|
2557
|
+
debugJson(logger$19, "Alpha search provider Responses result:", {
|
|
2511
2558
|
provider: providerConfig.name,
|
|
2512
2559
|
result
|
|
2513
2560
|
});
|
|
@@ -2523,7 +2570,7 @@ async function requestProviderSearch(c, providerConfig, payload, model, sessionI
|
|
|
2523
2570
|
return result;
|
|
2524
2571
|
}
|
|
2525
2572
|
async function requestCopilotSearch(payload, model, requestId, sessionId, clientSignal) {
|
|
2526
|
-
debugJson(logger$
|
|
2573
|
+
debugJson(logger$19, "Alpha search Copilot Responses request:", payload);
|
|
2527
2574
|
const result = await alphaSearchResponsesDependencies.createResponses(payload, {
|
|
2528
2575
|
vision: false,
|
|
2529
2576
|
initiator: "agent",
|
|
@@ -2532,7 +2579,7 @@ async function requestCopilotSearch(payload, model, requestId, sessionId, client
|
|
|
2532
2579
|
sessionId,
|
|
2533
2580
|
clientSignal
|
|
2534
2581
|
});
|
|
2535
|
-
debugJson(logger$
|
|
2582
|
+
debugJson(logger$19, "Alpha search Copilot Responses result:", result);
|
|
2536
2583
|
alphaSearchResponsesDependencies.createUsageRecorder(model, sessionId)({
|
|
2537
2584
|
...normalizeResponsesUsage(result.usage),
|
|
2538
2585
|
total_nano_aiu: normalizeOptionalToken(result.copilot_usage?.total_nano_aiu)
|
|
@@ -2608,7 +2655,7 @@ async function handleAlphaSearchResponses(c, options) {
|
|
|
2608
2655
|
const parsed = alphaSearchRequestSchema.safeParse(options.request);
|
|
2609
2656
|
if (!parsed.success) {
|
|
2610
2657
|
const issue = parsed.error.issues[0];
|
|
2611
|
-
return invalidRequest$
|
|
2658
|
+
return invalidRequest$2(c, `Invalid alpha search request at ${issue?.path.join(".") || "body"}: ${issue?.message ?? "invalid value"}`);
|
|
2612
2659
|
}
|
|
2613
2660
|
const request = parsed.data;
|
|
2614
2661
|
const now = alphaSearchResponsesDependencies.now();
|
|
@@ -2647,7 +2694,7 @@ async function forwardCodexAlphaSearch(request) {
|
|
|
2647
2694
|
}
|
|
2648
2695
|
//#endregion
|
|
2649
2696
|
//#region src/routes/alpha-search/route.ts
|
|
2650
|
-
const logger$
|
|
2697
|
+
const logger$18 = createHandlerLogger("alpha-search-handler");
|
|
2651
2698
|
const alphaSearchRoutes = new Hono();
|
|
2652
2699
|
const alphaSearchRouteDependencies = {
|
|
2653
2700
|
findEndpointModel,
|
|
@@ -2667,9 +2714,9 @@ function parseDebugBody(body) {
|
|
|
2667
2714
|
}
|
|
2668
2715
|
}
|
|
2669
2716
|
async function forwardCodexAlphaSearchRequest(request) {
|
|
2670
|
-
await debugJsonAsync(logger$
|
|
2717
|
+
await debugJsonAsync(logger$18, "alpha_search.codex.request", async () => ({ body: parseDebugBody(await request.clone().text()) }));
|
|
2671
2718
|
const upstreamResponse = await alphaSearchRouteDependencies.forwardCodexAlphaSearch(request);
|
|
2672
|
-
await debugJsonAsync(logger$
|
|
2719
|
+
await debugJsonAsync(logger$18, "alpha_search.codex.response", async () => ({
|
|
2673
2720
|
body: parseDebugBody(await upstreamResponse.clone().text()),
|
|
2674
2721
|
statusCode: upstreamResponse.status
|
|
2675
2722
|
}));
|
|
@@ -2690,7 +2737,7 @@ async function handleCodexRequest(c, request, resolvedProviderConfig) {
|
|
|
2690
2737
|
} }, 404);
|
|
2691
2738
|
return await forwardCodexAlphaSearchRequest(request);
|
|
2692
2739
|
}
|
|
2693
|
-
function invalidRequest(c, message) {
|
|
2740
|
+
function invalidRequest$1(c, message) {
|
|
2694
2741
|
return c.json({ error: {
|
|
2695
2742
|
message,
|
|
2696
2743
|
type: "invalid_request_error"
|
|
@@ -2701,9 +2748,9 @@ async function parseAlphaSearchBody(c) {
|
|
|
2701
2748
|
try {
|
|
2702
2749
|
body = await c.req.raw.clone().json();
|
|
2703
2750
|
} catch {
|
|
2704
|
-
return invalidRequest(c, "Invalid alpha search request: expected JSON body");
|
|
2751
|
+
return invalidRequest$1(c, "Invalid alpha search request: expected JSON body");
|
|
2705
2752
|
}
|
|
2706
|
-
if (typeof body?.model !== "string") return invalidRequest(c, "Invalid alpha search request: model must be a string");
|
|
2753
|
+
if (typeof body?.model !== "string") return invalidRequest$1(c, "Invalid alpha search request: model must be a string");
|
|
2707
2754
|
return body;
|
|
2708
2755
|
}
|
|
2709
2756
|
/**
|
|
@@ -2733,9 +2780,9 @@ async function handleAlphaSearchRequest(c, resolvedProviderConfig) {
|
|
|
2733
2780
|
const messagesBackedModel = await isMessagesBackedModel(resolvedRequestedModel);
|
|
2734
2781
|
if (messagesBackedModel) {
|
|
2735
2782
|
const searchModel = alphaSearchRouteDependencies.getAlphaSearchModel();
|
|
2736
|
-
if (!searchModel) return invalidRequest(c, "alphaSearchModel is disabled; Messages-backed Codex models require a native Responses search model");
|
|
2783
|
+
if (!searchModel) return invalidRequest$1(c, "alphaSearchModel is disabled; Messages-backed Codex models require a native Responses search model");
|
|
2737
2784
|
const resolvedSearchModel = alphaSearchRouteDependencies.resolveMappedModel(searchModel);
|
|
2738
|
-
if (!await isNativeResponsesModel(resolvedSearchModel)) return invalidRequest(c, `Configured alphaSearchModel '${searchModel}' does not support the Responses endpoint required for alpha search`);
|
|
2785
|
+
if (!await isNativeResponsesModel(resolvedSearchModel)) return invalidRequest$1(c, `Configured alphaSearchModel '${searchModel}' does not support the Responses endpoint required for alpha search`);
|
|
2739
2786
|
consola.debug(`Redirected alpha search model: ${resolvedRequestedModel} -> ${resolvedSearchModel}`);
|
|
2740
2787
|
payload.model = resolvedSearchModel;
|
|
2741
2788
|
providerModelAlias = parseProviderModelAlias(payload.model);
|
|
@@ -2780,7 +2827,7 @@ alphaSearchRoutes.post("/", async (c) => {
|
|
|
2780
2827
|
try {
|
|
2781
2828
|
return await handleAlphaSearchRequest(c);
|
|
2782
2829
|
} catch (error) {
|
|
2783
|
-
logger$
|
|
2830
|
+
logger$18.error("alpha_search.error", { error });
|
|
2784
2831
|
return await forwardError(c, error);
|
|
2785
2832
|
}
|
|
2786
2833
|
});
|
|
@@ -2935,7 +2982,7 @@ const normalizeProviderResponsesReasoningEffort = (payload, providerConfig) => {
|
|
|
2935
2982
|
};
|
|
2936
2983
|
//#endregion
|
|
2937
2984
|
//#region src/routes/provider/chat-completions/handler.ts
|
|
2938
|
-
const logger$
|
|
2985
|
+
const logger$17 = createHandlerLogger("provider-chat-completions-handler");
|
|
2939
2986
|
async function handleProviderChatCompletionsForProvider(c, options) {
|
|
2940
2987
|
const { payload, provider } = options;
|
|
2941
2988
|
const configuredProvider = await resolveProviderConfig(provider);
|
|
@@ -2950,13 +2997,13 @@ async function handleProviderChatCompletionsForProvider(c, options) {
|
|
|
2950
2997
|
applyProviderStreamOptions(payload);
|
|
2951
2998
|
applyDashScopePreserveThinkingDefault(payload, providerConfig);
|
|
2952
2999
|
applyProviderContextCache(payload, modelConfig, providerConfig);
|
|
2953
|
-
debugJson(logger$
|
|
3000
|
+
debugJson(logger$17, "provider.chat_completions.request", {
|
|
2954
3001
|
payload,
|
|
2955
3002
|
provider
|
|
2956
3003
|
});
|
|
2957
3004
|
const upstreamResponse = await forwardProviderChatCompletions(providerConfig, payload, c.req.raw.headers, { clientSignal: c.req.raw.signal });
|
|
2958
3005
|
if (!upstreamResponse.ok) {
|
|
2959
|
-
logger$
|
|
3006
|
+
logger$17.error("Failed to create provider chat completions", {
|
|
2960
3007
|
provider,
|
|
2961
3008
|
statusCode: upstreamResponse.status
|
|
2962
3009
|
});
|
|
@@ -2970,7 +3017,7 @@ async function handleProviderChatCompletionsForProvider(c, options) {
|
|
|
2970
3017
|
});
|
|
2971
3018
|
const responseBody = await upstreamResponse.clone().json();
|
|
2972
3019
|
recordUsage(normalizeOpenAIUsage(responseBody.usage));
|
|
2973
|
-
debugJson(logger$
|
|
3020
|
+
debugJson(logger$17, "provider.chat_completions.response", responseBody);
|
|
2974
3021
|
return createProviderProxyResponse(upstreamResponse);
|
|
2975
3022
|
}
|
|
2976
3023
|
const applyProviderStreamOptions = (payload) => {
|
|
@@ -2992,12 +3039,12 @@ const createProviderChatCompletionsUsageRecorder = (payload, provider, modelConf
|
|
|
2992
3039
|
providerName: provider
|
|
2993
3040
|
});
|
|
2994
3041
|
const streamProviderChatCompletions = (c, upstreamResponse, options) => {
|
|
2995
|
-
logger$
|
|
3042
|
+
logger$17.debug("provider.chat_completions.streaming", { provider: options.provider });
|
|
2996
3043
|
return streamSSE(c, async (stream) => {
|
|
2997
3044
|
let usage = {};
|
|
2998
3045
|
try {
|
|
2999
3046
|
for await (const chunk of events(upstreamResponse)) {
|
|
3000
|
-
debugJson(logger$
|
|
3047
|
+
debugJson(logger$17, "provider.chat_completions.stream_chunk", chunk);
|
|
3001
3048
|
if (chunk.data && chunk.data !== "[DONE]") {
|
|
3002
3049
|
const parsedChunk = parseChatCompletionChunkData(chunk.data);
|
|
3003
3050
|
if (parsedChunk?.usage) usage = normalizeOpenAIUsage(parsedChunk.usage);
|
|
@@ -3056,7 +3103,7 @@ const createChatCompletions = async (payload, options) => {
|
|
|
3056
3103
|
};
|
|
3057
3104
|
//#endregion
|
|
3058
3105
|
//#region src/routes/chat-completions/handler.ts
|
|
3059
|
-
const logger$
|
|
3106
|
+
const logger$16 = createHandlerLogger("chat-completions-handler");
|
|
3060
3107
|
async function handleCompletion$1(c) {
|
|
3061
3108
|
let payload = await c.req.json();
|
|
3062
3109
|
const requestedModel = payload.model;
|
|
@@ -3070,7 +3117,7 @@ async function handleCompletion$1(c) {
|
|
|
3070
3117
|
provider: providerModelAlias.provider
|
|
3071
3118
|
});
|
|
3072
3119
|
}
|
|
3073
|
-
debugJson(logger$
|
|
3120
|
+
debugJson(logger$16, "Request payload:", payload);
|
|
3074
3121
|
const selectedModel = findEndpointModel(payload.model);
|
|
3075
3122
|
payload.model = selectedModel?.id ?? payload.model;
|
|
3076
3123
|
if (isNullish(payload.max_tokens) && isNullish(payload.max_completion_tokens)) {
|
|
@@ -3078,16 +3125,16 @@ async function handleCompletion$1(c) {
|
|
|
3078
3125
|
...payload,
|
|
3079
3126
|
max_tokens: selectedModel?.capabilities.limits.max_output_tokens
|
|
3080
3127
|
};
|
|
3081
|
-
debugJson(logger$
|
|
3128
|
+
debugJson(logger$16, "Set max_tokens to:", payload.max_tokens);
|
|
3082
3129
|
}
|
|
3083
3130
|
if (payload.model.includes("gpt")) {
|
|
3084
3131
|
if (isNullish(payload.max_completion_tokens)) payload.max_completion_tokens = payload.max_tokens;
|
|
3085
3132
|
delete payload.max_tokens;
|
|
3086
3133
|
}
|
|
3087
3134
|
const requestId = generateRequestIdFromPayload(payload);
|
|
3088
|
-
logger$
|
|
3135
|
+
logger$16.debug("Generated request ID:", requestId);
|
|
3089
3136
|
const sessionId = getUUID(requestId);
|
|
3090
|
-
logger$
|
|
3137
|
+
logger$16.debug("Extracted session ID:", sessionId);
|
|
3091
3138
|
const recordUsage = createCopilotTokenUsageRecorder({
|
|
3092
3139
|
endpoint: "chat_completions",
|
|
3093
3140
|
fallbackSessionId: sessionId,
|
|
@@ -3099,18 +3146,18 @@ async function handleCompletion$1(c) {
|
|
|
3099
3146
|
sessionId
|
|
3100
3147
|
});
|
|
3101
3148
|
if (isNonStreaming$1(response)) {
|
|
3102
|
-
debugJson(logger$
|
|
3149
|
+
debugJson(logger$16, "Non-streaming response:", response);
|
|
3103
3150
|
recordUsage({
|
|
3104
3151
|
...normalizeOpenAIUsage(response.usage),
|
|
3105
3152
|
total_nano_aiu: normalizeOptionalToken(response.copilot_usage?.total_nano_aiu)
|
|
3106
3153
|
});
|
|
3107
3154
|
return c.json(response);
|
|
3108
3155
|
}
|
|
3109
|
-
logger$
|
|
3156
|
+
logger$16.debug("Streaming response");
|
|
3110
3157
|
return streamSSE(c, async (stream) => {
|
|
3111
3158
|
let usage = {};
|
|
3112
3159
|
for await (const chunk of response) {
|
|
3113
|
-
debugJson(logger$
|
|
3160
|
+
debugJson(logger$16, "Streaming chunk:", chunk);
|
|
3114
3161
|
const parsedChunk = parseChatCompletionChunk(chunk);
|
|
3115
3162
|
if (parsedChunk?.usage || parsedChunk?.copilot_usage) usage = {
|
|
3116
3163
|
...normalizeOpenAIUsage(parsedChunk.usage),
|
|
@@ -3340,7 +3387,7 @@ async function forwardCodexImages(request, operation) {
|
|
|
3340
3387
|
}
|
|
3341
3388
|
//#endregion
|
|
3342
3389
|
//#region src/routes/images/shared.ts
|
|
3343
|
-
const logger$
|
|
3390
|
+
const logger$15 = createHandlerLogger("images-handler");
|
|
3344
3391
|
const imageRouteDependencies = {
|
|
3345
3392
|
debugJsonAsync,
|
|
3346
3393
|
getImageEditModel,
|
|
@@ -3388,16 +3435,16 @@ async function handleCodexImages(c, operation, resolvedProviderConfig, request =
|
|
|
3388
3435
|
message: "Provider 'codex' not found or disabled",
|
|
3389
3436
|
type: "invalid_request_error"
|
|
3390
3437
|
} }, 404);
|
|
3391
|
-
if (operation === "generations") await imageRouteDependencies.debugJsonAsync(logger$
|
|
3392
|
-
else debugJson(logger$
|
|
3438
|
+
if (operation === "generations") await imageRouteDependencies.debugJsonAsync(logger$15, "images.generations.codex.request", async () => ({ body: await request.clone().text() }));
|
|
3439
|
+
else debugJson(logger$15, "images.edits.codex.request", getContentMetadata(request.headers));
|
|
3393
3440
|
const upstreamResponse = await forwardCodexImages(request, operation);
|
|
3394
|
-
debugJson(logger$
|
|
3441
|
+
debugJson(logger$15, `images.${operation}.codex.response`, {
|
|
3395
3442
|
...getContentMetadata(upstreamResponse.headers),
|
|
3396
3443
|
statusCode: upstreamResponse.status
|
|
3397
3444
|
});
|
|
3398
3445
|
return createProviderProxyResponse(upstreamResponse);
|
|
3399
3446
|
} catch (error) {
|
|
3400
|
-
logger$
|
|
3447
|
+
logger$15.error(`images.${operation}.codex.error`, { error });
|
|
3401
3448
|
return await forwardError(c, error);
|
|
3402
3449
|
}
|
|
3403
3450
|
}
|
|
@@ -3416,7 +3463,7 @@ async function routeImagesRequest(c, operation, parsed) {
|
|
|
3416
3463
|
const request = parsed.createRequest(providerModelAlias.model);
|
|
3417
3464
|
if (providerConfig.name === "codex") return await handleCodexImages(c, operation, providerConfig, request);
|
|
3418
3465
|
return await forwardProviderImagesWithLogging(providerConfig, request, operation, {
|
|
3419
|
-
logger: logger$
|
|
3466
|
+
logger: logger$15,
|
|
3420
3467
|
provider: providerModelAlias.provider
|
|
3421
3468
|
});
|
|
3422
3469
|
}
|
|
@@ -3910,12 +3957,12 @@ async function forwardXaiImages(providerConfig, request, operation, payload) {
|
|
|
3910
3957
|
method: "POST",
|
|
3911
3958
|
signal: request.signal
|
|
3912
3959
|
}), operation, {
|
|
3913
|
-
logger: logger$
|
|
3960
|
+
logger: logger$15,
|
|
3914
3961
|
provider: "xai"
|
|
3915
3962
|
}), void 0, {
|
|
3916
3963
|
clientSignal: request.signal,
|
|
3917
3964
|
onImageUrl: (url) => {
|
|
3918
|
-
logger$
|
|
3965
|
+
logger$15.info("images.xai.output.url", JSON.stringify({
|
|
3919
3966
|
operation,
|
|
3920
3967
|
url
|
|
3921
3968
|
}));
|
|
@@ -3939,7 +3986,7 @@ async function handleXaiImageEdit(c, model, parsed) {
|
|
|
3939
3986
|
}
|
|
3940
3987
|
//#endregion
|
|
3941
3988
|
//#region src/routes/images/temp-form-data.ts
|
|
3942
|
-
const logger$
|
|
3989
|
+
const logger$14 = createHandlerLogger("images-temp-form-data");
|
|
3943
3990
|
const multipartStagingDependencies = { createWriteStream };
|
|
3944
3991
|
/**
|
|
3945
3992
|
* Matches the images forwarding timeouts: an upstream upload may take that
|
|
@@ -4131,7 +4178,7 @@ async function stageMultipartBodyToDisk(body, contentType, limitOverrides = {})
|
|
|
4131
4178
|
recursive: true
|
|
4132
4179
|
});
|
|
4133
4180
|
} catch (error) {
|
|
4134
|
-
logger$
|
|
4181
|
+
logger$14.warn("Failed to remove staged images temp directory", {
|
|
4135
4182
|
directory,
|
|
4136
4183
|
error
|
|
4137
4184
|
});
|
|
@@ -4153,7 +4200,7 @@ async function stageMultipartBodyToDisk(body, contentType, limitOverrides = {})
|
|
|
4153
4200
|
recursive: true
|
|
4154
4201
|
});
|
|
4155
4202
|
} catch (error) {
|
|
4156
|
-
logger$
|
|
4203
|
+
logger$14.warn("Failed to remove staged images temp directory on exit", {
|
|
4157
4204
|
directory,
|
|
4158
4205
|
error
|
|
4159
4206
|
});
|
|
@@ -4234,7 +4281,7 @@ async function handleImagesEdits(c) {
|
|
|
4234
4281
|
} }, error instanceof MultipartBodyTooLargeError ? 413 : 400);
|
|
4235
4282
|
const invalidRequest = xaiImagesRequestErrorResponse(c, error);
|
|
4236
4283
|
if (invalidRequest) return invalidRequest;
|
|
4237
|
-
logger$
|
|
4284
|
+
logger$15.error("images.edits.error", { error });
|
|
4238
4285
|
return await forwardError(c, error);
|
|
4239
4286
|
}
|
|
4240
4287
|
}
|
|
@@ -4286,7 +4333,7 @@ async function handleImagesGenerations(c) {
|
|
|
4286
4333
|
} catch (error) {
|
|
4287
4334
|
const invalidRequest = xaiImagesRequestErrorResponse(c, error);
|
|
4288
4335
|
if (invalidRequest) return invalidRequest;
|
|
4289
|
-
logger$
|
|
4336
|
+
logger$15.error("images.generations.error", { error });
|
|
4290
4337
|
return await forwardError(c, error);
|
|
4291
4338
|
}
|
|
4292
4339
|
}
|
|
@@ -5380,7 +5427,7 @@ const prepareMessagesApiPayload = (payload, selectedModel) => {
|
|
|
5380
5427
|
};
|
|
5381
5428
|
//#endregion
|
|
5382
5429
|
//#region src/routes/provider/messages/count-tokens-handler.ts
|
|
5383
|
-
const logger$
|
|
5430
|
+
const logger$13 = createHandlerLogger("provider-count-tokens-handler");
|
|
5384
5431
|
async function handleProviderCountTokens(c) {
|
|
5385
5432
|
const provider = c.req.param("provider");
|
|
5386
5433
|
const payload = await c.req.json();
|
|
@@ -5408,7 +5455,7 @@ async function handleProviderCountTokensForProvider(c, options) {
|
|
|
5408
5455
|
const selectedModel = createFallbackModel(modelId);
|
|
5409
5456
|
const tokenCount = await getTokenCount(openAIPayload, selectedModel);
|
|
5410
5457
|
const finalTokenCount = tokenCount.input + tokenCount.output;
|
|
5411
|
-
logger$
|
|
5458
|
+
logger$13.debug("provider.count_tokens.success", {
|
|
5412
5459
|
provider,
|
|
5413
5460
|
model: anthropicPayload.model,
|
|
5414
5461
|
input_tokens: finalTokenCount
|
|
@@ -8461,6 +8508,539 @@ function getModels() {
|
|
|
8461
8508
|
};
|
|
8462
8509
|
}
|
|
8463
8510
|
//#endregion
|
|
8511
|
+
//#region src/routes/messages/google-thinking.ts
|
|
8512
|
+
function supportsThinkingControls(modelId) {
|
|
8513
|
+
const model = modelId.replace(/^models\//u, "").toLowerCase();
|
|
8514
|
+
if (/(?:^|-)(?:tts|live|image)(?:-|$)/u.test(model)) return false;
|
|
8515
|
+
if (/^gemini-3\.8-flash(?:-|$)/u.test(model)) return true;
|
|
8516
|
+
const major = /^gemini-(\d+)(?:\.\d+)?(?:-|$)/u.exec(model)?.[1];
|
|
8517
|
+
return major !== void 0 && Number(major) >= 4;
|
|
8518
|
+
}
|
|
8519
|
+
function translateGoogleThinking(payload) {
|
|
8520
|
+
const thinking = payload.thinking;
|
|
8521
|
+
const effort = payload.output_config?.effort;
|
|
8522
|
+
if (!thinking && !effort || !supportsThinkingControls(payload.model)) return void 0;
|
|
8523
|
+
const config = { includeThoughts: thinking?.type !== "disabled" };
|
|
8524
|
+
if (thinking?.type === "disabled") return {
|
|
8525
|
+
...config,
|
|
8526
|
+
thinkingLevel: "LOW"
|
|
8527
|
+
};
|
|
8528
|
+
const requestedBudget = thinking?.budget_tokens;
|
|
8529
|
+
if (requestedBudget !== void 0) {
|
|
8530
|
+
if (requestedBudget !== -1) config.thinkingLevel = requestedBudget <= 2048 ? "LOW" : requestedBudget <= 8192 ? "MEDIUM" : "HIGH";
|
|
8531
|
+
return config;
|
|
8532
|
+
}
|
|
8533
|
+
if (effort) config.thinkingLevel = effort === "low" ? "LOW" : effort === "medium" ? "MEDIUM" : "HIGH";
|
|
8534
|
+
return config;
|
|
8535
|
+
}
|
|
8536
|
+
//#endregion
|
|
8537
|
+
//#region src/routes/messages/google-translation.ts
|
|
8538
|
+
const GOOGLE_SIGNATURE_PREFIX = "google:";
|
|
8539
|
+
function encodeGoogleSignature(signature, target) {
|
|
8540
|
+
return GOOGLE_SIGNATURE_PREFIX + Buffer.from(JSON.stringify({
|
|
8541
|
+
signature,
|
|
8542
|
+
target
|
|
8543
|
+
})).toString("base64url");
|
|
8544
|
+
}
|
|
8545
|
+
function decodeGoogleSignature(value) {
|
|
8546
|
+
if (!value.startsWith(GOOGLE_SIGNATURE_PREFIX)) return void 0;
|
|
8547
|
+
try {
|
|
8548
|
+
const decoded = JSON.parse(Buffer.from(value.slice(7), "base64url").toString());
|
|
8549
|
+
if (typeof decoded !== "object" || decoded === null) return void 0;
|
|
8550
|
+
const { signature, target } = decoded;
|
|
8551
|
+
if (typeof signature !== "string") return void 0;
|
|
8552
|
+
if (target === "thinking" || target === "previous") return {
|
|
8553
|
+
signature,
|
|
8554
|
+
target
|
|
8555
|
+
};
|
|
8556
|
+
if (typeof target === "object" && target !== null && "toolUseId" in target && typeof target.toolUseId === "string" && target.toolUseId.length > 0) return {
|
|
8557
|
+
signature,
|
|
8558
|
+
target: { toolUseId: target.toolUseId }
|
|
8559
|
+
};
|
|
8560
|
+
} catch {}
|
|
8561
|
+
}
|
|
8562
|
+
function translateThinkingBlock(block, parts, toolSignatures) {
|
|
8563
|
+
const decoded = decodeGoogleSignature(block.signature);
|
|
8564
|
+
if (decoded?.target === "previous") {
|
|
8565
|
+
const previous = parts.at(-1);
|
|
8566
|
+
if (previous) previous.thoughtSignature = decoded.signature;
|
|
8567
|
+
} else if (decoded && typeof decoded.target === "object") toolSignatures.set(decoded.target.toolUseId, decoded.signature);
|
|
8568
|
+
if (block.thinking || decoded?.target === "thinking") parts.push({
|
|
8569
|
+
text: block.thinking,
|
|
8570
|
+
thought: true,
|
|
8571
|
+
...decoded?.target === "thinking" && { thoughtSignature: decoded.signature }
|
|
8572
|
+
});
|
|
8573
|
+
}
|
|
8574
|
+
function invalidRequest(message) {
|
|
8575
|
+
throw new HTTPError(message, Response.json({ error: {
|
|
8576
|
+
type: "invalid_request_error",
|
|
8577
|
+
message
|
|
8578
|
+
} }, { status: 400 }));
|
|
8579
|
+
}
|
|
8580
|
+
function translateToolResult(block, toolNames) {
|
|
8581
|
+
const name = toolNames.get(block.tool_use_id);
|
|
8582
|
+
if (!name) invalidRequest(`Google tool result has no matching tool_use: ${block.tool_use_id}`);
|
|
8583
|
+
const text = [];
|
|
8584
|
+
const media = [];
|
|
8585
|
+
const references = [];
|
|
8586
|
+
const mediaPrefix = createHash("sha256").update(block.tool_use_id).digest("hex").slice(0, 16);
|
|
8587
|
+
if (typeof block.content === "string") text.push(block.content);
|
|
8588
|
+
else for (const item of block.content) if (item.type === "text") text.push(item.text);
|
|
8589
|
+
else if (item.type === "tool_reference") text.push(item.tool_name);
|
|
8590
|
+
else {
|
|
8591
|
+
const displayName = `tool-result-${mediaPrefix}-${media.length}`;
|
|
8592
|
+
media.push({ inlineData: {
|
|
8593
|
+
mimeType: item.source.media_type,
|
|
8594
|
+
data: item.source.data,
|
|
8595
|
+
displayName
|
|
8596
|
+
} });
|
|
8597
|
+
references.push({ $ref: displayName });
|
|
8598
|
+
}
|
|
8599
|
+
return { functionResponse: {
|
|
8600
|
+
id: block.tool_use_id,
|
|
8601
|
+
name,
|
|
8602
|
+
response: { [block.is_error ? "error" : "output"]: media.length > 0 ? {
|
|
8603
|
+
text: text.join("\n"),
|
|
8604
|
+
media: references
|
|
8605
|
+
} : text.join("\n") },
|
|
8606
|
+
...media.length > 0 && { parts: media }
|
|
8607
|
+
} };
|
|
8608
|
+
}
|
|
8609
|
+
function translateAnthropicToGoogle(payload) {
|
|
8610
|
+
const result = {
|
|
8611
|
+
contents: [],
|
|
8612
|
+
generationConfig: {
|
|
8613
|
+
candidateCount: 1,
|
|
8614
|
+
maxOutputTokens: payload.max_tokens,
|
|
8615
|
+
temperature: payload.temperature,
|
|
8616
|
+
topP: payload.top_p,
|
|
8617
|
+
topK: payload.top_k,
|
|
8618
|
+
stopSequences: payload.stop_sequences
|
|
8619
|
+
}
|
|
8620
|
+
};
|
|
8621
|
+
const systemParts = typeof payload.system === "string" ? [{ text: payload.system }] : (payload.system ?? []).map((block) => ({ text: block.text }));
|
|
8622
|
+
const toolNames = /* @__PURE__ */ new Map();
|
|
8623
|
+
const toolSignatures = /* @__PURE__ */ new Map();
|
|
8624
|
+
for (const message of payload.messages) {
|
|
8625
|
+
if (message.role === "system") {
|
|
8626
|
+
systemParts.push(...typeof message.content === "string" ? [{ text: message.content }] : message.content.map((block) => ({ text: block.text })));
|
|
8627
|
+
continue;
|
|
8628
|
+
}
|
|
8629
|
+
const parts = [];
|
|
8630
|
+
if (typeof message.content === "string") {
|
|
8631
|
+
if (message.content) parts.push({ text: message.content });
|
|
8632
|
+
} else for (const block of message.content) switch (block.type) {
|
|
8633
|
+
case "text":
|
|
8634
|
+
if (block.text) parts.push({ text: block.text });
|
|
8635
|
+
break;
|
|
8636
|
+
case "image":
|
|
8637
|
+
case "document":
|
|
8638
|
+
parts.push({ inlineData: {
|
|
8639
|
+
mimeType: block.source.media_type,
|
|
8640
|
+
data: block.source.data
|
|
8641
|
+
} });
|
|
8642
|
+
break;
|
|
8643
|
+
case "tool_use":
|
|
8644
|
+
toolNames.set(block.id, block.name);
|
|
8645
|
+
parts.push({ functionCall: {
|
|
8646
|
+
id: block.id,
|
|
8647
|
+
name: block.name,
|
|
8648
|
+
args: block.input
|
|
8649
|
+
} });
|
|
8650
|
+
break;
|
|
8651
|
+
case "tool_result":
|
|
8652
|
+
parts.push(translateToolResult(block, toolNames));
|
|
8653
|
+
break;
|
|
8654
|
+
case "thinking": translateThinkingBlock(block, parts, toolSignatures);
|
|
8655
|
+
}
|
|
8656
|
+
if (!parts.length) continue;
|
|
8657
|
+
const role = message.role === "assistant" ? "model" : "user";
|
|
8658
|
+
const previous = result.contents.at(-1);
|
|
8659
|
+
if (previous?.role === role) previous.parts.push(...parts);
|
|
8660
|
+
else result.contents.push({
|
|
8661
|
+
role,
|
|
8662
|
+
parts
|
|
8663
|
+
});
|
|
8664
|
+
}
|
|
8665
|
+
for (const content of result.contents) for (const part of content.parts) {
|
|
8666
|
+
const id = part.functionCall?.id;
|
|
8667
|
+
const signature = id ? toolSignatures.get(id) : void 0;
|
|
8668
|
+
if (signature !== void 0) part.thoughtSignature = signature;
|
|
8669
|
+
}
|
|
8670
|
+
if (systemParts.length) result.systemInstruction = { parts: systemParts };
|
|
8671
|
+
if (payload.tools?.length) result.tools = [{ functionDeclarations: payload.tools.map((tool) => {
|
|
8672
|
+
if (tool.type && tool.type !== "custom") invalidRequest(`Google does not support Anthropic server tool '${tool.type}'`);
|
|
8673
|
+
return {
|
|
8674
|
+
name: tool.name,
|
|
8675
|
+
description: tool.description,
|
|
8676
|
+
parametersJsonSchema: tool.input_schema
|
|
8677
|
+
};
|
|
8678
|
+
}) }];
|
|
8679
|
+
if (payload.tool_choice) {
|
|
8680
|
+
const choice = payload.tool_choice;
|
|
8681
|
+
result.toolConfig = { functionCallingConfig: {
|
|
8682
|
+
mode: choice.type === "none" ? "NONE" : choice.type === "auto" ? "AUTO" : "ANY",
|
|
8683
|
+
...choice.type === "tool" && choice.name && { allowedFunctionNames: [choice.name] }
|
|
8684
|
+
} };
|
|
8685
|
+
}
|
|
8686
|
+
if (payload.output_config?.format) {
|
|
8687
|
+
result.generationConfig.responseMimeType = "application/json";
|
|
8688
|
+
result.generationConfig.responseJsonSchema = payload.output_config.format.schema;
|
|
8689
|
+
}
|
|
8690
|
+
const thinkingConfig = translateGoogleThinking(payload);
|
|
8691
|
+
if (thinkingConfig) result.generationConfig.thinkingConfig = thinkingConfig;
|
|
8692
|
+
return result;
|
|
8693
|
+
}
|
|
8694
|
+
function translateGoogleUsage(usage = {}) {
|
|
8695
|
+
const cached = usage.cachedContentTokenCount ?? 0;
|
|
8696
|
+
return {
|
|
8697
|
+
input_tokens: Math.max(0, (usage.promptTokenCount ?? 0) - cached),
|
|
8698
|
+
output_tokens: (usage.candidatesTokenCount ?? 0) + (usage.thoughtsTokenCount ?? 0),
|
|
8699
|
+
cache_read_input_tokens: cached
|
|
8700
|
+
};
|
|
8701
|
+
}
|
|
8702
|
+
function getGoogleStopReason(finishReason, hasTools, blocked) {
|
|
8703
|
+
if (blocked || [
|
|
8704
|
+
"SAFETY",
|
|
8705
|
+
"RECITATION",
|
|
8706
|
+
"BLOCKLIST",
|
|
8707
|
+
"PROHIBITED_CONTENT",
|
|
8708
|
+
"SPII",
|
|
8709
|
+
"IMAGE_SAFETY"
|
|
8710
|
+
].includes(finishReason ?? "")) return "refusal";
|
|
8711
|
+
if (finishReason === "MAX_TOKENS") return "max_tokens";
|
|
8712
|
+
if (finishReason === "STOP") return hasTools ? "tool_use" : "end_turn";
|
|
8713
|
+
throw new Error(`Google generation ended without a successful finish reason (${finishReason ?? "missing"})`);
|
|
8714
|
+
}
|
|
8715
|
+
function googleSignatureBlock(signature, toolUseId) {
|
|
8716
|
+
return {
|
|
8717
|
+
type: "thinking",
|
|
8718
|
+
thinking: "",
|
|
8719
|
+
signature: encodeGoogleSignature(signature, toolUseId ? { toolUseId } : "previous")
|
|
8720
|
+
};
|
|
8721
|
+
}
|
|
8722
|
+
function translateGoogleToAnthropic(response, model) {
|
|
8723
|
+
if (response.error) throw new Error(response.error.message ?? "Google generation failed");
|
|
8724
|
+
const candidate = response.candidates?.[0];
|
|
8725
|
+
const content = [];
|
|
8726
|
+
for (const part of candidate?.content?.parts ?? []) {
|
|
8727
|
+
if (part.functionCall) {
|
|
8728
|
+
const call = part.functionCall;
|
|
8729
|
+
const id = call.id || `toolu_${randomUUID()}`;
|
|
8730
|
+
if (part.thoughtSignature) {
|
|
8731
|
+
const previous = content.at(-1);
|
|
8732
|
+
const signature = googleSignatureBlock(part.thoughtSignature, id);
|
|
8733
|
+
if (previous?.type === "thinking" && !previous.signature) previous.signature = signature.signature;
|
|
8734
|
+
else content.push(signature);
|
|
8735
|
+
}
|
|
8736
|
+
content.push({
|
|
8737
|
+
type: "tool_use",
|
|
8738
|
+
id,
|
|
8739
|
+
name: call.name,
|
|
8740
|
+
input: call.args ?? {}
|
|
8741
|
+
});
|
|
8742
|
+
continue;
|
|
8743
|
+
} else if (part.thought) {
|
|
8744
|
+
content.push({
|
|
8745
|
+
type: "thinking",
|
|
8746
|
+
thinking: part.text ?? "",
|
|
8747
|
+
signature: part.thoughtSignature ? encodeGoogleSignature(part.thoughtSignature, "thinking") : ""
|
|
8748
|
+
});
|
|
8749
|
+
continue;
|
|
8750
|
+
} else if (part.text !== void 0) content.push({
|
|
8751
|
+
type: "text",
|
|
8752
|
+
text: part.text
|
|
8753
|
+
});
|
|
8754
|
+
if (part.thoughtSignature) content.push(googleSignatureBlock(part.thoughtSignature));
|
|
8755
|
+
}
|
|
8756
|
+
return {
|
|
8757
|
+
id: response.responseId || `msg_${randomUUID()}`,
|
|
8758
|
+
type: "message",
|
|
8759
|
+
role: "assistant",
|
|
8760
|
+
model,
|
|
8761
|
+
content,
|
|
8762
|
+
stop_reason: getGoogleStopReason(candidate?.finishReason, content.some((block) => block.type === "tool_use"), response.promptFeedback?.blockReason),
|
|
8763
|
+
stop_sequence: null,
|
|
8764
|
+
usage: translateGoogleUsage(response.usageMetadata)
|
|
8765
|
+
};
|
|
8766
|
+
}
|
|
8767
|
+
//#endregion
|
|
8768
|
+
//#region src/routes/messages/google-stream-translation.ts
|
|
8769
|
+
var GoogleMessagesStreamTranslator = class {
|
|
8770
|
+
started = false;
|
|
8771
|
+
nextIndex = 0;
|
|
8772
|
+
block;
|
|
8773
|
+
hasTools = false;
|
|
8774
|
+
finishReason;
|
|
8775
|
+
blocked;
|
|
8776
|
+
usageMetadata = {};
|
|
8777
|
+
model;
|
|
8778
|
+
constructor(model) {
|
|
8779
|
+
this.model = model;
|
|
8780
|
+
}
|
|
8781
|
+
get usage() {
|
|
8782
|
+
return translateGoogleUsage(this.usageMetadata);
|
|
8783
|
+
}
|
|
8784
|
+
push(response) {
|
|
8785
|
+
if (response.error) throw new Error(response.error.message ?? "Google stream failed");
|
|
8786
|
+
this.usageMetadata = {
|
|
8787
|
+
...this.usageMetadata,
|
|
8788
|
+
...response.usageMetadata
|
|
8789
|
+
};
|
|
8790
|
+
const events = [];
|
|
8791
|
+
if (!this.started) {
|
|
8792
|
+
this.started = true;
|
|
8793
|
+
events.push({
|
|
8794
|
+
type: "message_start",
|
|
8795
|
+
message: {
|
|
8796
|
+
id: response.responseId || `msg_${randomUUID()}`,
|
|
8797
|
+
type: "message",
|
|
8798
|
+
role: "assistant",
|
|
8799
|
+
model: this.model,
|
|
8800
|
+
content: [],
|
|
8801
|
+
stop_reason: null,
|
|
8802
|
+
stop_sequence: null,
|
|
8803
|
+
usage: {
|
|
8804
|
+
...this.usage,
|
|
8805
|
+
output_tokens: 0
|
|
8806
|
+
}
|
|
8807
|
+
}
|
|
8808
|
+
});
|
|
8809
|
+
}
|
|
8810
|
+
const candidate = response.candidates?.[0];
|
|
8811
|
+
for (const part of candidate?.content?.parts ?? []) this.addPart(part, events);
|
|
8812
|
+
this.finishReason = candidate?.finishReason ?? this.finishReason;
|
|
8813
|
+
this.blocked = response.promptFeedback?.blockReason ?? this.blocked;
|
|
8814
|
+
return events;
|
|
8815
|
+
}
|
|
8816
|
+
finish() {
|
|
8817
|
+
const stopReason = getGoogleStopReason(this.finishReason, this.hasTools, this.blocked);
|
|
8818
|
+
const events = [];
|
|
8819
|
+
this.closeBlock(events);
|
|
8820
|
+
events.push({
|
|
8821
|
+
type: "message_delta",
|
|
8822
|
+
delta: {
|
|
8823
|
+
stop_reason: stopReason,
|
|
8824
|
+
stop_sequence: null
|
|
8825
|
+
},
|
|
8826
|
+
usage: this.usage
|
|
8827
|
+
}, { type: "message_stop" });
|
|
8828
|
+
return events;
|
|
8829
|
+
}
|
|
8830
|
+
addPart(part, events) {
|
|
8831
|
+
if (part.functionCall) {
|
|
8832
|
+
const call = part.functionCall;
|
|
8833
|
+
const id = call.id || `toolu_${randomUUID()}`;
|
|
8834
|
+
if (part.thoughtSignature) this.addSignature(part.thoughtSignature, events, id);
|
|
8835
|
+
this.closeBlock(events);
|
|
8836
|
+
const index = this.nextIndex++;
|
|
8837
|
+
this.hasTools = true;
|
|
8838
|
+
events.push({
|
|
8839
|
+
type: "content_block_start",
|
|
8840
|
+
index,
|
|
8841
|
+
content_block: {
|
|
8842
|
+
type: "tool_use",
|
|
8843
|
+
id,
|
|
8844
|
+
name: call.name,
|
|
8845
|
+
input: {}
|
|
8846
|
+
}
|
|
8847
|
+
}, {
|
|
8848
|
+
type: "content_block_delta",
|
|
8849
|
+
index,
|
|
8850
|
+
delta: {
|
|
8851
|
+
type: "input_json_delta",
|
|
8852
|
+
partial_json: JSON.stringify(call.args ?? {})
|
|
8853
|
+
}
|
|
8854
|
+
}, {
|
|
8855
|
+
type: "content_block_stop",
|
|
8856
|
+
index
|
|
8857
|
+
});
|
|
8858
|
+
return;
|
|
8859
|
+
}
|
|
8860
|
+
if (part.text || part.thought) {
|
|
8861
|
+
const type = part.thought ? "thinking" : "text";
|
|
8862
|
+
if (this.block?.type !== type) this.closeBlock(events);
|
|
8863
|
+
if (!this.block) {
|
|
8864
|
+
const index = this.nextIndex++;
|
|
8865
|
+
this.block = {
|
|
8866
|
+
index,
|
|
8867
|
+
type,
|
|
8868
|
+
signed: false
|
|
8869
|
+
};
|
|
8870
|
+
events.push({
|
|
8871
|
+
type: "content_block_start",
|
|
8872
|
+
index,
|
|
8873
|
+
content_block: type === "thinking" ? {
|
|
8874
|
+
type,
|
|
8875
|
+
thinking: ""
|
|
8876
|
+
} : {
|
|
8877
|
+
type,
|
|
8878
|
+
text: ""
|
|
8879
|
+
}
|
|
8880
|
+
});
|
|
8881
|
+
}
|
|
8882
|
+
events.push({
|
|
8883
|
+
type: "content_block_delta",
|
|
8884
|
+
index: this.block.index,
|
|
8885
|
+
delta: type === "thinking" ? {
|
|
8886
|
+
type: "thinking_delta",
|
|
8887
|
+
thinking: part.text ?? ""
|
|
8888
|
+
} : {
|
|
8889
|
+
type: "text_delta",
|
|
8890
|
+
text: part.text ?? ""
|
|
8891
|
+
}
|
|
8892
|
+
});
|
|
8893
|
+
}
|
|
8894
|
+
if (part.thoughtSignature) this.addSignature(part.thoughtSignature, events);
|
|
8895
|
+
}
|
|
8896
|
+
addSignature(signature, events, toolUseId) {
|
|
8897
|
+
if (this.block?.type === "thinking") {
|
|
8898
|
+
this.block.signed = true;
|
|
8899
|
+
events.push({
|
|
8900
|
+
type: "content_block_delta",
|
|
8901
|
+
index: this.block.index,
|
|
8902
|
+
delta: {
|
|
8903
|
+
type: "signature_delta",
|
|
8904
|
+
signature: encodeGoogleSignature(signature, toolUseId ? { toolUseId } : "thinking")
|
|
8905
|
+
}
|
|
8906
|
+
});
|
|
8907
|
+
this.closeBlock(events);
|
|
8908
|
+
return;
|
|
8909
|
+
}
|
|
8910
|
+
this.closeBlock(events);
|
|
8911
|
+
const index = this.nextIndex++;
|
|
8912
|
+
events.push({
|
|
8913
|
+
type: "content_block_start",
|
|
8914
|
+
index,
|
|
8915
|
+
content_block: {
|
|
8916
|
+
type: "thinking",
|
|
8917
|
+
thinking: ""
|
|
8918
|
+
}
|
|
8919
|
+
}, {
|
|
8920
|
+
type: "content_block_delta",
|
|
8921
|
+
index,
|
|
8922
|
+
delta: {
|
|
8923
|
+
type: "signature_delta",
|
|
8924
|
+
signature: encodeGoogleSignature(signature, toolUseId ? { toolUseId } : "previous")
|
|
8925
|
+
}
|
|
8926
|
+
}, {
|
|
8927
|
+
type: "content_block_stop",
|
|
8928
|
+
index
|
|
8929
|
+
});
|
|
8930
|
+
}
|
|
8931
|
+
closeBlock(events) {
|
|
8932
|
+
if (!this.block) return;
|
|
8933
|
+
if (this.block.type === "thinking" && !this.block.signed) events.push({
|
|
8934
|
+
type: "content_block_delta",
|
|
8935
|
+
index: this.block.index,
|
|
8936
|
+
delta: {
|
|
8937
|
+
type: "signature_delta",
|
|
8938
|
+
signature: ""
|
|
8939
|
+
}
|
|
8940
|
+
});
|
|
8941
|
+
events.push({
|
|
8942
|
+
type: "content_block_stop",
|
|
8943
|
+
index: this.block.index
|
|
8944
|
+
});
|
|
8945
|
+
this.block = void 0;
|
|
8946
|
+
}
|
|
8947
|
+
};
|
|
8948
|
+
//#endregion
|
|
8949
|
+
//#region src/services/providers/google.ts
|
|
8950
|
+
async function forwardGoogleGenerateContent(provider, model, payload, requestHeaders, options) {
|
|
8951
|
+
const modelId = encodeURIComponent(model.replace(/^models\//u, ""));
|
|
8952
|
+
const method = options.stream ? "streamGenerateContent" : "generateContent";
|
|
8953
|
+
const url = new URL(resolveProviderEndpointUrl(provider, `models/${modelId}:${method}`));
|
|
8954
|
+
if (options.stream) url.searchParams.set("alt", "sse");
|
|
8955
|
+
const headers = buildProviderUpstreamHeaders(provider, requestHeaders);
|
|
8956
|
+
applyOpencodeSessionHeader(provider, headers, options.sessionId);
|
|
8957
|
+
headers.accept = options.stream ? "text/event-stream" : "application/json";
|
|
8958
|
+
const transport = getUpstreamTransportConfig();
|
|
8959
|
+
return await fetchUpstreamWithLifecycle(url, {
|
|
8960
|
+
method: "POST",
|
|
8961
|
+
headers,
|
|
8962
|
+
body: JSON.stringify(payload)
|
|
8963
|
+
}, {
|
|
8964
|
+
clientSignal: options.clientSignal,
|
|
8965
|
+
headersTimeoutMs: transport.headersTimeoutMs,
|
|
8966
|
+
streamInactivityTimeoutMs: transport.streamInactivityTimeoutMs
|
|
8967
|
+
});
|
|
8968
|
+
}
|
|
8969
|
+
//#endregion
|
|
8970
|
+
//#region src/routes/provider/messages/google-handler.ts
|
|
8971
|
+
const logger$12 = createHandlerLogger("provider-google-messages");
|
|
8972
|
+
async function handleGoogleProviderMessages(c, payload, provider, usageEndpoint) {
|
|
8973
|
+
debugJson(logger$12, "provider.messages.google.original_request", payload);
|
|
8974
|
+
const translated = translateAnthropicToGoogle(payload);
|
|
8975
|
+
const modelConfig = provider.models?.[payload.model];
|
|
8976
|
+
const extraGenerationConfig = modelConfig?.extraBody?.generationConfig;
|
|
8977
|
+
if (extraGenerationConfig && typeof extraGenerationConfig === "object" && !Array.isArray(extraGenerationConfig)) {
|
|
8978
|
+
const generationConfig = translated.generationConfig;
|
|
8979
|
+
for (const [key, value] of Object.entries(extraGenerationConfig)) if (generationConfig[key] === void 0) generationConfig[key] = value;
|
|
8980
|
+
}
|
|
8981
|
+
applyMissingExtraBody(translated, { extraBody: modelConfig?.extraBody });
|
|
8982
|
+
debugJson(logger$12, "provider.messages.google.request", translated);
|
|
8983
|
+
const controller = new AbortController();
|
|
8984
|
+
const signal = AbortSignal.any([controller.signal, c.req.raw.signal]);
|
|
8985
|
+
const upstream = await forwardGoogleGenerateContent(provider, payload.model, translated, c.req.raw.headers, {
|
|
8986
|
+
stream: payload.stream === true,
|
|
8987
|
+
clientSignal: signal,
|
|
8988
|
+
sessionId: resolveOpencodeMessagesSession(payload)
|
|
8989
|
+
});
|
|
8990
|
+
if (!upstream.ok) throw new HTTPError("Failed to create Google response", upstream);
|
|
8991
|
+
const recordUsage = createProviderTokenUsageRecorder({
|
|
8992
|
+
endpoint: usageEndpoint ?? "provider_messages",
|
|
8993
|
+
model: payload.model,
|
|
8994
|
+
providerName: provider.name,
|
|
8995
|
+
pricing: modelConfig?.pricing,
|
|
8996
|
+
pricingCurrency: provider.pricingCurrency,
|
|
8997
|
+
sessionId: parseUserIdMetadata(payload.metadata?.user_id).sessionId
|
|
8998
|
+
});
|
|
8999
|
+
if (!payload.stream) {
|
|
9000
|
+
const response = translateGoogleToAnthropic(await upstream.json(), payload.model);
|
|
9001
|
+
recordUsage(normalizeAnthropicUsage(response.usage));
|
|
9002
|
+
return c.json(response);
|
|
9003
|
+
}
|
|
9004
|
+
return streamSSE(c, async (stream) => {
|
|
9005
|
+
const translator = new GoogleMessagesStreamTranslator(payload.model);
|
|
9006
|
+
stream.onAbort(() => controller.abort());
|
|
9007
|
+
const writeEvents = async (items) => {
|
|
9008
|
+
for (const item of items) {
|
|
9009
|
+
debugJson(logger$12, "provider.messages.google.translated_event:", item);
|
|
9010
|
+
await writeSSEIfConnected(stream, {
|
|
9011
|
+
event: item.type,
|
|
9012
|
+
data: JSON.stringify(item)
|
|
9013
|
+
});
|
|
9014
|
+
}
|
|
9015
|
+
};
|
|
9016
|
+
try {
|
|
9017
|
+
const response = new Response(upstream.body?.pipeThrough(new TransformStream(), { signal }), { headers: upstream.headers });
|
|
9018
|
+
if (response.headers.get("content-type")?.includes("text/event-stream")) for await (const event of events(response, signal)) {
|
|
9019
|
+
if (!event.data || event.data === "[DONE]") continue;
|
|
9020
|
+
const response = JSON.parse(event.data);
|
|
9021
|
+
debugJson(logger$12, "provider.messages.google.raw_stream_event:", response);
|
|
9022
|
+
await writeEvents(translator.push(response));
|
|
9023
|
+
}
|
|
9024
|
+
else await writeEvents(translator.push(await response.json()));
|
|
9025
|
+
if (!signal.aborted) await writeEvents(translator.finish());
|
|
9026
|
+
} catch (error) {
|
|
9027
|
+
if (!signal.aborted) {
|
|
9028
|
+
logger$12.warn("provider.messages.google.stream_interrupted", error);
|
|
9029
|
+
await writeEvents([{
|
|
9030
|
+
type: "error",
|
|
9031
|
+
error: {
|
|
9032
|
+
type: "api_error",
|
|
9033
|
+
message: error instanceof Error ? error.message : "Google stream interrupted"
|
|
9034
|
+
}
|
|
9035
|
+
}]);
|
|
9036
|
+
}
|
|
9037
|
+
} finally {
|
|
9038
|
+
controller.abort();
|
|
9039
|
+
recordUsage(normalizeAnthropicUsage(translator.usage));
|
|
9040
|
+
}
|
|
9041
|
+
});
|
|
9042
|
+
}
|
|
9043
|
+
//#endregion
|
|
8464
9044
|
//#region src/routes/provider/messages/handler.ts
|
|
8465
9045
|
const logger$11 = createHandlerLogger("provider-messages-handler");
|
|
8466
9046
|
const providerMessagesHandlerDependencies = { resolveProviderConfig };
|
|
@@ -8497,6 +9077,10 @@ async function handleProviderMessagesForProvider(c, options) {
|
|
|
8497
9077
|
normalizeSystemMessages(payload);
|
|
8498
9078
|
applyModelDefaults(payload, modelConfig);
|
|
8499
9079
|
appendClaudeContinuationMessage(payload);
|
|
9080
|
+
if (effectiveType === "google") {
|
|
9081
|
+
stripWebSearchServerTool(payload);
|
|
9082
|
+
return await handleGoogleProviderMessages(c, payload, providerConfig, usageEndpoint);
|
|
9083
|
+
}
|
|
8500
9084
|
if (effectiveType === "openai-responses") {
|
|
8501
9085
|
if (hasWebSearchServerTool(payload)) {
|
|
8502
9086
|
if (isWebSearchOnlyRequest(payload)) return await handleOpenAIResponsesProviderWebSearchMessages(c, {
|
|
@@ -9984,20 +10568,13 @@ function getCopilotCodexCandidates() {
|
|
|
9984
10568
|
function isCopilotCodexCandidate(model) {
|
|
9985
10569
|
return (model.supported_endpoints ?? []).some((endpoint) => endpoint === MESSAGES_ENDPOINT || endpoint === CHAT_COMPLETIONS_ENDPOINT || RESPONSES_ENDPOINTS.has(endpoint)) && model.capabilities.supports.tool_calls !== false;
|
|
9986
10570
|
}
|
|
9987
|
-
function describeCopilotAdapter(model) {
|
|
9988
|
-
const supportsResponses = model.supported_endpoints?.some((endpoint) => RESPONSES_ENDPOINTS.has(endpoint));
|
|
9989
|
-
if (model.id.startsWith("gpt") && supportsResponses) return `${model.name} through the Copilot Responses API.`;
|
|
9990
|
-
if (model.supported_endpoints?.includes(MESSAGES_ENDPOINT)) return `${model.name} through the Copilot Messages adapter.`;
|
|
9991
|
-
if (supportsResponses) return `${model.name} through the Copilot Messages-to-Responses adapter.`;
|
|
9992
|
-
return `${model.name} through the Copilot Messages-to-Chat adapter.`;
|
|
9993
|
-
}
|
|
9994
10571
|
function createCopilotCodexCandidate(model) {
|
|
9995
10572
|
const reasoningEfforts = normalizeReasoningEfforts(model.capabilities.supports.reasoning_effort);
|
|
9996
10573
|
return {
|
|
9997
10574
|
slug: toClientModelId(model.id),
|
|
9998
10575
|
catalogSlug: model.id,
|
|
9999
10576
|
displayName: model.name,
|
|
10000
|
-
description:
|
|
10577
|
+
description: model.name,
|
|
10001
10578
|
contextWindow: positiveNumber(model.capabilities.limits.max_prompt_tokens, 256e3),
|
|
10002
10579
|
maxOutputTokens: positiveNumber(model.capabilities.limits.max_output_tokens, 32e3),
|
|
10003
10580
|
inputModalities: model.capabilities.supports.vision ? ["text", "image"] : ["text"],
|
|
@@ -10029,18 +10606,12 @@ async function getProviderCodexCandidates(provider, requestHeaders) {
|
|
|
10029
10606
|
}
|
|
10030
10607
|
}
|
|
10031
10608
|
function isMessagesFallbackProviderType(type) {
|
|
10032
|
-
return type === "anthropic" || type === "openai-compatible";
|
|
10033
|
-
}
|
|
10034
|
-
function describeProviderAdapter(type) {
|
|
10035
|
-
if (type === "anthropic") return "Messages";
|
|
10036
|
-
if (type === "openai-responses") return "Messages-to-Responses";
|
|
10037
|
-
return "Messages-to-Chat";
|
|
10609
|
+
return type === "anthropic" || type === "openai-compatible" || type === "google";
|
|
10038
10610
|
}
|
|
10039
10611
|
function createProviderCodexCandidate(providerConfig, modelId, remoteModel, effectiveType) {
|
|
10040
10612
|
const metadata = getModelMetadata(providerConfig.name, modelId, remoteModel ?? {}, providerConfig);
|
|
10041
10613
|
const reasoningEfforts = normalizeReasoningEfforts(metadata.reasoningEfforts);
|
|
10042
10614
|
const displayName = getStringField(remoteModel ?? {}, "display_name") ?? getStringField(remoteModel ?? {}, "name") ?? modelId;
|
|
10043
|
-
const adapterName = describeProviderAdapter(effectiveType);
|
|
10044
10615
|
const requiresCatalogMatch = effectiveType === "openai-responses" && modelId.startsWith("gpt");
|
|
10045
10616
|
return {
|
|
10046
10617
|
slug: `${providerConfig.name}/${modelId}`,
|
|
@@ -10048,7 +10619,7 @@ function createProviderCodexCandidate(providerConfig, modelId, remoteModel, effe
|
|
|
10048
10619
|
catalogMatchRequired: requiresCatalogMatch,
|
|
10049
10620
|
providerName: providerConfig.name,
|
|
10050
10621
|
displayName: `${displayName} (${providerConfig.name})`,
|
|
10051
|
-
description:
|
|
10622
|
+
description: displayName,
|
|
10052
10623
|
contextWindow: metadata.contextWindow ?? 256e3,
|
|
10053
10624
|
maxOutputTokens: metadata.maxOutputTokens ?? 32e3,
|
|
10054
10625
|
inputModalities: normalizeInputModalities(metadata.inputModalities),
|
|
@@ -13149,7 +13720,7 @@ async function handleProviderResponsesForProvider(c, options) {
|
|
|
13149
13720
|
return createProviderProxyResponse(upstreamResponse);
|
|
13150
13721
|
}
|
|
13151
13722
|
const shouldFallbackToMessages$1 = (c, modelId, effectiveType) => {
|
|
13152
|
-
if (effectiveType === "anthropic" || effectiveType === "openai-compatible") return true;
|
|
13723
|
+
if (effectiveType === "anthropic" || effectiveType === "openai-compatible" || effectiveType === "google") return true;
|
|
13153
13724
|
if (isCodexUserAgent(c.req.header("user-agent"))) return !(modelId.startsWith("gpt") || modelId.startsWith("codex"));
|
|
13154
13725
|
return false;
|
|
13155
13726
|
};
|
|
@@ -13633,4 +14204,4 @@ createServer();
|
|
|
13633
14204
|
//#endregion
|
|
13634
14205
|
export { createServer };
|
|
13635
14206
|
|
|
13636
|
-
//# sourceMappingURL=server-
|
|
14207
|
+
//# sourceMappingURL=server-D8LzQcmu.js.map
|