@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.
- package/README.md +140 -45
- package/README.zh-CN.md +140 -45
- 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-GxNB5Syq.js → server-DJ3_UGc4.js} +313 -165
- 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-GxNB5Syq.js.map +0 -1
- package/dist/start-DdrurmQ3.js +0 -274
- package/dist/start-DdrurmQ3.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
|
|
@@ -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
|
-
|
|
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
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
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.
|
|
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
|
-
|
|
8908
|
-
|
|
8909
|
-
|
|
8910
|
-
|
|
8911
|
-
|
|
8912
|
-
|
|
8913
|
-
|
|
8914
|
-
|
|
8915
|
-
|
|
8916
|
-
|
|
8917
|
-
|
|
8918
|
-
|
|
8919
|
-
|
|
8920
|
-
|
|
8921
|
-
|
|
8922
|
-
|
|
8923
|
-
|
|
8924
|
-
|
|
8925
|
-
|
|
8926
|
-
|
|
8927
|
-
|
|
8928
|
-
|
|
8929
|
-
|
|
8930
|
-
|
|
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 {
|
|
9080
|
+
export { createServer };
|
|
8933
9081
|
|
|
8934
|
-
//# sourceMappingURL=server-
|
|
9082
|
+
//# sourceMappingURL=server-DJ3_UGc4.js.map
|