@nick3/copilot-api 1.10.9 → 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.
Files changed (55) hide show
  1. package/README.md +140 -45
  2. package/README.zh-CN.md +140 -45
  3. package/dist/{account-COtMmvzU.js → account-DpW8RaT6.js} +3 -3
  4. package/dist/{account-COtMmvzU.js.map → account-DpW8RaT6.js.map} +1 -1
  5. package/dist/admin/AGENTS.md +19 -0
  6. package/dist/auth-nO-eHeO_.js +327 -0
  7. package/dist/auth-nO-eHeO_.js.map +1 -0
  8. package/dist/{check-usage-DdevqHE5.js → check-usage-ZifYvA3w.js} +4 -42
  9. package/dist/check-usage-ZifYvA3w.js.map +1 -0
  10. package/dist/config-CmhIPHn_.js +578 -0
  11. package/dist/config-CmhIPHn_.js.map +1 -0
  12. package/dist/{debug-BMo6ltbp.js → debug-DvpksqEL.js} +18 -7
  13. package/dist/debug-DvpksqEL.js.map +1 -0
  14. package/dist/main.js +5 -10
  15. package/dist/main.js.map +1 -1
  16. package/dist/mcp-http-BhELuvog.js +2 -0
  17. package/dist/mcp-http-DI4Vz01p.js +82 -0
  18. package/dist/mcp-http-DI4Vz01p.js.map +1 -0
  19. package/dist/mcp-http-config-DMdUDz1D.js +39 -0
  20. package/dist/mcp-http-config-DMdUDz1D.js.map +1 -0
  21. package/dist/mcp-pLTPS0tO.js +79 -0
  22. package/dist/mcp-pLTPS0tO.js.map +1 -0
  23. package/dist/{tool-search-BrN7M0Dd.js → mcp-server-DEqHrXFq.js} +25 -2
  24. package/dist/mcp-server-DEqHrXFq.js.map +1 -0
  25. package/dist/{paths-CclKwouX.js → paths-Bpsb62LK.js} +3 -1
  26. package/dist/paths-Bpsb62LK.js.map +1 -0
  27. package/dist/{poll-access-token-BAgM2-7k.js → poll-access-token-GzVkiTH8.js} +71 -4
  28. package/dist/poll-access-token-GzVkiTH8.js.map +1 -0
  29. package/dist/{request-outbound-BJjWS_jF.js → request-outbound-BkEA8Wgb.js} +1 -1
  30. package/dist/{request-outbound-Pu1kp2x8.js → request-outbound-DZTxxtcx.js} +3 -3
  31. package/dist/{request-outbound-Pu1kp2x8.js.map → request-outbound-DZTxxtcx.js.map} +1 -1
  32. package/dist/{proxy-_U-hgwIn.js → responses-bridge-registry-BJ5Sbh6-.js} +116 -577
  33. package/dist/responses-bridge-registry-BJ5Sbh6-.js.map +1 -0
  34. package/dist/{server-GxNB5Syq.js → server-DJ3_UGc4.js} +313 -165
  35. package/dist/server-DJ3_UGc4.js.map +1 -0
  36. package/dist/start-DaB0AcjZ.js +526 -0
  37. package/dist/start-DaB0AcjZ.js.map +1 -0
  38. package/dist/token-DrFDLVxa.js +365 -0
  39. package/dist/token-DrFDLVxa.js.map +1 -0
  40. package/package.json +1 -1
  41. package/dist/auth-B0y-2njL.js +0 -226
  42. package/dist/auth-B0y-2njL.js.map +0 -1
  43. package/dist/check-usage-DdevqHE5.js.map +0 -1
  44. package/dist/debug-BMo6ltbp.js.map +0 -1
  45. package/dist/get-copilot-token-8Rm-rVsp.js +0 -17
  46. package/dist/get-copilot-token-8Rm-rVsp.js.map +0 -1
  47. package/dist/mcp-9Hgepkc5.js +0 -37
  48. package/dist/mcp-9Hgepkc5.js.map +0 -1
  49. package/dist/paths-CclKwouX.js.map +0 -1
  50. package/dist/poll-access-token-BAgM2-7k.js.map +0 -1
  51. package/dist/proxy-_U-hgwIn.js.map +0 -1
  52. package/dist/server-GxNB5Syq.js.map +0 -1
  53. package/dist/start-DdrurmQ3.js +0 -274
  54. package/dist/start-DdrurmQ3.js.map +0 -1
  55. package/dist/tool-search-BrN7M0Dd.js.map +0 -1
@@ -1,109 +1,26 @@
1
- import { A as state, D as prepareInteractionHeaders, E as prepareForCompact, I as compactAutoContinuePromptStarts, L as compactMessageSections, N as requestContext, O as prepareMessageProxyHeaders, P as resolveTraceId, S as copilotWebSocketHeaders, T as normalizeDomain, _ as HTTPError, b as copilotHeaders, c as getUUID, d as parseUserIdMetadata, f as resolveAffinityKey, g as getCopilotUsage, h as getDeviceCode, j as captureOutboundHeadersSnapshot, k as accountFromState, l as isNullish, m as getGitHubUser, o as generateRequestIdFromPayload, p as sleep, s as getRootSessionId, t as pollAccessToken, u as normalizeStableSessionId, v as forwardError, y as copilotBaseUrl, z as compactSystemPromptStarts } from "./poll-access-token-BAgM2-7k.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-COtMmvzU.js";
3
- import { r as ensurePaths, t as PATHS } from "./paths-CclKwouX.js";
4
- import { i as getRequestOutboundStore, r as getRedactedHeaderKeys } from "./request-outbound-Pu1kp2x8.js";
5
- import { a as isDeferredToolName, c as parseMcpToolSearchSentinel, i as isBridgeToolSearchName, l as selectDeferredToolsByNames, o as listDeferredToolNames, r as formatToolSearchBridgeArguments, s as normalizeToolSearchBridgeArguments, t as BRIDGE_TOOL_SEARCH_NAME, u as shouldEnableResponsesToolSearch } from "./tool-search-BrN7M0Dd.js";
6
- import { A as getModelRefreshIntervalMs, B as isResponsesApiWebSocketEnabled, C as getAnthropicApiKey, D as getLogLevel, E as getExtraPromptForModel, F as isForceAgentEnabled, H as resolveModelAlias, I as isMessageStartInputTokensFallbackEnabled, L as isMessagesApiEnabled, M as getReasoningEffortForModel, N as getSmallModel, O as getModelAliases, P as isAccountAffinityEnabled, R as isResponsesApiContextManagementModel, S as getAliasTargetSet, T as getConfig, U as shouldCompactUseSmallModel, V as mergeConfigWithDefaults, _ as toLocalDateString, b as isDevModeEnabled, c as applySharedSessionAffinityRetention, d as getClientIpInfo, f as getRequestHistoryStore, g as normalizeMessagesUsage, h as normalizeEmbeddingsUsage, j as getProviderConfig, k as getModelAliasesInfo, l as extractResponsesUsageFromResult, m as normalizeChatCompletionsUsage, o as updateQuotaRefreshSchedulerFromConfig, p as getStatsStore, s as accountsManager, t as getProxyEnvDispatcher, u as extractResponsesUsageFromStreamEvent, v as copilotFetch, w as getClaudeTokenMultiplier, x as PROVIDER_TYPE_ANTHROPIC, y as flushPendingCapture, z as isResponsesApiWebSearchEnabled } from "./proxy-_U-hgwIn.js";
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, timingSafeEqual } from "node:crypto";
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 { fileURLToPath } from "node:url";
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 = _normalizeSdkModelId(sdkModelId);
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 _normalizeSdkModelId = (sdkModelId) => {
237
+ const normalizeSdkModelId = (sdkModelId) => {
321
238
  const withoutDate = sdkModelId.toLowerCase().replace(/-\d{8}$/, "");
322
- const pattern1 = withoutDate.match(/^claude-(\w+)-(\d+)-(\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-(\d+)-(\d+)-(\w+)$/);
244
+ const pattern2 = withoutDate.match(/^claude-(\w+)-(\d+)-(\d+)$/);
328
245
  if (pattern2) return {
329
- family: pattern2[3],
330
- version: `${pattern2[1]}.${pattern2[2]}`
246
+ family: pattern2[1],
247
+ version: `${pattern2[2]}.${pattern2[3]}`
331
248
  };
332
- const pattern3 = withoutDate.match(/^claude-(\w+)-(\d+)\.(\d+)$/);
249
+ const pattern3 = withoutDate.match(/^claude-(\d+)-(\d+)-(\w+)$/);
333
250
  if (pattern3) return {
334
- family: pattern3[1],
335
- version: `${pattern3[2]}.${pattern3[3]}`
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.info(`Copilot ${usage.type} quota remaining: ${usage.remaining}, resets at: ${dateStr}`);
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 === "claude-opus-4.7") payload.thinking.display = "summarized";
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 = ["authorization", "x-api-key"];
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
- subagentMarker
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
- requestId,
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/anthropic-proxy.ts
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 === "authorization") authHeaders.authorization = `Bearer ${providerConfig.apiKey}`;
6013
- else authHeaders["x-api-key"] = providerConfig.apiKey;
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
@@ -6528,7 +6551,8 @@ const createResponsesStreamState = (options) => ({
6528
6551
  openBlocks: /* @__PURE__ */ new Set(),
6529
6552
  blockHasDelta: /* @__PURE__ */ new Set(),
6530
6553
  functionCallStateByOutputIndex: /* @__PURE__ */ new Map(),
6531
- toolSearchName: options?.toolSearchName ?? "mcp__tool_search__search"
6554
+ toolSearchName: options?.toolSearchName ?? "mcp__tool_search__search",
6555
+ hasToolCall: false
6532
6556
  });
6533
6557
  const translateResponsesStreamEvent = (rawEvent, state) => {
6534
6558
  switch (rawEvent.type) {
@@ -6776,7 +6800,10 @@ const handleResponseCompleted = (rawEvent, state) => {
6776
6800
  const events = new Array();
6777
6801
  closeAllOpenBlocks(state, events);
6778
6802
  state.responseStatus = response.status;
6779
- const anthropic = translateResponsesResultToAnthropic(response);
6803
+ const anthropic = translateResponsesResultToAnthropic(response, {
6804
+ hasToolCall: state.hasToolCall,
6805
+ toolSearchName: state.toolSearchName
6806
+ });
6780
6807
  events.push({
6781
6808
  type: "message_delta",
6782
6809
  delta: {
@@ -6908,6 +6935,7 @@ const buildErrorEvent = (message) => ({
6908
6935
  const getBlockKey = (outputIndex, contentIndex) => `${outputIndex}:${contentIndex}`;
6909
6936
  const openFunctionCallBlock = (state, params) => {
6910
6937
  const { outputIndex, toolCallId, name, events } = params;
6938
+ state.hasToolCall = true;
6911
6939
  let functionCallState = state.functionCallStateByOutputIndex.get(outputIndex);
6912
6940
  if (!functionCallState) {
6913
6941
  const blockIndex = state.nextContentBlockIndex;
@@ -6961,8 +6989,9 @@ const stringifyToolSearchArguments = (argumentsValue) => {
6961
6989
  return;
6962
6990
  }
6963
6991
  };
6992
+ const DEFAULT_RESPONSES_COMPACT_THRESHOLD_RATIO = .9;
6964
6993
  const responsesUtilsDependencies = {
6965
- isResponsesApiContextManagementModel,
6994
+ isResponsesApiContextManagementEnabled,
6966
6995
  isResponsesApiWebSocketEnabled
6967
6996
  };
6968
6997
  const getResponsesRequestOptions = (payload) => {
@@ -6992,18 +7021,35 @@ const isAgentRole = (item) => {
6992
7021
  const hasVisionInput$1 = (payload) => {
6993
7022
  return getPayloadItems(payload).some((item) => containsVisionContent(item));
6994
7023
  };
6995
- const resolveResponsesCompactThreshold = (maxPromptTokens) => {
6996
- if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * .9);
6997
- return 5e4;
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;
6998
7044
  };
6999
7045
  const createCompactionContextManagement = (compactThreshold) => [{
7000
7046
  type: "compaction",
7001
7047
  compact_threshold: compactThreshold
7002
7048
  }];
7003
- const applyResponsesApiContextManagement = (payload, maxPromptTokens) => {
7049
+ const applyResponsesApiContextManagement = (payload, maxPromptTokens, compactThresholdRatio = DEFAULT_RESPONSES_COMPACT_THRESHOLD_RATIO) => {
7004
7050
  if (payload.context_management !== void 0) return;
7005
- if (!responsesUtilsDependencies.isResponsesApiContextManagementModel(payload.model)) return;
7006
- payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens));
7051
+ if (!responsesUtilsDependencies.isResponsesApiContextManagementEnabled()) return;
7052
+ payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens, compactThresholdRatio));
7007
7053
  };
7008
7054
  const compactInputByLatestCompaction = (payload) => {
7009
7055
  if (!Array.isArray(payload.input) || payload.input.length === 0) return;
@@ -7106,7 +7152,7 @@ const buildMessagesHeaders = ({ ctx, enableVision, initiator, options, payload }
7106
7152
  };
7107
7153
  prepareInteractionHeaders(options?.sessionId, Boolean(options?.subagentMarker), headers);
7108
7154
  prepareForCompact(headers, options?.compactType);
7109
- if (shouldUseMessageProxyHeaders(payload)) prepareMessageProxyHeaders(headers);
7155
+ if (shouldUseMessageProxyHeaders(payload) && payload.model !== "claude-opus-4.8") prepareMessageProxyHeaders(headers);
7110
7156
  const anthropicBeta = buildAnthropicBetaHeader(options?.anthropicBetaHeader, payload.thinking, payload.model);
7111
7157
  if (anthropicBeta) headers["anthropic-beta"] = anthropicBeta;
7112
7158
  return headers;
@@ -7364,6 +7410,7 @@ async function handleCompletion(c) {
7364
7410
  const path = new URL(c.req.url, "http://local").pathname;
7365
7411
  const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
7366
7412
  const userAgent = c.req.header("user-agent") ?? void 0;
7413
+ normalizeSystemMessages(anthropicPayload);
7367
7414
  sanitizeIdeTools(anthropicPayload);
7368
7415
  debugJson(logger$3, "Anthropic request payload:", anthropicPayload);
7369
7416
  const markerInspection = inspectSubagentMarkerFromFirstUser(anthropicPayload);
@@ -8292,6 +8339,82 @@ providerMessageRoutes.post("/count_tokens", async (c) => {
8292
8339
  }
8293
8340
  });
8294
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
8295
8418
  //#region src/routes/provider/models/route.ts
8296
8419
  const logger$2 = createHandlerLogger("provider-models-handler");
8297
8420
  const getProviderFetch = (c) => c.get("providerFetch") ?? fetch;
@@ -8307,6 +8430,14 @@ providerModelRoutes.get("/", async (c) => {
8307
8430
  message: `Provider '${provider}' not found or disabled`,
8308
8431
  type: "invalid_request_error"
8309
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
+ }
8310
8441
  const upstreamResponse = await forwardProviderModels(providerConfig, c.req.raw.headers, getProviderFetch(c));
8311
8442
  logger$2.debug("provider.models.response", {
8312
8443
  provider,
@@ -8437,6 +8568,7 @@ const handleResponses = async (c) => {
8437
8568
  const upstreamSessionId = getUUID(normalizedPromptCacheKey ?? headerSessionId ?? upstreamRequestId);
8438
8569
  request.upstreamRequestId = upstreamRequestId;
8439
8570
  request.upstreamSessionId = upstreamSessionId;
8571
+ const bridgeId = c.req.header("x-responses-bridge-id") ?? void 0;
8440
8572
  if (streamRequested) return handleStreamingResponses({
8441
8573
  c,
8442
8574
  store,
@@ -8449,7 +8581,8 @@ const handleResponses = async (c) => {
8449
8581
  initiator,
8450
8582
  premiumRemainingBefore,
8451
8583
  premiumUnlimitedBefore,
8452
- transport
8584
+ transport,
8585
+ bridgeId
8453
8586
  });
8454
8587
  return handleNonStreamingResponses({
8455
8588
  c,
@@ -8463,7 +8596,8 @@ const handleResponses = async (c) => {
8463
8596
  initiator,
8464
8597
  premiumRemainingBefore,
8465
8598
  premiumUnlimitedBefore,
8466
- transport
8599
+ transport,
8600
+ bridgeId
8467
8601
  });
8468
8602
  };
8469
8603
  async function observeRequestError(accountId, error, affinity) {
@@ -8571,7 +8705,7 @@ function extractUsageFromChunkData(data) {
8571
8705
  }
8572
8706
  }
8573
8707
  async function handleStreamingResponses(params) {
8574
- 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;
8575
8709
  let response;
8576
8710
  try {
8577
8711
  response = await createResponses(payload, {
@@ -8580,7 +8714,8 @@ async function handleStreamingResponses(params) {
8580
8714
  upstreamRequestId: request.upstreamRequestId,
8581
8715
  sessionId: request.upstreamSessionId,
8582
8716
  requestId: request.requestId,
8583
- transport
8717
+ transport,
8718
+ bridgeId
8584
8719
  }, accountCtx);
8585
8720
  selection.confirmAffinity?.();
8586
8721
  } catch (error) {
@@ -8768,7 +8903,7 @@ async function streamResponsesAndLog(params) {
8768
8903
  }
8769
8904
  }
8770
8905
  async function handleNonStreamingResponses(params) {
8771
- 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;
8772
8907
  const { account, reservation, selectedModel, endpoint, costUnits } = selection;
8773
8908
  let usage = {};
8774
8909
  let errorState = { httpStatus: 200 };
@@ -8780,7 +8915,8 @@ async function handleNonStreamingResponses(params) {
8780
8915
  upstreamRequestId: request.upstreamRequestId,
8781
8916
  sessionId: request.upstreamSessionId,
8782
8917
  requestId: request.requestId,
8783
- transport
8918
+ transport,
8919
+ bridgeId
8784
8920
  }, accountCtx);
8785
8921
  if (isAsyncIterable$1(response)) throw new Error("Upstream returned a stream unexpectedly");
8786
8922
  selection.confirmAffinity?.();
@@ -8904,31 +9040,43 @@ usageRoute.get("/:accountIndex", async (c) => {
8904
9040
  });
8905
9041
  //#endregion
8906
9042
  //#region src/server.ts
8907
- const server = new Hono();
8908
- server.use(traceIdMiddleware);
8909
- server.use(logger());
8910
- server.use(cors());
8911
- server.use("*", createAuthMiddleware({
8912
- allowUnauthenticatedPaths: ["/"],
8913
- allowUnauthenticatedPathPrefixes: ["/admin", "/api/admin"]
8914
- }));
8915
- server.get("/", (c) => c.text("Server running"));
8916
- server.route("/chat/completions", completionRoutes);
8917
- server.route("/models", modelRoutes);
8918
- server.route("/embeddings", embeddingRoutes);
8919
- server.route("/usage", usageRoute);
8920
- server.route("/token", tokenRoute);
8921
- server.route("/responses", responsesRoutes);
8922
- server.route("/admin", adminRoutes);
8923
- server.route("/api/admin", adminApiRoutes);
8924
- server.route("/v1/chat/completions", completionRoutes);
8925
- server.route("/v1/models", modelRoutes);
8926
- server.route("/v1/embeddings", embeddingRoutes);
8927
- server.route("/v1/responses", responsesRoutes);
8928
- server.route("/v1/messages", messageRoutes);
8929
- server.route("/:provider/v1/messages", providerMessageRoutes);
8930
- server.route("/:provider/v1/models", providerModelRoutes);
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();
8931
9079
  //#endregion
8932
- export { server };
9080
+ export { createServer };
8933
9081
 
8934
- //# sourceMappingURL=server-GxNB5Syq.js.map
9082
+ //# sourceMappingURL=server-DJ3_UGc4.js.map