@nick3/copilot-api 1.10.8 → 1.10.29
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 +141 -46
- package/README.zh-CN.md +141 -46
- package/dist/{account-COtMmvzU.js → account-DpW8RaT6.js} +3 -3
- package/dist/{account-COtMmvzU.js.map → account-DpW8RaT6.js.map} +1 -1
- package/dist/admin/AGENTS.md +19 -0
- package/dist/auth-nO-eHeO_.js +327 -0
- package/dist/auth-nO-eHeO_.js.map +1 -0
- package/dist/{check-usage-DdevqHE5.js → check-usage-ZifYvA3w.js} +4 -42
- package/dist/check-usage-ZifYvA3w.js.map +1 -0
- package/dist/config-CmhIPHn_.js +578 -0
- package/dist/config-CmhIPHn_.js.map +1 -0
- package/dist/{debug-BMo6ltbp.js → debug-DvpksqEL.js} +18 -7
- package/dist/debug-DvpksqEL.js.map +1 -0
- package/dist/main.js +5 -10
- package/dist/main.js.map +1 -1
- package/dist/mcp-http-BhELuvog.js +2 -0
- package/dist/mcp-http-DI4Vz01p.js +82 -0
- package/dist/mcp-http-DI4Vz01p.js.map +1 -0
- package/dist/mcp-http-config-DMdUDz1D.js +39 -0
- package/dist/mcp-http-config-DMdUDz1D.js.map +1 -0
- package/dist/mcp-pLTPS0tO.js +79 -0
- package/dist/mcp-pLTPS0tO.js.map +1 -0
- package/dist/{tool-search-BrN7M0Dd.js → mcp-server-DEqHrXFq.js} +25 -2
- package/dist/mcp-server-DEqHrXFq.js.map +1 -0
- package/dist/{paths-CclKwouX.js → paths-Bpsb62LK.js} +3 -1
- package/dist/paths-Bpsb62LK.js.map +1 -0
- package/dist/{poll-access-token-BAgM2-7k.js → poll-access-token-GzVkiTH8.js} +71 -4
- package/dist/poll-access-token-GzVkiTH8.js.map +1 -0
- package/dist/{request-outbound-BJjWS_jF.js → request-outbound-BkEA8Wgb.js} +1 -1
- package/dist/{request-outbound-Pu1kp2x8.js → request-outbound-DZTxxtcx.js} +3 -3
- package/dist/{request-outbound-Pu1kp2x8.js.map → request-outbound-DZTxxtcx.js.map} +1 -1
- package/dist/{proxy-_U-hgwIn.js → responses-bridge-registry-BJ5Sbh6-.js} +116 -577
- package/dist/responses-bridge-registry-BJ5Sbh6-.js.map +1 -0
- package/dist/{server-DulP9mYd.js → server-DJ3_UGc4.js} +339 -168
- package/dist/server-DJ3_UGc4.js.map +1 -0
- package/dist/start-DaB0AcjZ.js +526 -0
- package/dist/start-DaB0AcjZ.js.map +1 -0
- package/dist/token-DrFDLVxa.js +365 -0
- package/dist/token-DrFDLVxa.js.map +1 -0
- package/package.json +1 -1
- package/dist/auth-B0y-2njL.js +0 -226
- package/dist/auth-B0y-2njL.js.map +0 -1
- package/dist/check-usage-DdevqHE5.js.map +0 -1
- package/dist/debug-BMo6ltbp.js.map +0 -1
- package/dist/get-copilot-token-8Rm-rVsp.js +0 -17
- package/dist/get-copilot-token-8Rm-rVsp.js.map +0 -1
- package/dist/mcp-9Hgepkc5.js +0 -37
- package/dist/mcp-9Hgepkc5.js.map +0 -1
- package/dist/paths-CclKwouX.js.map +0 -1
- package/dist/poll-access-token-BAgM2-7k.js.map +0 -1
- package/dist/proxy-_U-hgwIn.js.map +0 -1
- package/dist/server-DulP9mYd.js.map +0 -1
- package/dist/start-CtEoE2gt.js +0 -274
- package/dist/start-CtEoE2gt.js.map +0 -1
- package/dist/tool-search-BrN7M0Dd.js.map +0 -1
|
@@ -1,109 +1,26 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import { a as getAccountClientIdentityByLoginAndApp, b as getCurrentIdentityEnvironment, d as loadRegistry, g as saveRegistry, h as saveAccountToken, l as listAccountsFromRegistry, m as removeAccountToken, p as removeAccountFromRegistry, r as addAccountToRegistry, t as isAccountType } from "./account-
|
|
3
|
-
import { r as ensurePaths, t as PATHS } from "./paths-
|
|
4
|
-
import { i as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { A as accountFromState, B as compactSystemPromptStarts, C as copilotHeaders, D as prepareForCompact, E as normalizeDomain, F as resolveTraceId, L as compactAutoContinuePromptStarts, M as captureOutboundHeadersSnapshot, O as prepareInteractionHeaders, P as requestContext, R as compactMessageSections, S as copilotBaseUrl, T as copilotWebSocketHeaders, b as HTTPError, c as getUUID, d as parseUserIdMetadata, f as resolveAffinityKey, g as getCopilotUsage, h as getDeviceCode, j as state, k as prepareMessageProxyHeaders, l as isNullish, m as getGitHubUser, o as generateRequestIdFromPayload, p as sleep, s as getRootSessionId, t as pollAccessToken, u as normalizeStableSessionId, v as getProxyEnvDispatcher, x as forwardError } from "./poll-access-token-GzVkiTH8.js";
|
|
2
|
+
import { a as getAccountClientIdentityByLoginAndApp, b as getCurrentIdentityEnvironment, d as loadRegistry, g as saveRegistry, h as saveAccountToken, l as listAccountsFromRegistry, m as removeAccountToken, p as removeAccountFromRegistry, r as addAccountToRegistry, t as isAccountType } from "./account-DpW8RaT6.js";
|
|
3
|
+
import { r as ensurePaths, t as PATHS } from "./paths-Bpsb62LK.js";
|
|
4
|
+
import { C as isResponsesApiWebSocketEnabled, E as resolveModelAlias, O as shouldCompactUseSmallModel, S as isResponsesApiWebSearchEnabled, T as mergeConfigWithDefaults, _ as isAccountAffinityEnabled, a as getConfig, b as isMessagesApiEnabled, c as getModelAliases, d as getProviderConfig, g as getSmallModel, i as getClaudeTokenMultiplier, l as getModelAliasesInfo, m as getReasoningEffortForModel, n as getAliasTargetSet, o as getExtraPromptForModel, r as getAnthropicApiKey, s as getLogLevel, t as PROVIDER_TYPE_ANTHROPIC, u as getModelRefreshIntervalMs, v as isForceAgentEnabled, x as isResponsesApiContextManagementEnabled, y as isMessageStartInputTokensFallbackEnabled } from "./config-CmhIPHn_.js";
|
|
5
|
+
import { i as getRequestOutboundStore, r as getRedactedHeaderKeys } from "./request-outbound-DZTxxtcx.js";
|
|
6
|
+
import { i as isMcpHttpEnabledFromEnv, n as DEFAULT_MCP_HTTP_PATH } from "./mcp-http-config-DMdUDz1D.js";
|
|
7
|
+
import { a as isDeferredToolName, c as parseMcpToolSearchSentinel, i as isBridgeToolSearchName, l as selectDeferredToolsByNames, n as BRIDGE_TOOL_SEARCH_NAME, o as listDeferredToolNames, r as formatToolSearchBridgeArguments, s as normalizeToolSearchBridgeArguments, u as shouldEnableResponsesToolSearch } from "./mcp-server-DEqHrXFq.js";
|
|
8
|
+
import { n as handleStreamableHttpMcpRequest, r as mcpHttpCorsOptions } from "./mcp-http-DI4Vz01p.js";
|
|
9
|
+
import { S as createAuthMiddleware, _ as normalizeMessagesUsage, b as flushPendingCapture, c as accountsManager, d as extractResponsesUsageFromStreamEvent, f as getClientIpInfo, g as normalizeEmbeddingsUsage, h as normalizeChatCompletionsUsage, l as applySharedSessionAffinityRetention, m as getStatsStore, p as getRequestHistoryStore, s as updateQuotaRefreshSchedulerFromConfig, t as closeResponsesBridge, u as extractResponsesUsageFromResult, v as toLocalDateString, x as isDevModeEnabled, y as copilotFetch } from "./responses-bridge-registry-BJ5Sbh6-.js";
|
|
7
10
|
import consola from "consola";
|
|
8
11
|
import fs, { readFile } from "node:fs/promises";
|
|
9
|
-
import { createHash, randomUUID
|
|
12
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
10
13
|
import * as path$1 from "node:path";
|
|
11
14
|
import path from "node:path";
|
|
12
|
-
import {
|
|
15
|
+
import { events } from "fetch-event-stream";
|
|
13
16
|
import fs$1, { existsSync } from "node:fs";
|
|
17
|
+
import { WebSocket } from "undici";
|
|
18
|
+
import { fileURLToPath } from "node:url";
|
|
14
19
|
import { Hono } from "hono";
|
|
15
20
|
import { cors } from "hono/cors";
|
|
16
21
|
import { logger } from "hono/logger";
|
|
17
22
|
import { streamSSE } from "hono/streaming";
|
|
18
|
-
import { events } from "fetch-event-stream";
|
|
19
23
|
import util from "node:util";
|
|
20
|
-
import { WebSocket } from "undici";
|
|
21
|
-
//#region src/lib/request-auth.ts
|
|
22
|
-
const LEGACY_API_KEY_ENV_VAR = "COPILOT_API_KEY";
|
|
23
|
-
let warnedLegacyEnvFallback = false;
|
|
24
|
-
let warnedLegacyConfigFallback = false;
|
|
25
|
-
function normalizeApiKeys(apiKeys) {
|
|
26
|
-
if (!Array.isArray(apiKeys)) {
|
|
27
|
-
if (apiKeys !== void 0) consola.warn("Invalid auth.apiKeys config. Expected an array of strings.");
|
|
28
|
-
return [];
|
|
29
|
-
}
|
|
30
|
-
const normalizedKeys = apiKeys.filter((key) => typeof key === "string").map((key) => key.trim()).filter((key) => key.length > 0);
|
|
31
|
-
if (normalizedKeys.length !== apiKeys.length) consola.warn("Invalid auth.apiKeys entries found. Only non-empty strings are allowed.");
|
|
32
|
-
return [...new Set(normalizedKeys)];
|
|
33
|
-
}
|
|
34
|
-
function getConfiguredApiKeys() {
|
|
35
|
-
const config = getConfig();
|
|
36
|
-
const configuredApiKeys = normalizeApiKeys(config.auth?.apiKeys);
|
|
37
|
-
if (configuredApiKeys.length > 0) return configuredApiKeys;
|
|
38
|
-
const envApiKey = process.env[LEGACY_API_KEY_ENV_VAR]?.trim();
|
|
39
|
-
if (envApiKey) {
|
|
40
|
-
if (!warnedLegacyEnvFallback) {
|
|
41
|
-
warnedLegacyEnvFallback = true;
|
|
42
|
-
consola.warn(`Using legacy ${LEGACY_API_KEY_ENV_VAR}. Please migrate to config.auth.apiKeys.`);
|
|
43
|
-
}
|
|
44
|
-
return [envApiKey];
|
|
45
|
-
}
|
|
46
|
-
const legacyConfigApiKey = config.apiKey?.trim();
|
|
47
|
-
if (legacyConfigApiKey) {
|
|
48
|
-
if (!warnedLegacyConfigFallback) {
|
|
49
|
-
warnedLegacyConfigFallback = true;
|
|
50
|
-
consola.warn("Using deprecated config.apiKey. Please migrate to config.auth.apiKeys.");
|
|
51
|
-
}
|
|
52
|
-
return [legacyConfigApiKey];
|
|
53
|
-
}
|
|
54
|
-
return configuredApiKeys;
|
|
55
|
-
}
|
|
56
|
-
function extractRequestApiKey(c) {
|
|
57
|
-
const xApiKey = c.req.header("x-api-key")?.trim();
|
|
58
|
-
if (xApiKey) return xApiKey;
|
|
59
|
-
const authorization = c.req.header("authorization");
|
|
60
|
-
if (!authorization) return null;
|
|
61
|
-
const [scheme, ...rest] = authorization.trim().split(/\s+/);
|
|
62
|
-
if (scheme.toLowerCase() !== "bearer") return null;
|
|
63
|
-
return rest.join(" ").trim() || null;
|
|
64
|
-
}
|
|
65
|
-
function createUnauthorizedResponse(c) {
|
|
66
|
-
c.header("WWW-Authenticate", "Bearer realm=\"copilot-api\"");
|
|
67
|
-
return c.json({ error: {
|
|
68
|
-
message: "Unauthorized. Provide Authorization: Bearer <key> or x-api-key.",
|
|
69
|
-
type: "unauthorized"
|
|
70
|
-
} }, 401);
|
|
71
|
-
}
|
|
72
|
-
function normalizePathname(pathname) {
|
|
73
|
-
if (pathname.length > 1 && pathname.endsWith("/")) return pathname.slice(0, -1);
|
|
74
|
-
return pathname;
|
|
75
|
-
}
|
|
76
|
-
function hasPrefixBoundary(pathname, prefix) {
|
|
77
|
-
return pathname === prefix || pathname.startsWith(`${prefix}/`);
|
|
78
|
-
}
|
|
79
|
-
function timingSafeKeyCompare(a, b) {
|
|
80
|
-
try {
|
|
81
|
-
const aBuf = Buffer.from(a);
|
|
82
|
-
const bBuf = Buffer.from(b);
|
|
83
|
-
if (aBuf.length !== bBuf.length) return false;
|
|
84
|
-
return timingSafeEqual(aBuf, bBuf);
|
|
85
|
-
} catch {
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
function createAuthMiddleware(options = {}) {
|
|
90
|
-
const getApiKeys = options.getApiKeys ?? getConfiguredApiKeys;
|
|
91
|
-
const allowUnauthenticatedPaths = new Set((options.allowUnauthenticatedPaths ?? ["/"]).map((path) => normalizePathname(path)));
|
|
92
|
-
const allowUnauthenticatedPathPrefixes = (options.allowUnauthenticatedPathPrefixes ?? []).map((path) => normalizePathname(path));
|
|
93
|
-
const allowOptionsBypass = options.allowOptionsBypass ?? true;
|
|
94
|
-
return async (c, next) => {
|
|
95
|
-
if (allowOptionsBypass && c.req.method === "OPTIONS") return next();
|
|
96
|
-
const pathname = normalizePathname(new URL(c.req.url, "http://local").pathname);
|
|
97
|
-
if (allowUnauthenticatedPaths.has(pathname)) return next();
|
|
98
|
-
if (allowUnauthenticatedPathPrefixes.some((prefix) => hasPrefixBoundary(pathname, prefix))) return next();
|
|
99
|
-
const apiKeys = getApiKeys();
|
|
100
|
-
if (apiKeys.length === 0) return next();
|
|
101
|
-
const requestApiKey = extractRequestApiKey(c);
|
|
102
|
-
if (!(requestApiKey ? apiKeys.some((apiKey) => timingSafeKeyCompare(requestApiKey, apiKey)) : false)) return createUnauthorizedResponse(c);
|
|
103
|
-
return next();
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
//#endregion
|
|
107
24
|
//#region src/lib/trace.ts
|
|
108
25
|
const traceIdMiddleware = async (c, next) => {
|
|
109
26
|
const traceId = resolveTraceId(c.req.header("x-trace-id"));
|
|
@@ -112,7 +29,7 @@ const traceIdMiddleware = async (c, next) => {
|
|
|
112
29
|
traceId,
|
|
113
30
|
startTime: Date.now(),
|
|
114
31
|
userAgent: c.req.header("user-agent") || "",
|
|
115
|
-
sessionAffinity: c.req.header("x-session-affinity"),
|
|
32
|
+
sessionAffinity: c.req.header("x-session-affinity") ?? c.req.header("x-client-request-id"),
|
|
116
33
|
parentSessionId: c.req.header("x-parent-session-id")
|
|
117
34
|
};
|
|
118
35
|
await requestContext.run(context, async () => {
|
|
@@ -302,7 +219,7 @@ const findEndpointModel = (sdkModelId) => {
|
|
|
302
219
|
const models = getAvailableModels();
|
|
303
220
|
const exactMatch = models.find((m) => m.id === sdkModelId);
|
|
304
221
|
if (exactMatch) return exactMatch;
|
|
305
|
-
const normalized =
|
|
222
|
+
const normalized = normalizeSdkModelId(sdkModelId);
|
|
306
223
|
if (!normalized) return;
|
|
307
224
|
const modelName = `claude-${normalized.family}-${normalized.version}`;
|
|
308
225
|
return models.find((m) => m.id === modelName);
|
|
@@ -317,22 +234,22 @@ const findEndpointModel = (sdkModelId) => {
|
|
|
317
234
|
* - "claude-haiku-3-5-20250514" -> { family: "haiku", version: "3.5" }
|
|
318
235
|
* - "claude-haiku-4.5" -> { family: "haiku", version: "4.5" }
|
|
319
236
|
*/
|
|
320
|
-
const
|
|
237
|
+
const normalizeSdkModelId = (sdkModelId) => {
|
|
321
238
|
const withoutDate = sdkModelId.toLowerCase().replace(/-\d{8}$/, "");
|
|
322
|
-
const pattern1 = withoutDate.match(/^claude-(\w+)-(\d+)
|
|
239
|
+
const pattern1 = withoutDate.match(/^claude-(\w+)-(\d+)\.(\d+)$/);
|
|
323
240
|
if (pattern1) return {
|
|
324
241
|
family: pattern1[1],
|
|
325
242
|
version: `${pattern1[2]}.${pattern1[3]}`
|
|
326
243
|
};
|
|
327
|
-
const pattern2 = withoutDate.match(/^claude-(\
|
|
244
|
+
const pattern2 = withoutDate.match(/^claude-(\w+)-(\d+)-(\d+)$/);
|
|
328
245
|
if (pattern2) return {
|
|
329
|
-
family: pattern2[
|
|
330
|
-
version: `${pattern2[
|
|
246
|
+
family: pattern2[1],
|
|
247
|
+
version: `${pattern2[2]}.${pattern2[3]}`
|
|
331
248
|
};
|
|
332
|
-
const pattern3 = withoutDate.match(/^claude-(\
|
|
249
|
+
const pattern3 = withoutDate.match(/^claude-(\d+)-(\d+)-(\w+)$/);
|
|
333
250
|
if (pattern3) return {
|
|
334
|
-
family: pattern3[
|
|
335
|
-
version: `${pattern3[
|
|
251
|
+
family: pattern3[3],
|
|
252
|
+
version: `${pattern3[1]}.${pattern3[2]}`
|
|
336
253
|
};
|
|
337
254
|
const pattern4 = withoutDate.match(/^claude-(\w+)-(\d+)$/);
|
|
338
255
|
if (pattern4) return {
|
|
@@ -411,7 +328,7 @@ const logCopilotQuotaSnapshots = (snapshots) => {
|
|
|
411
328
|
const logCopilotRateLimitUsage = (usage) => {
|
|
412
329
|
const d = new Date(usage.resetAt);
|
|
413
330
|
const dateStr = Number.isNaN(d.getTime()) ? usage.resetAt : d.toLocaleString();
|
|
414
|
-
consola.
|
|
331
|
+
consola.log(`Copilot ${usage.type} quota remaining: ${usage.remaining}, resets at: ${dateStr}`);
|
|
415
332
|
};
|
|
416
333
|
const isCopilotQuotaSnapshot = (value) => {
|
|
417
334
|
if (!value || typeof value !== "object") return false;
|
|
@@ -693,10 +610,95 @@ const getTokenCount = async (payload, model) => {
|
|
|
693
610
|
output: outputTokens
|
|
694
611
|
};
|
|
695
612
|
};
|
|
613
|
+
const SYSTEM_REMINDER_START = "<system-reminder>";
|
|
614
|
+
const SYSTEM_REMINDER_END = "</system-reminder>";
|
|
615
|
+
const SUBAGENT_START_HOOK_ADDITIONAL_PREFIX = "SubagentStart hook additional";
|
|
696
616
|
const IDE_EXECUTE_CODE_TOOL = "mcp__ide__executeCode";
|
|
697
617
|
const IDE_GET_DIAGNOSTICS_TOOL = "mcp__ide__getDiagnostics";
|
|
698
618
|
const IDE_GET_DIAGNOSTICS_DESCRIPTION = "Get language diagnostics from VS Code. Returns errors, warnings, information, and hints for files in the workspace.";
|
|
699
619
|
const PDF_FILE_READ_PREFIX = "PDF file read:";
|
|
620
|
+
const createTextBlock = (text) => ({
|
|
621
|
+
type: "text",
|
|
622
|
+
text
|
|
623
|
+
});
|
|
624
|
+
const appendTextSegment = (base, addition) => {
|
|
625
|
+
if (base.length === 0) return addition;
|
|
626
|
+
if (addition.length === 0) return base;
|
|
627
|
+
return `${base}\n\n${addition}`;
|
|
628
|
+
};
|
|
629
|
+
const ensureSystemReminderText = (text) => {
|
|
630
|
+
if (text.startsWith(SYSTEM_REMINDER_START)) return text;
|
|
631
|
+
return `${SYSTEM_REMINDER_START}\n${text.trim()}\n${SYSTEM_REMINDER_END}`;
|
|
632
|
+
};
|
|
633
|
+
const normalizeSystemStringForMerge = (text) => {
|
|
634
|
+
if (!text.startsWith(SUBAGENT_START_HOOK_ADDITIONAL_PREFIX)) return ensureSystemReminderText(text);
|
|
635
|
+
const lineBreakMatch = /\r?\n/.exec(text);
|
|
636
|
+
if (!lineBreakMatch) return [createTextBlock(ensureSystemReminderText(text))];
|
|
637
|
+
const firstLine = text.slice(0, lineBreakMatch.index);
|
|
638
|
+
const rest = text.slice(lineBreakMatch.index + lineBreakMatch[0].length);
|
|
639
|
+
return [createTextBlock(ensureSystemReminderText(firstLine)), ...rest.length > 0 ? [createTextBlock(ensureSystemReminderText(rest))] : []];
|
|
640
|
+
};
|
|
641
|
+
const normalizeSystemContentForMerge = (content) => {
|
|
642
|
+
if (typeof content === "string") return normalizeSystemStringForMerge(content);
|
|
643
|
+
return content.map((block) => block.text.startsWith(SYSTEM_REMINDER_START) ? block : {
|
|
644
|
+
...block,
|
|
645
|
+
text: ensureSystemReminderText(block.text)
|
|
646
|
+
});
|
|
647
|
+
};
|
|
648
|
+
const toSystemTextBlocks = (content) => {
|
|
649
|
+
return typeof content === "string" ? [createTextBlock(content)] : [...content];
|
|
650
|
+
};
|
|
651
|
+
const mergeSystemPromptContent = (current, addition) => {
|
|
652
|
+
if (current === void 0) return typeof addition === "string" ? addition : [...addition];
|
|
653
|
+
if (typeof current === "string" && typeof addition === "string") return appendTextSegment(current, addition);
|
|
654
|
+
return [...toSystemTextBlocks(current), ...toSystemTextBlocks(addition)];
|
|
655
|
+
};
|
|
656
|
+
const prependSystemContentToUserMessage = (message, addition) => {
|
|
657
|
+
if (typeof message.content === "string" && typeof addition === "string") {
|
|
658
|
+
message.content = appendTextSegment(addition, message.content);
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
if (Array.isArray(message.content)) {
|
|
662
|
+
const lastToolResultIndex = message.content.findLastIndex((block) => block.type === "tool_result");
|
|
663
|
+
if (lastToolResultIndex >= 0) {
|
|
664
|
+
message.content = [
|
|
665
|
+
...message.content.slice(0, lastToolResultIndex + 1),
|
|
666
|
+
...toSystemTextBlocks(addition),
|
|
667
|
+
...message.content.slice(lastToolResultIndex + 1)
|
|
668
|
+
];
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
message.content = [...toSystemTextBlocks(addition), ...typeof message.content === "string" ? [createTextBlock(message.content)] : message.content];
|
|
673
|
+
};
|
|
674
|
+
const normalizeSystemMessages = (payload) => {
|
|
675
|
+
if (!Array.isArray(payload.messages) || !payload.messages.some((msg) => msg.role === "system")) return;
|
|
676
|
+
const normalizedMessages = [];
|
|
677
|
+
let system = payload.system;
|
|
678
|
+
for (const message of payload.messages) {
|
|
679
|
+
if (message.role === "system") {
|
|
680
|
+
const normalizedContent = normalizeSystemContentForMerge(message.content);
|
|
681
|
+
const previousMessage = normalizedMessages.at(-1);
|
|
682
|
+
if (previousMessage?.role === "user") prependSystemContentToUserMessage(previousMessage, normalizedContent);
|
|
683
|
+
else if (!previousMessage) system = mergeSystemPromptContent(system, normalizedContent);
|
|
684
|
+
continue;
|
|
685
|
+
}
|
|
686
|
+
normalizedMessages.push(message);
|
|
687
|
+
}
|
|
688
|
+
payload.messages = normalizedMessages;
|
|
689
|
+
payload.system = system;
|
|
690
|
+
};
|
|
691
|
+
const isVersionAtLeast = (version, minimumMajor, minimumMinor) => {
|
|
692
|
+
const [majorPart, minorPart = "0"] = version.split(".");
|
|
693
|
+
const major = Number.parseInt(majorPart, 10);
|
|
694
|
+
const minor = Number.parseInt(minorPart, 10);
|
|
695
|
+
if (!Number.isInteger(major) || !Number.isInteger(minor)) return false;
|
|
696
|
+
return major > minimumMajor || major === minimumMajor && minor >= minimumMinor;
|
|
697
|
+
};
|
|
698
|
+
const shouldSummarizeThinkingDisplayForModel = (model) => {
|
|
699
|
+
const normalized = normalizeSdkModelId(model);
|
|
700
|
+
return Boolean(normalized && isVersionAtLeast(normalized.version, 4, 7));
|
|
701
|
+
};
|
|
700
702
|
const getBlockCacheControl = (block) => {
|
|
701
703
|
if (!block || block.type === "thinking") return;
|
|
702
704
|
const cacheControl = block.cache_control;
|
|
@@ -966,7 +968,7 @@ const prepareMessagesApiPayload = (payload, selectedModel) => {
|
|
|
966
968
|
if (selectedModel?.capabilities.supports.adaptive_thinking && !disableThink) {
|
|
967
969
|
payload.thinking = { type: "adaptive" };
|
|
968
970
|
if (!hasThinking) payload.thinking.display = "summarized";
|
|
969
|
-
if (payload.model
|
|
971
|
+
if (shouldSummarizeThinkingDisplayForModel(payload.model)) payload.thinking.display = "summarized";
|
|
970
972
|
let effort = getReasoningEffortForModel(payload.model);
|
|
971
973
|
if (effort === "none" || effort === "minimal") effort = "low";
|
|
972
974
|
const reasoningEffort = selectedModel.capabilities.supports.reasoning_effort;
|
|
@@ -1884,7 +1886,11 @@ const PROVIDER_CONFIG_FIELDS = [
|
|
|
1884
1886
|
"models",
|
|
1885
1887
|
"adjustInputTokens"
|
|
1886
1888
|
];
|
|
1887
|
-
const PROVIDER_AUTH_TYPES = [
|
|
1889
|
+
const PROVIDER_AUTH_TYPES = [
|
|
1890
|
+
"authorization",
|
|
1891
|
+
"oauth2",
|
|
1892
|
+
"x-api-key"
|
|
1893
|
+
];
|
|
1888
1894
|
const PROVIDER_CONFIG_KEYS = new Set(PROVIDER_CONFIG_FIELDS);
|
|
1889
1895
|
function isProviderAuthType(value) {
|
|
1890
1896
|
return PROVIDER_AUTH_TYPES.includes(value);
|
|
@@ -4548,6 +4554,7 @@ async function handleProviderCountTokens(c) {
|
|
|
4548
4554
|
}
|
|
4549
4555
|
async function handleProviderCountTokensForProvider(c, options) {
|
|
4550
4556
|
const { payload: anthropicPayload, provider } = options;
|
|
4557
|
+
normalizeSystemMessages(anthropicPayload);
|
|
4551
4558
|
const providerConfig = resolveProviderConfig$2(c, provider);
|
|
4552
4559
|
if (!providerConfig) return c.json({ error: {
|
|
4553
4560
|
message: `Provider '${provider}' not found or disabled`,
|
|
@@ -4559,7 +4566,7 @@ async function handleProviderCountTokensForProvider(c, options) {
|
|
|
4559
4566
|
} }, 400);
|
|
4560
4567
|
const modelId = anthropicPayload.model.trim();
|
|
4561
4568
|
const modelConfig = providerConfig.models?.[modelId];
|
|
4562
|
-
const translationOptions = providerConfig.type === "openai-compatible" ? {
|
|
4569
|
+
const translationOptions = providerConfig.type === "openai-compatible" || providerConfig.type === "openai-responses" ? {
|
|
4563
4570
|
supportPdf: modelConfig?.supportPdf,
|
|
4564
4571
|
toolContentSupportType: modelConfig?.toolContentSupportType ?? []
|
|
4565
4572
|
} : void 0;
|
|
@@ -4639,6 +4646,7 @@ async function countTokensViaAnthropic(c, payload) {
|
|
|
4639
4646
|
async function handleCountTokens(c) {
|
|
4640
4647
|
const anthropicPayload = await c.req.json();
|
|
4641
4648
|
anthropicPayload.model = resolveModelAlias(anthropicPayload.model);
|
|
4649
|
+
normalizeSystemMessages(anthropicPayload);
|
|
4642
4650
|
const providerModelAlias = resolveExistingProviderModelAlias(anthropicPayload.model, getProviderConfigResolver$1(c));
|
|
4643
4651
|
if (providerModelAlias) {
|
|
4644
4652
|
anthropicPayload.model = providerModelAlias.model;
|
|
@@ -4676,7 +4684,7 @@ async function handleCountTokens(c) {
|
|
|
4676
4684
|
//#endregion
|
|
4677
4685
|
//#region src/services/copilot/create-responses.ts
|
|
4678
4686
|
const RESPONSES_WEBSOCKET_IDLE_TIMEOUT_MS = 6e4;
|
|
4679
|
-
const createResponses = async (payload, { vision, initiator, upstreamRequestId, subagentMarker, sessionId, compactType, requestId, fetchImpl, transport = "http" }, account) => {
|
|
4687
|
+
const createResponses = async (payload, { vision, initiator, upstreamRequestId, subagentMarker, sessionId, compactType, requestId, fetchImpl, transport = "http", bridgeId }, account) => {
|
|
4680
4688
|
const ctx = account ?? accountFromState();
|
|
4681
4689
|
if (!ctx.copilotToken) throw new Error("Copilot token not found");
|
|
4682
4690
|
const effectiveInitiator = resolveEffectiveInitiator(initiator, {
|
|
@@ -4696,7 +4704,9 @@ const createResponses = async (payload, { vision, initiator, upstreamRequestId,
|
|
|
4696
4704
|
const stream = createPooledResponsesWebSocketStream(prepareResponsesWebSocketRequest(payload, headers, {
|
|
4697
4705
|
copilotToken: ctx.copilotToken,
|
|
4698
4706
|
requestId: requestId ?? upstreamRequestId ?? "missing-request-id",
|
|
4699
|
-
|
|
4707
|
+
sessionId,
|
|
4708
|
+
subagentMarker,
|
|
4709
|
+
bridgeId
|
|
4700
4710
|
}), copilotBaseUrl(ctx));
|
|
4701
4711
|
if (payload.stream) return stream;
|
|
4702
4712
|
return await consumeResponsesWebSocketStream(stream);
|
|
@@ -4729,20 +4739,22 @@ const prepareResponsesWebSocketRequest = (payload, preparedHeaders, options) =>
|
|
|
4729
4739
|
return {
|
|
4730
4740
|
headers: copilotWebSocketHeaders(preparedHeaders),
|
|
4731
4741
|
poolKey: buildResponsesWebSocketPoolKey(payload, options),
|
|
4732
|
-
payload: buildResponsesWebSocketPayload(payload, initiator)
|
|
4742
|
+
payload: buildResponsesWebSocketPayload(payload, initiator),
|
|
4743
|
+
bridgeId: options.bridgeId
|
|
4733
4744
|
};
|
|
4734
4745
|
};
|
|
4735
|
-
const buildResponsesWebSocketPoolKey = (payload, { copilotToken, requestId, subagentMarker }) => {
|
|
4746
|
+
const buildResponsesWebSocketPoolKey = (payload, { copilotToken, requestId, sessionId, subagentMarker }) => {
|
|
4736
4747
|
const tokenFingerprint = copilotToken ? createHash("sha256").update(copilotToken).digest("hex").slice(0, 16) : "missing-token";
|
|
4737
4748
|
const subagentKey = subagentMarker ? [
|
|
4738
4749
|
subagentMarker.session_id,
|
|
4739
4750
|
subagentMarker.agent_id,
|
|
4740
4751
|
subagentMarker.agent_type
|
|
4741
4752
|
].join(":") : "main";
|
|
4753
|
+
const connectionAffinityKey = sessionId ?? requestId;
|
|
4742
4754
|
return [
|
|
4743
4755
|
tokenFingerprint,
|
|
4744
4756
|
payload.model,
|
|
4745
|
-
|
|
4757
|
+
connectionAffinityKey,
|
|
4746
4758
|
subagentKey
|
|
4747
4759
|
].map(encodePoolKeyPart).join("|");
|
|
4748
4760
|
};
|
|
@@ -4797,6 +4809,7 @@ const getResponsesWebSocketRequestTarget = (request, baseUrl) => {
|
|
|
4797
4809
|
const existing = responsesWebSocketPool.get(request.poolKey);
|
|
4798
4810
|
if (existing && !existing.closed) {
|
|
4799
4811
|
clearResponsesWebSocketIdleTimer(existing);
|
|
4812
|
+
existing.bridgeId = request.bridgeId;
|
|
4800
4813
|
return {
|
|
4801
4814
|
entry: existing,
|
|
4802
4815
|
pooled: true
|
|
@@ -4817,13 +4830,16 @@ const createResponsesWebSocketEntry = (request, baseUrl) => {
|
|
|
4817
4830
|
websocketPromise: openResponsesWebSocket({
|
|
4818
4831
|
headers: request.headers,
|
|
4819
4832
|
url: buildResponsesWebSocketUrl(baseUrl)
|
|
4820
|
-
})
|
|
4833
|
+
}),
|
|
4834
|
+
bridgeId: request.bridgeId
|
|
4821
4835
|
};
|
|
4822
4836
|
entry.websocketPromise.then((websocket) => {
|
|
4823
4837
|
websocket.addEventListener("close", () => {
|
|
4838
|
+
maybeCloseResponsesBridgeForReapedEntry(request.poolKey, entry);
|
|
4824
4839
|
removeResponsesWebSocketPoolEntry(request.poolKey, entry);
|
|
4825
4840
|
});
|
|
4826
4841
|
websocket.addEventListener("error", () => {
|
|
4842
|
+
maybeCloseResponsesBridgeForReapedEntry(request.poolKey, entry);
|
|
4827
4843
|
removeResponsesWebSocketPoolEntry(request.poolKey, entry);
|
|
4828
4844
|
});
|
|
4829
4845
|
}).catch(() => {
|
|
@@ -4831,6 +4847,10 @@ const createResponsesWebSocketEntry = (request, baseUrl) => {
|
|
|
4831
4847
|
});
|
|
4832
4848
|
return entry;
|
|
4833
4849
|
};
|
|
4850
|
+
const maybeCloseResponsesBridgeForReapedEntry = (poolKey, entry) => {
|
|
4851
|
+
if (entry.bridgeId === void 0 || entry.requestCount > 0 || responsesWebSocketPool.get(poolKey) !== entry) return;
|
|
4852
|
+
closeResponsesBridge(entry.bridgeId);
|
|
4853
|
+
};
|
|
4834
4854
|
const acquireResponsesWebSocketEntry = (poolKey, entry, pooled) => {
|
|
4835
4855
|
clearResponsesWebSocketIdleTimer(entry);
|
|
4836
4856
|
incrementResponsesWebSocketActiveRequestCount(poolKey);
|
|
@@ -4862,6 +4882,7 @@ const getReadyResponsesWebSocket = async (poolKey, entry, pooled) => {
|
|
|
4862
4882
|
const scheduleResponsesWebSocketIdleClose = (poolKey, entry) => {
|
|
4863
4883
|
clearResponsesWebSocketIdleTimer(entry);
|
|
4864
4884
|
entry.idleTimer = setTimeout(() => {
|
|
4885
|
+
maybeCloseResponsesBridgeForReapedEntry(poolKey, entry);
|
|
4865
4886
|
removeResponsesWebSocketPoolEntry(poolKey, entry);
|
|
4866
4887
|
}, RESPONSES_WEBSOCKET_IDLE_TIMEOUT_MS);
|
|
4867
4888
|
unrefTimer(entry.idleTimer);
|
|
@@ -5408,7 +5429,7 @@ const translateResponsesResultToAnthropic = (response, options) => {
|
|
|
5408
5429
|
const usage = mapResponsesUsage(response);
|
|
5409
5430
|
let anthropicContent = fallbackContentBlocks(response.output_text);
|
|
5410
5431
|
if (contentBlocks.length > 0) anthropicContent = contentBlocks;
|
|
5411
|
-
const stopReason = mapResponsesStopReason(response);
|
|
5432
|
+
const stopReason = mapResponsesStopReason(response, options);
|
|
5412
5433
|
return {
|
|
5413
5434
|
id: response.id,
|
|
5414
5435
|
type: "message",
|
|
@@ -5422,6 +5443,7 @@ const translateResponsesResultToAnthropic = (response, options) => {
|
|
|
5422
5443
|
};
|
|
5423
5444
|
const mapOutputToAnthropicContent = (output, options) => {
|
|
5424
5445
|
const contentBlocks = [];
|
|
5446
|
+
if (!output) output = [];
|
|
5425
5447
|
for (const item of output) switch (item.type) {
|
|
5426
5448
|
case "reasoning": {
|
|
5427
5449
|
const thinkingText = extractReasoningText(item);
|
|
@@ -5562,9 +5584,10 @@ const fallbackContentBlocks = (outputText) => {
|
|
|
5562
5584
|
text: outputText
|
|
5563
5585
|
}];
|
|
5564
5586
|
};
|
|
5565
|
-
const mapResponsesStopReason = (response) => {
|
|
5587
|
+
const mapResponsesStopReason = (response, options) => {
|
|
5566
5588
|
const { status, incomplete_details: incompleteDetails } = response;
|
|
5567
5589
|
if (status === "completed") {
|
|
5590
|
+
if (!response.output || response.output.length === 0) return options?.hasToolCall ? "tool_use" : "end_turn";
|
|
5568
5591
|
if (response.output.some((item) => item.type === "function_call" || item.type === "tool_search_call")) return "tool_use";
|
|
5569
5592
|
return "end_turn";
|
|
5570
5593
|
}
|
|
@@ -5992,7 +6015,7 @@ function closeThinkingBlockIfOpen(state, events) {
|
|
|
5992
6015
|
}
|
|
5993
6016
|
}
|
|
5994
6017
|
//#endregion
|
|
5995
|
-
//#region src/services/providers/
|
|
6018
|
+
//#region src/services/providers/provider-proxy.ts
|
|
5996
6019
|
const SHARED_FORWARDABLE_HEADERS = ["accept", "user-agent"];
|
|
5997
6020
|
const ANTHROPIC_FORWARDABLE_HEADERS = ["anthropic-version", "anthropic-beta"];
|
|
5998
6021
|
const STRIPPED_RESPONSE_HEADERS = [
|
|
@@ -6009,8 +6032,8 @@ const STRIPPED_RESPONSE_HEADERS = [
|
|
|
6009
6032
|
];
|
|
6010
6033
|
function buildProviderUpstreamHeaders(providerConfig, requestHeaders) {
|
|
6011
6034
|
const authHeaders = {};
|
|
6012
|
-
if (providerConfig.authType === "
|
|
6013
|
-
else authHeaders
|
|
6035
|
+
if (providerConfig.authType === "x-api-key") authHeaders["x-api-key"] = providerConfig.apiKey;
|
|
6036
|
+
else authHeaders.authorization = `Bearer ${providerConfig.apiKey}`;
|
|
6014
6037
|
const headers = {
|
|
6015
6038
|
"content-type": "application/json",
|
|
6016
6039
|
accept: "application/json",
|
|
@@ -6027,10 +6050,10 @@ function buildProviderUpstreamHeaders(providerConfig, requestHeaders) {
|
|
|
6027
6050
|
}
|
|
6028
6051
|
return headers;
|
|
6029
6052
|
}
|
|
6030
|
-
function createProviderProxyResponse(upstreamResponse) {
|
|
6053
|
+
function createProviderProxyResponse(upstreamResponse, body) {
|
|
6031
6054
|
const headers = new Headers(upstreamResponse.headers);
|
|
6032
6055
|
for (const headerName of STRIPPED_RESPONSE_HEADERS) headers.delete(headerName);
|
|
6033
|
-
return new Response(upstreamResponse.body, {
|
|
6056
|
+
return new Response(body ?? upstreamResponse.body, {
|
|
6034
6057
|
headers,
|
|
6035
6058
|
status: upstreamResponse.status,
|
|
6036
6059
|
statusText: upstreamResponse.statusText
|
|
@@ -6162,6 +6185,25 @@ const applyModelDefaults = (payload, modelConfig) => {
|
|
|
6162
6185
|
const applyMissingExtraBody = (payload, options) => {
|
|
6163
6186
|
for (const [key, value] of Object.entries(options.extraBody ?? {})) if (!Object.hasOwn(payload, key)) payload[key] = value;
|
|
6164
6187
|
};
|
|
6188
|
+
const getRequestThinkingBudget = (payload) => {
|
|
6189
|
+
const budget = payload.thinking?.budget_tokens;
|
|
6190
|
+
if (typeof budget !== "number" || !Number.isFinite(budget)) return;
|
|
6191
|
+
return budget;
|
|
6192
|
+
};
|
|
6193
|
+
const applyOpenAICompatibleThinkingBudget = (payload, source) => {
|
|
6194
|
+
const thinkingBudget = getRequestThinkingBudget(source);
|
|
6195
|
+
if (thinkingBudget !== void 0) {
|
|
6196
|
+
payload.thinking_budget = thinkingBudget;
|
|
6197
|
+
return;
|
|
6198
|
+
}
|
|
6199
|
+
if (payload.thinking_budget === void 0) delete payload.thinking_budget;
|
|
6200
|
+
};
|
|
6201
|
+
const applyOpenAICompatibleExtraBodyThinkingBudget = (payload, options) => {
|
|
6202
|
+
const { extraBody } = options;
|
|
6203
|
+
if (!extraBody || !Object.hasOwn(extraBody, "thinking_budget")) return;
|
|
6204
|
+
const rawPayload = payload;
|
|
6205
|
+
rawPayload.thinking_budget = extraBody.thinking_budget;
|
|
6206
|
+
};
|
|
6165
6207
|
const handleOpenAICompatibleProviderMessages = async (c, options) => {
|
|
6166
6208
|
const { instrumentation, modelConfig, payload, provider, providerConfig } = options;
|
|
6167
6209
|
const openAIPayload = createOpenAICompatiblePayload(payload, modelConfig);
|
|
@@ -6194,6 +6236,7 @@ const createOpenAICompatiblePayload = (payload, modelConfig) => {
|
|
|
6194
6236
|
supportPdf: modelConfig?.supportPdf,
|
|
6195
6237
|
toolContentSupportType: modelConfig?.toolContentSupportType ?? []
|
|
6196
6238
|
});
|
|
6239
|
+
applyOpenAICompatibleThinkingBudget(openAIPayload, payload);
|
|
6197
6240
|
if (payload.top_k !== void 0) openAIPayload.top_k = payload.top_k;
|
|
6198
6241
|
if (openAIPayload.stream) openAIPayload.stream_options = { include_usage: true };
|
|
6199
6242
|
normalizeOpenAICompatibleReasoningContent(openAIPayload);
|
|
@@ -6202,6 +6245,7 @@ const createOpenAICompatiblePayload = (payload, modelConfig) => {
|
|
|
6202
6245
|
source: payload
|
|
6203
6246
|
});
|
|
6204
6247
|
applyMissingExtraBody(openAIPayload, { extraBody: modelConfig?.extraBody });
|
|
6248
|
+
applyOpenAICompatibleExtraBodyThinkingBudget(openAIPayload, { extraBody: modelConfig?.extraBody });
|
|
6205
6249
|
if (!Object.hasOwn(openAIPayload, "parallel_tool_calls")) openAIPayload.parallel_tool_calls = true;
|
|
6206
6250
|
if (modelConfig?.contextCache !== false) applyOpenAICompatibleContextCache(openAIPayload);
|
|
6207
6251
|
return openAIPayload;
|
|
@@ -6507,7 +6551,8 @@ const createResponsesStreamState = (options) => ({
|
|
|
6507
6551
|
openBlocks: /* @__PURE__ */ new Set(),
|
|
6508
6552
|
blockHasDelta: /* @__PURE__ */ new Set(),
|
|
6509
6553
|
functionCallStateByOutputIndex: /* @__PURE__ */ new Map(),
|
|
6510
|
-
toolSearchName: options?.toolSearchName ?? "mcp__tool_search__search"
|
|
6554
|
+
toolSearchName: options?.toolSearchName ?? "mcp__tool_search__search",
|
|
6555
|
+
hasToolCall: false
|
|
6511
6556
|
});
|
|
6512
6557
|
const translateResponsesStreamEvent = (rawEvent, state) => {
|
|
6513
6558
|
switch (rawEvent.type) {
|
|
@@ -6755,7 +6800,10 @@ const handleResponseCompleted = (rawEvent, state) => {
|
|
|
6755
6800
|
const events = new Array();
|
|
6756
6801
|
closeAllOpenBlocks(state, events);
|
|
6757
6802
|
state.responseStatus = response.status;
|
|
6758
|
-
const anthropic = translateResponsesResultToAnthropic(response
|
|
6803
|
+
const anthropic = translateResponsesResultToAnthropic(response, {
|
|
6804
|
+
hasToolCall: state.hasToolCall,
|
|
6805
|
+
toolSearchName: state.toolSearchName
|
|
6806
|
+
});
|
|
6759
6807
|
events.push({
|
|
6760
6808
|
type: "message_delta",
|
|
6761
6809
|
delta: {
|
|
@@ -6887,6 +6935,7 @@ const buildErrorEvent = (message) => ({
|
|
|
6887
6935
|
const getBlockKey = (outputIndex, contentIndex) => `${outputIndex}:${contentIndex}`;
|
|
6888
6936
|
const openFunctionCallBlock = (state, params) => {
|
|
6889
6937
|
const { outputIndex, toolCallId, name, events } = params;
|
|
6938
|
+
state.hasToolCall = true;
|
|
6890
6939
|
let functionCallState = state.functionCallStateByOutputIndex.get(outputIndex);
|
|
6891
6940
|
if (!functionCallState) {
|
|
6892
6941
|
const blockIndex = state.nextContentBlockIndex;
|
|
@@ -6940,8 +6989,9 @@ const stringifyToolSearchArguments = (argumentsValue) => {
|
|
|
6940
6989
|
return;
|
|
6941
6990
|
}
|
|
6942
6991
|
};
|
|
6992
|
+
const DEFAULT_RESPONSES_COMPACT_THRESHOLD_RATIO = .9;
|
|
6943
6993
|
const responsesUtilsDependencies = {
|
|
6944
|
-
|
|
6994
|
+
isResponsesApiContextManagementEnabled,
|
|
6945
6995
|
isResponsesApiWebSocketEnabled
|
|
6946
6996
|
};
|
|
6947
6997
|
const getResponsesRequestOptions = (payload) => {
|
|
@@ -6971,18 +7021,35 @@ const isAgentRole = (item) => {
|
|
|
6971
7021
|
const hasVisionInput$1 = (payload) => {
|
|
6972
7022
|
return getPayloadItems(payload).some((item) => containsVisionContent(item));
|
|
6973
7023
|
};
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
7024
|
+
"" + [
|
|
7025
|
+
"iVBORw0KGgoAAAANSUhEUgAAAGAAAAAgCAMAAADaHo1mAAADAFBMVEX///8fKTfR1dsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
7026
|
+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
7027
|
+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
7028
|
+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
7029
|
+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
7030
|
+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
7031
|
+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
7032
|
+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
7033
|
+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
7034
|
+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
7035
|
+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
7036
|
+
"AAAAAAAAAAAAAAAAAAAAAACae8QWAAAAvElEQVR42u1WixKAIAhj/f9Hdz2BXJiVed3pVSYtpgwsGSo3GaRq6wSd4F8EyIJx",
|
|
7037
|
+
"ydSUAMB8il51sHT2fiVQu8czguQwXWAyFvswIJhmoS9gmzYlcFiHj1aAgzcJVgCyguYhAhNZmMhYQZs1EJnnIAqKiuHjSrZT",
|
|
7038
|
+
"ucSQ4s8JkKDDIYr3IuR8vEWgqroKP9b1bYKk2wfgeVmqATQLXdXamsXdEKkz3QXEEeTTuWWImMhW6qci94/+hwSVf99HqVoD",
|
|
7039
|
+
"OAuj2SEAAAAASUVORK5CYII="
|
|
7040
|
+
].join("");
|
|
7041
|
+
const resolveResponsesCompactThreshold = (maxPromptTokens, compactThresholdRatio = DEFAULT_RESPONSES_COMPACT_THRESHOLD_RATIO) => {
|
|
7042
|
+
if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * compactThresholdRatio);
|
|
7043
|
+
return 2e5 * compactThresholdRatio;
|
|
6977
7044
|
};
|
|
6978
7045
|
const createCompactionContextManagement = (compactThreshold) => [{
|
|
6979
7046
|
type: "compaction",
|
|
6980
7047
|
compact_threshold: compactThreshold
|
|
6981
7048
|
}];
|
|
6982
|
-
const applyResponsesApiContextManagement = (payload, maxPromptTokens) => {
|
|
7049
|
+
const applyResponsesApiContextManagement = (payload, maxPromptTokens, compactThresholdRatio = DEFAULT_RESPONSES_COMPACT_THRESHOLD_RATIO) => {
|
|
6983
7050
|
if (payload.context_management !== void 0) return;
|
|
6984
|
-
if (!responsesUtilsDependencies.
|
|
6985
|
-
payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens));
|
|
7051
|
+
if (!responsesUtilsDependencies.isResponsesApiContextManagementEnabled()) return;
|
|
7052
|
+
payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens, compactThresholdRatio));
|
|
6986
7053
|
};
|
|
6987
7054
|
const compactInputByLatestCompaction = (payload) => {
|
|
6988
7055
|
if (!Array.isArray(payload.input) || payload.input.length === 0) return;
|
|
@@ -7085,7 +7152,7 @@ const buildMessagesHeaders = ({ ctx, enableVision, initiator, options, payload }
|
|
|
7085
7152
|
};
|
|
7086
7153
|
prepareInteractionHeaders(options?.sessionId, Boolean(options?.subagentMarker), headers);
|
|
7087
7154
|
prepareForCompact(headers, options?.compactType);
|
|
7088
|
-
if (shouldUseMessageProxyHeaders(payload)) prepareMessageProxyHeaders(headers);
|
|
7155
|
+
if (shouldUseMessageProxyHeaders(payload) && payload.model !== "claude-opus-4.8") prepareMessageProxyHeaders(headers);
|
|
7089
7156
|
const anthropicBeta = buildAnthropicBetaHeader(options?.anthropicBetaHeader, payload.thinking, payload.model);
|
|
7090
7157
|
if (anthropicBeta) headers["anthropic-beta"] = anthropicBeta;
|
|
7091
7158
|
return headers;
|
|
@@ -7343,6 +7410,7 @@ async function handleCompletion(c) {
|
|
|
7343
7410
|
const path = new URL(c.req.url, "http://local").pathname;
|
|
7344
7411
|
const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
|
|
7345
7412
|
const userAgent = c.req.header("user-agent") ?? void 0;
|
|
7413
|
+
normalizeSystemMessages(anthropicPayload);
|
|
7346
7414
|
sanitizeIdeTools(anthropicPayload);
|
|
7347
7415
|
debugJson(logger$3, "Anthropic request payload:", anthropicPayload);
|
|
7348
7416
|
const markerInspection = inspectSubagentMarkerFromFirstUser(anthropicPayload);
|
|
@@ -7370,6 +7438,8 @@ async function handleCompletion(c) {
|
|
|
7370
7438
|
const upstreamRequestId = generateRequestIdFromPayload(anthropicPayload, sessionId);
|
|
7371
7439
|
logger$3.debug("Generated request ID:", upstreamRequestId);
|
|
7372
7440
|
const clientModel = anthropicPayload.model;
|
|
7441
|
+
anthropicPayload.model = resolveModelAlias(anthropicPayload.model);
|
|
7442
|
+
const routingModel = anthropicPayload.model;
|
|
7373
7443
|
const streamRequested = Boolean(anthropicPayload.stream);
|
|
7374
7444
|
const rawUserId = anthropicPayload.metadata?.user_id;
|
|
7375
7445
|
const userId = typeof rawUserId === "string" ? rawUserId : void 0;
|
|
@@ -7401,9 +7471,9 @@ async function handleCompletion(c) {
|
|
|
7401
7471
|
selectionReason: invalidSubagentMarkerSelectionReason
|
|
7402
7472
|
});
|
|
7403
7473
|
if (blockedResponse) return blockedResponse;
|
|
7404
|
-
const endpointModel = findEndpointModel(
|
|
7405
|
-
const resolvedClientModel = endpointModel?.id ??
|
|
7406
|
-
const affinityModelId =
|
|
7474
|
+
const endpointModel = findEndpointModel(routingModel);
|
|
7475
|
+
const resolvedClientModel = endpointModel?.id ?? routingModel;
|
|
7476
|
+
const affinityModelId = routingModel !== originalRequestModel ? findEndpointModel(originalRequestModel)?.id ?? originalRequestModel : void 0;
|
|
7407
7477
|
const useMessagesApi = isMessagesApiEnabled();
|
|
7408
7478
|
const candidates = [];
|
|
7409
7479
|
if (useMessagesApi) candidates.push({
|
|
@@ -8269,6 +8339,82 @@ providerMessageRoutes.post("/count_tokens", async (c) => {
|
|
|
8269
8339
|
}
|
|
8270
8340
|
});
|
|
8271
8341
|
//#endregion
|
|
8342
|
+
//#region src/services/codex/get-models.ts
|
|
8343
|
+
const CODEX_MODELS = [
|
|
8344
|
+
{
|
|
8345
|
+
contextWindow: 1e5,
|
|
8346
|
+
id: "gpt-5.3-codex-spark",
|
|
8347
|
+
input: ["text"],
|
|
8348
|
+
maxTokens: 32e3,
|
|
8349
|
+
name: "GPT-5.3 Codex Spark"
|
|
8350
|
+
},
|
|
8351
|
+
{
|
|
8352
|
+
contextWindow: 4e5,
|
|
8353
|
+
id: "gpt-5.4",
|
|
8354
|
+
input: ["text", "image"],
|
|
8355
|
+
maxTokens: 128e3,
|
|
8356
|
+
name: "GPT-5.4"
|
|
8357
|
+
},
|
|
8358
|
+
{
|
|
8359
|
+
contextWindow: 4e5,
|
|
8360
|
+
id: "gpt-5.4-mini",
|
|
8361
|
+
input: ["text", "image"],
|
|
8362
|
+
maxTokens: 128e3,
|
|
8363
|
+
name: "GPT-5.4 mini"
|
|
8364
|
+
},
|
|
8365
|
+
{
|
|
8366
|
+
contextWindow: 272e3,
|
|
8367
|
+
id: "gpt-5.5",
|
|
8368
|
+
input: ["text", "image"],
|
|
8369
|
+
maxTokens: 128e3,
|
|
8370
|
+
name: "GPT-5.5"
|
|
8371
|
+
}
|
|
8372
|
+
];
|
|
8373
|
+
function normalizeCodexModel(model) {
|
|
8374
|
+
const supportsVision = model.input.includes("image");
|
|
8375
|
+
return {
|
|
8376
|
+
capabilities: {
|
|
8377
|
+
family: "gpt",
|
|
8378
|
+
limits: {
|
|
8379
|
+
max_context_window_tokens: model.contextWindow,
|
|
8380
|
+
max_output_tokens: model.maxTokens,
|
|
8381
|
+
max_prompt_tokens: model.contextWindow
|
|
8382
|
+
},
|
|
8383
|
+
object: "model_capabilities",
|
|
8384
|
+
supports: {
|
|
8385
|
+
adaptive_thinking: true,
|
|
8386
|
+
parallel_tool_calls: true,
|
|
8387
|
+
reasoning_effort: [
|
|
8388
|
+
"minimal",
|
|
8389
|
+
"low",
|
|
8390
|
+
"medium",
|
|
8391
|
+
"high",
|
|
8392
|
+
"xhigh"
|
|
8393
|
+
],
|
|
8394
|
+
streaming: true,
|
|
8395
|
+
tool_calls: true,
|
|
8396
|
+
vision: supportsVision
|
|
8397
|
+
},
|
|
8398
|
+
tokenizer: "o200k_base",
|
|
8399
|
+
type: "chat"
|
|
8400
|
+
},
|
|
8401
|
+
id: model.id,
|
|
8402
|
+
model_picker_enabled: true,
|
|
8403
|
+
name: model.name,
|
|
8404
|
+
object: "model",
|
|
8405
|
+
preview: false,
|
|
8406
|
+
supported_endpoints: ["/v1/messages", "/v1/responses"],
|
|
8407
|
+
vendor: "openai",
|
|
8408
|
+
version: "chatgpt-codex"
|
|
8409
|
+
};
|
|
8410
|
+
}
|
|
8411
|
+
function getModels() {
|
|
8412
|
+
return {
|
|
8413
|
+
object: "list",
|
|
8414
|
+
data: CODEX_MODELS.map((model) => normalizeCodexModel(model))
|
|
8415
|
+
};
|
|
8416
|
+
}
|
|
8417
|
+
//#endregion
|
|
8272
8418
|
//#region src/routes/provider/models/route.ts
|
|
8273
8419
|
const logger$2 = createHandlerLogger("provider-models-handler");
|
|
8274
8420
|
const getProviderFetch = (c) => c.get("providerFetch") ?? fetch;
|
|
@@ -8284,6 +8430,14 @@ providerModelRoutes.get("/", async (c) => {
|
|
|
8284
8430
|
message: `Provider '${provider}' not found or disabled`,
|
|
8285
8431
|
type: "invalid_request_error"
|
|
8286
8432
|
} }, 404);
|
|
8433
|
+
if (providerConfig.name === "codex") {
|
|
8434
|
+
const models = getModels();
|
|
8435
|
+
return c.json({
|
|
8436
|
+
object: "list",
|
|
8437
|
+
data: models.data,
|
|
8438
|
+
has_more: false
|
|
8439
|
+
});
|
|
8440
|
+
}
|
|
8287
8441
|
const upstreamResponse = await forwardProviderModels(providerConfig, c.req.raw.headers, getProviderFetch(c));
|
|
8288
8442
|
logger$2.debug("provider.models.response", {
|
|
8289
8443
|
provider,
|
|
@@ -8414,6 +8568,7 @@ const handleResponses = async (c) => {
|
|
|
8414
8568
|
const upstreamSessionId = getUUID(normalizedPromptCacheKey ?? headerSessionId ?? upstreamRequestId);
|
|
8415
8569
|
request.upstreamRequestId = upstreamRequestId;
|
|
8416
8570
|
request.upstreamSessionId = upstreamSessionId;
|
|
8571
|
+
const bridgeId = c.req.header("x-responses-bridge-id") ?? void 0;
|
|
8417
8572
|
if (streamRequested) return handleStreamingResponses({
|
|
8418
8573
|
c,
|
|
8419
8574
|
store,
|
|
@@ -8426,7 +8581,8 @@ const handleResponses = async (c) => {
|
|
|
8426
8581
|
initiator,
|
|
8427
8582
|
premiumRemainingBefore,
|
|
8428
8583
|
premiumUnlimitedBefore,
|
|
8429
|
-
transport
|
|
8584
|
+
transport,
|
|
8585
|
+
bridgeId
|
|
8430
8586
|
});
|
|
8431
8587
|
return handleNonStreamingResponses({
|
|
8432
8588
|
c,
|
|
@@ -8440,7 +8596,8 @@ const handleResponses = async (c) => {
|
|
|
8440
8596
|
initiator,
|
|
8441
8597
|
premiumRemainingBefore,
|
|
8442
8598
|
premiumUnlimitedBefore,
|
|
8443
|
-
transport
|
|
8599
|
+
transport,
|
|
8600
|
+
bridgeId
|
|
8444
8601
|
});
|
|
8445
8602
|
};
|
|
8446
8603
|
async function observeRequestError(accountId, error, affinity) {
|
|
@@ -8548,7 +8705,7 @@ function extractUsageFromChunkData(data) {
|
|
|
8548
8705
|
}
|
|
8549
8706
|
}
|
|
8550
8707
|
async function handleStreamingResponses(params) {
|
|
8551
|
-
const { c, store, request, payload, selection, clientModel, accountCtx, vision, initiator, premiumRemainingBefore, premiumUnlimitedBefore, transport } = params;
|
|
8708
|
+
const { c, store, request, payload, selection, clientModel, accountCtx, vision, initiator, premiumRemainingBefore, premiumUnlimitedBefore, transport, bridgeId } = params;
|
|
8552
8709
|
let response;
|
|
8553
8710
|
try {
|
|
8554
8711
|
response = await createResponses(payload, {
|
|
@@ -8557,7 +8714,8 @@ async function handleStreamingResponses(params) {
|
|
|
8557
8714
|
upstreamRequestId: request.upstreamRequestId,
|
|
8558
8715
|
sessionId: request.upstreamSessionId,
|
|
8559
8716
|
requestId: request.requestId,
|
|
8560
|
-
transport
|
|
8717
|
+
transport,
|
|
8718
|
+
bridgeId
|
|
8561
8719
|
}, accountCtx);
|
|
8562
8720
|
selection.confirmAffinity?.();
|
|
8563
8721
|
} catch (error) {
|
|
@@ -8745,7 +8903,7 @@ async function streamResponsesAndLog(params) {
|
|
|
8745
8903
|
}
|
|
8746
8904
|
}
|
|
8747
8905
|
async function handleNonStreamingResponses(params) {
|
|
8748
|
-
const { c, store, request, payload, selection, clientModel, accountCtx, vision, initiator, premiumRemainingBefore, premiumUnlimitedBefore, transport } = params;
|
|
8906
|
+
const { c, store, request, payload, selection, clientModel, accountCtx, vision, initiator, premiumRemainingBefore, premiumUnlimitedBefore, transport, bridgeId } = params;
|
|
8749
8907
|
const { account, reservation, selectedModel, endpoint, costUnits } = selection;
|
|
8750
8908
|
let usage = {};
|
|
8751
8909
|
let errorState = { httpStatus: 200 };
|
|
@@ -8757,7 +8915,8 @@ async function handleNonStreamingResponses(params) {
|
|
|
8757
8915
|
upstreamRequestId: request.upstreamRequestId,
|
|
8758
8916
|
sessionId: request.upstreamSessionId,
|
|
8759
8917
|
requestId: request.requestId,
|
|
8760
|
-
transport
|
|
8918
|
+
transport,
|
|
8919
|
+
bridgeId
|
|
8761
8920
|
}, accountCtx);
|
|
8762
8921
|
if (isAsyncIterable$1(response)) throw new Error("Upstream returned a stream unexpectedly");
|
|
8763
8922
|
selection.confirmAffinity?.();
|
|
@@ -8881,31 +9040,43 @@ usageRoute.get("/:accountIndex", async (c) => {
|
|
|
8881
9040
|
});
|
|
8882
9041
|
//#endregion
|
|
8883
9042
|
//#region src/server.ts
|
|
8884
|
-
|
|
8885
|
-
|
|
8886
|
-
|
|
8887
|
-
|
|
8888
|
-
|
|
8889
|
-
|
|
8890
|
-
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
|
|
8894
|
-
|
|
8895
|
-
|
|
8896
|
-
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
8900
|
-
|
|
8901
|
-
|
|
8902
|
-
|
|
8903
|
-
|
|
8904
|
-
|
|
8905
|
-
|
|
8906
|
-
|
|
8907
|
-
|
|
9043
|
+
function createServer(options = {}) {
|
|
9044
|
+
const app = new Hono();
|
|
9045
|
+
const enableMcpHttp = options.enableMcpHttp ?? isMcpHttpEnabledFromEnv();
|
|
9046
|
+
app.use(traceIdMiddleware);
|
|
9047
|
+
app.use(logger());
|
|
9048
|
+
if (enableMcpHttp) {
|
|
9049
|
+
app.use(DEFAULT_MCP_HTTP_PATH, cors(mcpHttpCorsOptions));
|
|
9050
|
+
app.all(DEFAULT_MCP_HTTP_PATH, (c) => handleStreamableHttpMcpRequest(c.req.raw));
|
|
9051
|
+
} else app.all(DEFAULT_MCP_HTTP_PATH, (c) => c.json({ error: {
|
|
9052
|
+
type: "mcp_http_disabled",
|
|
9053
|
+
message: "MCP Streamable HTTP is disabled. Start with --enable-mcp-http to expose /mcp."
|
|
9054
|
+
} }, 404));
|
|
9055
|
+
app.use(cors());
|
|
9056
|
+
app.use("*", createAuthMiddleware({
|
|
9057
|
+
allowUnauthenticatedPaths: ["/", DEFAULT_MCP_HTTP_PATH],
|
|
9058
|
+
allowUnauthenticatedPathPrefixes: ["/admin", "/api/admin"]
|
|
9059
|
+
}));
|
|
9060
|
+
app.get("/", (c) => c.text("Server running"));
|
|
9061
|
+
app.route("/chat/completions", completionRoutes);
|
|
9062
|
+
app.route("/models", modelRoutes);
|
|
9063
|
+
app.route("/embeddings", embeddingRoutes);
|
|
9064
|
+
app.route("/usage", usageRoute);
|
|
9065
|
+
app.route("/token", tokenRoute);
|
|
9066
|
+
app.route("/responses", responsesRoutes);
|
|
9067
|
+
app.route("/admin", adminRoutes);
|
|
9068
|
+
app.route("/api/admin", adminApiRoutes);
|
|
9069
|
+
app.route("/v1/chat/completions", completionRoutes);
|
|
9070
|
+
app.route("/v1/models", modelRoutes);
|
|
9071
|
+
app.route("/v1/embeddings", embeddingRoutes);
|
|
9072
|
+
app.route("/v1/responses", responsesRoutes);
|
|
9073
|
+
app.route("/v1/messages", messageRoutes);
|
|
9074
|
+
app.route("/:provider/v1/messages", providerMessageRoutes);
|
|
9075
|
+
app.route("/:provider/v1/models", providerModelRoutes);
|
|
9076
|
+
return app;
|
|
9077
|
+
}
|
|
9078
|
+
createServer();
|
|
8908
9079
|
//#endregion
|
|
8909
|
-
export {
|
|
9080
|
+
export { createServer };
|
|
8910
9081
|
|
|
8911
|
-
//# sourceMappingURL=server-
|
|
9082
|
+
//# sourceMappingURL=server-DJ3_UGc4.js.map
|