@jeffreycao/copilot-api 1.9.15 → 1.10.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-De0Po8kG.js","names":["get"],"sources":["../src/lib/config.ts","../src/lib/proxy.ts"],"sourcesContent":["import consola from \"consola\"\nimport fs from \"node:fs\"\n\nimport { PATHS } from \"./paths\"\n\nexport interface AppConfig {\n auth?: {\n apiKeys?: Array<string>\n }\n providers?: Record<string, ProviderConfig>\n extraPrompts?: Record<string, string>\n smallModel?: string\n responsesApiContextManagementModels?: Array<string>\n modelReasoningEfforts?: Record<\n string,\n \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"\n >\n useFunctionApplyPatch?: boolean\n useMessagesApi?: boolean\n useResponsesApiWebSocket?: boolean\n anthropicApiKey?: string\n useResponsesApiWebSearch?: boolean\n claudeTokenMultiplier?: number\n}\n\nexport interface ModelConfig {\n temperature?: number\n topP?: number\n topK?: number\n extraBody?: Record<string, unknown>\n contextCache?: boolean\n supportPdf?: boolean\n toolContentSupportType?: Array<ToolContentSupportType>\n}\n\nexport type ProviderAuthType = \"authorization\" | \"x-api-key\"\nexport type ProviderType = \"anthropic\" | \"openai-compatible\"\nexport type ToolContentSupportType = \"array\" | \"image\" | \"pdf\"\n\nexport interface ProviderConfig {\n type?: string\n enabled?: boolean\n baseUrl?: string\n apiKey?: string\n authType?: ProviderAuthType\n models?: Record<string, ModelConfig>\n adjustInputTokens?: boolean\n}\n\nexport interface ResolvedProviderConfig {\n name: string\n type: ProviderType\n baseUrl: string\n apiKey: string\n authType: ProviderAuthType\n models?: Record<string, ModelConfig>\n adjustInputTokens?: boolean\n}\n\nconst gpt5ExplorationPrompt = `## Exploration and reading files\n- **Think first.** Before any tool call, decide ALL files/resources you will need.\n- **Batch everything.** If you need multiple files (even from different places), read them together.\n- **multi_tool_use.parallel** Use multi_tool_use.parallel to parallelize tool calls and only this.\n- **Only make sequential calls if you truly cannot know the next file without seeing a result first.**\n- **Workflow:** (a) plan all needed reads → (b) issue one parallel batch → (c) analyze results → (d) repeat if new, unpredictable reads arise.`\n\nconst gpt5CommentaryPrompt = `# Working with the user\n\nYou interact with the user through a terminal. You have 2 ways of communicating with the users: \n- Share intermediary updates in \\`commentary\\` channel. \n- After you have completed all your work, send a message to the \\`final\\` channel. \n\n## Intermediary updates\n\n- Intermediary updates go to the \\`commentary\\` channel.\n- User updates are short updates while you are working, they are NOT final answers.\n- You use 1-2 sentence user updates to communicate progress and new information to the user as you are doing work.\n- Do not begin responses with conversational interjections or meta commentary. Avoid openers such as acknowledgements (“Done —”, “Got it”, “Great question, ”) or framing phrases.\n- You provide user updates frequently, every 20s.\n- Before exploring or doing substantial work, you start with a user update acknowledging the request and explaining your first step. You should include your understanding of the user request and explain what you will do. Avoid commenting on the request or using starters such as \"Got it -\" or \"Understood -\" etc.\n- When exploring, e.g. searching, reading files, you provide user updates as you go, every 20s, explaining what context you are gathering and what you've learned. Vary your sentence structure when providing these updates to avoid sounding repetitive - in particular, don't start each sentence the same way.\n- After you have sufficient context, and the work is substantial, you provide a longer plan (this is the only user update that may be longer than 2 sentences and can contain formatting).\n- Before performing file edits of any kind, you provide updates explaining what edits you are making.\n- As you are thinking, you very frequently provide updates even if not taking any actions, informing the user of your progress. You interrupt your thinking and send multiple updates in a row if thinking for more than 100 words.\n- Tone of your updates MUST match your personality.`\n\nconst defaultConfig: AppConfig = {\n auth: {\n apiKeys: [],\n },\n providers: {},\n extraPrompts: {\n \"gpt-5-mini\": gpt5ExplorationPrompt,\n \"gpt-5.3-codex\": gpt5CommentaryPrompt,\n \"gpt-5.4-mini\": gpt5CommentaryPrompt,\n \"gpt-5.4\": gpt5CommentaryPrompt,\n \"gpt-5.5\": gpt5CommentaryPrompt,\n },\n smallModel: \"gpt-5-mini\",\n responsesApiContextManagementModels: [],\n modelReasoningEfforts: {\n \"gpt-5-mini\": \"low\",\n \"gpt-5.3-codex\": \"xhigh\",\n \"gpt-5.4-mini\": \"xhigh\",\n \"gpt-5.4\": \"xhigh\",\n \"gpt-5.5\": \"xhigh\",\n },\n useFunctionApplyPatch: true,\n useMessagesApi: true,\n useResponsesApiWebSocket: true,\n useResponsesApiWebSearch: true,\n}\n\nlet cachedConfig: AppConfig | null = null\n\nfunction ensureConfigFile(): void {\n try {\n fs.accessSync(PATHS.CONFIG_PATH, fs.constants.R_OK | fs.constants.W_OK)\n } catch {\n fs.mkdirSync(PATHS.APP_DIR, { recursive: true })\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(defaultConfig, null, 2)}\\n`,\n \"utf8\",\n )\n try {\n fs.chmodSync(PATHS.CONFIG_PATH, 0o600)\n } catch {\n return\n }\n }\n}\n\nfunction readConfigFromDisk(): AppConfig {\n ensureConfigFile()\n try {\n const raw = fs.readFileSync(PATHS.CONFIG_PATH, \"utf8\")\n if (!raw.trim()) {\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(defaultConfig, null, 2)}\\n`,\n \"utf8\",\n )\n return defaultConfig\n }\n return JSON.parse(raw) as AppConfig\n } catch (error) {\n consola.error(\"Failed to read config file, using default config\", error)\n return defaultConfig\n }\n}\n\nfunction mergeDefaultConfig(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const extraPrompts = config.extraPrompts ?? {}\n const defaultExtraPrompts = defaultConfig.extraPrompts ?? {}\n const modelReasoningEfforts = config.modelReasoningEfforts ?? {}\n const defaultModelReasoningEfforts = defaultConfig.modelReasoningEfforts ?? {}\n\n const missingExtraPromptModels = Object.keys(defaultExtraPrompts).filter(\n (model) => !Object.hasOwn(extraPrompts, model),\n )\n\n const missingReasoningEffortModels = Object.keys(\n defaultModelReasoningEfforts,\n ).filter((model) => !Object.hasOwn(modelReasoningEfforts, model))\n\n const hasExtraPromptChanges = missingExtraPromptModels.length > 0\n const hasReasoningEffortChanges = missingReasoningEffortModels.length > 0\n\n if (!hasExtraPromptChanges && !hasReasoningEffortChanges) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n extraPrompts: {\n ...defaultExtraPrompts,\n ...extraPrompts,\n },\n modelReasoningEfforts: {\n ...defaultModelReasoningEfforts,\n ...modelReasoningEfforts,\n },\n },\n changed: true,\n }\n}\n\nexport function mergeConfigWithDefaults(): AppConfig {\n const config = readConfigFromDisk()\n const { mergedConfig, changed } = mergeDefaultConfig(config)\n\n if (changed) {\n try {\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(mergedConfig, null, 2)}\\n`,\n \"utf8\",\n )\n } catch (writeError) {\n consola.warn(\n \"Failed to write merged extraPrompts to config file\",\n writeError,\n )\n }\n }\n\n cachedConfig = mergedConfig\n return mergedConfig\n}\n\nexport function getConfig(): AppConfig {\n cachedConfig ??= mergeDefaultConfig(readConfigFromDisk()).mergedConfig\n return cachedConfig\n}\n\nexport function getExtraPromptForModel(model: string): string {\n const config = getConfig()\n return config.extraPrompts?.[model] ?? \"\"\n}\n\nexport function getSmallModel(): string {\n const config = getConfig()\n return config.smallModel ?? \"gpt-5-mini\"\n}\n\nexport function getResponsesApiContextManagementModels(): Array<string> {\n const config = getConfig()\n return (\n config.responsesApiContextManagementModels\n ?? defaultConfig.responsesApiContextManagementModels\n ?? []\n )\n}\n\nexport function isResponsesApiContextManagementModel(model: string): boolean {\n return getResponsesApiContextManagementModels().includes(model)\n}\n\nexport function getReasoningEffortForModel(\n model: string,\n): \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" {\n const config = getConfig()\n return config.modelReasoningEfforts?.[model] ?? \"high\"\n}\n\nexport function normalizeProviderBaseUrl(url: string): string {\n return url.trim().replace(/\\/+$/u, \"\")\n}\n\nfunction getDefaultProviderAuthType(\n providerType: ProviderType,\n): ProviderAuthType {\n return providerType === \"openai-compatible\" ? \"authorization\" : \"x-api-key\"\n}\n\nexport function resolveProviderAuthType(\n providerName: string,\n authType: string | undefined,\n providerType: ProviderType,\n): ProviderAuthType {\n if (authType === undefined) {\n return getDefaultProviderAuthType(providerType)\n }\n\n if (authType === \"x-api-key\") {\n return \"x-api-key\"\n }\n\n if (authType === \"authorization\") {\n return authType\n }\n\n consola.warn(\n `Provider ${providerName} has invalid authType '${authType}', falling back to ${getDefaultProviderAuthType(providerType)}`,\n )\n return getDefaultProviderAuthType(providerType)\n}\n\nexport function getProviderConfig(name: string): ResolvedProviderConfig | null {\n const providerName = name.trim()\n if (!providerName) {\n return null\n }\n\n const config = getConfig()\n const provider = config.providers?.[providerName]\n if (!provider) {\n return null\n }\n\n if (provider.enabled === false) {\n return null\n }\n\n const type = provider.type ?? \"anthropic\"\n if (type !== \"anthropic\" && type !== \"openai-compatible\") {\n consola.warn(\n `Provider ${providerName} is ignored because type '${type}' is not supported`,\n )\n return null\n }\n\n const baseUrl = normalizeProviderBaseUrl(provider.baseUrl ?? \"\")\n const apiKey = (provider.apiKey ?? \"\").trim()\n const authType = resolveProviderAuthType(\n providerName,\n provider.authType,\n type,\n )\n if (!baseUrl || !apiKey) {\n consola.warn(\n `Provider ${providerName} is enabled but missing baseUrl or apiKey`,\n )\n return null\n }\n\n return {\n name: providerName,\n type,\n baseUrl,\n apiKey,\n authType,\n models: provider.models,\n adjustInputTokens: provider.adjustInputTokens,\n }\n}\n\nexport function listEnabledProviders(): Array<string> {\n const config = getConfig()\n const providerNames = Object.keys(config.providers ?? {})\n return providerNames.filter((name) => getProviderConfig(name) !== null)\n}\n\nexport function isMessagesApiEnabled(): boolean {\n const config = getConfig()\n return config.useMessagesApi ?? true\n}\n\nexport function isResponsesApiWebSocketEnabled(): boolean {\n const config = getConfig()\n return config.useResponsesApiWebSocket ?? true\n}\n\nexport function getAnthropicApiKey(): string | undefined {\n const config = getConfig()\n return config.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY ?? undefined\n}\n\nexport function isResponsesApiWebSearchEnabled(): boolean {\n const config = getConfig()\n return config.useResponsesApiWebSearch ?? true\n}\n\nexport function getClaudeTokenMultiplier(): number {\n const config = getConfig()\n return config.claudeTokenMultiplier ?? 1.15\n}\n","import consola from \"consola\"\nimport { getProxyForUrl } from \"proxy-from-env\"\nimport { Agent, ProxyAgent, setGlobalDispatcher, type Dispatcher } from \"undici\"\n\nlet proxyEnvDispatcher: Dispatcher | undefined\n\nexport function getProxyEnvDispatcher(): Dispatcher | undefined {\n return proxyEnvDispatcher\n}\n\nexport function initProxyFromEnv(): void {\n try {\n const direct = new Agent()\n const proxies = new Map<string, ProxyAgent>()\n\n // We only need a minimal dispatcher that implements `dispatch` at runtime.\n // Typing the object as `Dispatcher` forces TypeScript to require many\n // additional methods. Instead, keep a plain object and cast when passing\n // to `setGlobalDispatcher`.\n const dispatcher = {\n dispatch(\n options: Dispatcher.DispatchOptions,\n handler: Dispatcher.DispatchHandler,\n ) {\n try {\n const origin =\n typeof options.origin === \"string\" ?\n new URL(options.origin)\n : (options.origin as URL)\n const get = getProxyForUrl as unknown as (\n u: string,\n ) => string | undefined\n const raw = get(origin.toString())\n const proxyUrl = raw && raw.length > 0 ? raw : undefined\n if (!proxyUrl) {\n consola.debug(`HTTP proxy bypass: ${origin.hostname}`)\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n let agent = proxies.get(proxyUrl)\n if (!agent) {\n agent = new ProxyAgent(proxyUrl)\n proxies.set(proxyUrl, agent)\n }\n let label = proxyUrl\n try {\n const u = new URL(proxyUrl)\n label = `${u.protocol}//${u.host}`\n } catch {\n /* noop */\n }\n consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`)\n return (agent as unknown as Dispatcher).dispatch(options, handler)\n } catch {\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n },\n close() {\n return direct.close()\n },\n destroy() {\n return direct.destroy()\n },\n }\n\n proxyEnvDispatcher = dispatcher as unknown as Dispatcher\n\n if (typeof Bun !== \"undefined\") {\n consola.debug(\"WebSocket proxy configured from environment (per-URL)\")\n return\n }\n\n setGlobalDispatcher(proxyEnvDispatcher)\n consola.debug(\"HTTP proxy configured from environment (per-URL)\")\n } catch (err) {\n consola.debug(\"Proxy setup skipped:\", err)\n }\n}\n"],"mappings":"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"}
@@ -1,9 +1,10 @@
1
1
  import { t as PATHS } from "./paths-DC-mqCY3.js";
2
- import { A as compactAutoContinuePromptStarts, C as prepareForCompact, D as requestContext, E as generateTraceId, F as state, N as compactSystemPromptStarts, O as resolveTraceId$1, T as prepareMessageProxyHeaders, c as getUUID, d as sleep, f as getCopilotUsage, g as copilotHeaders, h as copilotBaseUrl, j as compactMessageSections, l as isNullish, m as forwardError, n as cacheModels, o as generateRequestIdFromPayload, p as HTTPError, s as getRootSessionId, u as parseUserIdMetadata, w as prepareInteractionHeaders } from "./utils-Cj-ToKA6.js";
3
- import { a as getProviderConfig, c as isMessagesApiEnabled, i as getExtraPromptForModel, l as isResponsesApiContextManagementModel, n as getClaudeTokenMultiplier, o as getReasoningEffortForModel, r as getConfig, s as getSmallModel, t as getAnthropicApiKey, u as isResponsesApiWebSearchEnabled } from "./config-DrfmMOO-.js";
2
+ import { D as generateTraceId, E as prepareMessageProxyHeaders, I as state, M as compactMessageSections, O as requestContext, P as compactSystemPromptStarts, T as prepareInteractionHeaders, _ as copilotWebSocketHeaders, c as getUUID, d as sleep, f as getCopilotUsage, g as copilotHeaders, h as copilotBaseUrl, j as compactAutoContinuePromptStarts, k as resolveTraceId$1, l as isNullish, m as forwardError, n as cacheModels, o as generateRequestIdFromPayload, p as HTTPError, s as getRootSessionId, u as parseUserIdMetadata, w as prepareForCompact } from "./utils-C5ej0z8n.js";
3
+ import { a as getConfig, c as getReasoningEffortForModel, d as isResponsesApiContextManagementModel, f as isResponsesApiWebSearchEnabled, i as getClaudeTokenMultiplier, l as getSmallModel, o as getExtraPromptForModel, p as isResponsesApiWebSocketEnabled, r as getAnthropicApiKey, s as getProviderConfig, t as getProxyEnvDispatcher, u as isMessagesApiEnabled } from "./proxy-De0Po8kG.js";
4
4
  import consola from "consola";
5
5
  import fs from "node:fs/promises";
6
6
  import path from "node:path";
7
+ import { createHash } from "node:crypto";
7
8
  import { Hono } from "hono";
8
9
  import { cors } from "hono/cors";
9
10
  import { logger } from "hono/logger";
@@ -11,6 +12,7 @@ import fs$1, { readFileSync } from "node:fs";
11
12
  import { streamSSE } from "hono/streaming";
12
13
  import util from "node:util";
13
14
  import { events } from "fetch-event-stream";
15
+ import { WebSocket } from "undici";
14
16
  //#region src/lib/request-auth.ts
15
17
  function normalizeApiKeys(apiKeys) {
16
18
  if (!Array.isArray(apiKeys)) {
@@ -831,10 +833,14 @@ const copilotRateLimitHeaders = {
831
833
  session: "x-usage-ratelimit-session",
832
834
  weekly: "x-usage-ratelimit-weekly"
833
835
  };
836
+ const copilotQuotaSnapshotKeys = {
837
+ session: "5Hour-Session-RateLimits",
838
+ weekly: "Weekly-Session-RateLimits"
839
+ };
834
840
  const hasGetMethod = (headers) => {
835
841
  return "get" in headers && typeof headers.get === "function";
836
842
  };
837
- const getHeaderValue = (headers, headerName) => {
843
+ const getHeaderValue$1 = (headers, headerName) => {
838
844
  if (hasGetMethod(headers)) return headers.get(headerName);
839
845
  const normalizedHeaderName = headerName.toLowerCase();
840
846
  return Object.entries(headers).find(([key]) => key.toLowerCase() === normalizedHeaderName)?.[1] ?? null;
@@ -851,7 +857,7 @@ const parseCopilotRateLimitHeader = (headerValue) => {
851
857
  };
852
858
  const getCopilotRateLimitUsage = (headers, type) => {
853
859
  const headerName = copilotRateLimitHeaders[type];
854
- const headerValue = getHeaderValue(headers, headerName);
860
+ const headerValue = getHeaderValue$1(headers, headerName);
855
861
  if (!headerValue) return null;
856
862
  const parsed = parseCopilotRateLimitHeader(headerValue);
857
863
  if (!parsed) return null;
@@ -860,15 +866,39 @@ const getCopilotRateLimitUsage = (headers, type) => {
860
866
  ...parsed
861
867
  };
862
868
  };
869
+ const getCopilotRateLimitUsageFromSnapshots = (snapshots, type) => {
870
+ const snapshot = snapshots?.[copilotQuotaSnapshotKeys[type]];
871
+ if (!isCopilotQuotaSnapshot(snapshot)) return null;
872
+ return {
873
+ remaining: String(snapshot.percent_remaining),
874
+ resetAt: snapshot.reset_date,
875
+ type
876
+ };
877
+ };
863
878
  const logCopilotRateLimits = (headers) => {
864
879
  for (const type of copilotRateLimitTypes) {
865
880
  const usage = getCopilotRateLimitUsage(headers, type);
866
881
  if (!usage) continue;
867
- const d = new Date(usage.resetAt);
868
- const dateStr = Number.isNaN(d.getTime()) ? usage.resetAt : d.toLocaleString();
869
- consola.info(`Copilot ${usage.type} quota remaining: ${usage.remaining}, resets at: ${dateStr}`);
882
+ logCopilotRateLimitUsage(usage);
883
+ }
884
+ };
885
+ const logCopilotQuotaSnapshots = (snapshots) => {
886
+ for (const type of copilotRateLimitTypes) {
887
+ const usage = getCopilotRateLimitUsageFromSnapshots(snapshots, type);
888
+ if (!usage) continue;
889
+ logCopilotRateLimitUsage(usage);
870
890
  }
871
891
  };
892
+ const logCopilotRateLimitUsage = (usage) => {
893
+ const d = new Date(usage.resetAt);
894
+ const dateStr = Number.isNaN(d.getTime()) ? usage.resetAt : d.toLocaleString();
895
+ consola.info(`Copilot ${usage.type} quota remaining: ${usage.remaining}, resets at: ${dateStr}`);
896
+ };
897
+ const isCopilotQuotaSnapshot = (value) => {
898
+ if (!value || typeof value !== "object") return false;
899
+ const record = value;
900
+ return typeof record.entitlement === "string" && typeof record.percent_remaining === "number" && typeof record.overage_permitted === "boolean" && typeof record.overage_count === "number" && typeof record.reset_date === "string";
901
+ };
872
902
  //#endregion
873
903
  //#region src/services/copilot/create-chat-completions.ts
874
904
  const createChatCompletions = async (payload, options) => {
@@ -2426,9 +2456,76 @@ const adjustInputTokens = (providerConfig, usage) => {
2426
2456
  usage.input_tokens = Math.max(0, (usage.input_tokens ?? 0) - (usage.cache_read_input_tokens ?? 0) - (usage.cache_creation_input_tokens ?? 0));
2427
2457
  debugJson(logger$4, "provider.messages.adjusted_usage:", usage);
2428
2458
  };
2459
+ const responsesUtilsDependencies = {
2460
+ isResponsesApiContextManagementModel,
2461
+ isResponsesApiWebSocketEnabled
2462
+ };
2463
+ const getResponsesRequestOptions = (payload) => {
2464
+ return {
2465
+ vision: hasVisionInput(payload),
2466
+ initiator: hasAgentInitiator(payload) ? "agent" : "user"
2467
+ };
2468
+ };
2469
+ const getResponsesTransportForModel = (selectedModel, options = {}) => {
2470
+ const supportedEndpoints = selectedModel?.supported_endpoints ?? [];
2471
+ const useWebSocket = responsesUtilsDependencies.isResponsesApiWebSocketEnabled();
2472
+ if (options.compactType !== 1 && useWebSocket && supportedEndpoints.includes("ws:/responses")) return "websocket";
2473
+ if (supportedEndpoints.includes("/responses")) return "http";
2474
+ return null;
2475
+ };
2476
+ const hasAgentInitiator = (payload) => {
2477
+ const lastItem = getPayloadItems(payload).at(-1);
2478
+ if (!lastItem) return false;
2479
+ if (!("role" in lastItem) || !lastItem.role) return true;
2480
+ return (typeof lastItem.role === "string" ? lastItem.role.toLowerCase() : "") === "assistant";
2481
+ };
2482
+ const hasVisionInput = (payload) => {
2483
+ return getPayloadItems(payload).some((item) => containsVisionContent(item));
2484
+ };
2485
+ const resolveResponsesCompactThreshold = (maxPromptTokens) => {
2486
+ if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * .9);
2487
+ return 5e4;
2488
+ };
2489
+ const createCompactionContextManagement = (compactThreshold) => [{
2490
+ type: "compaction",
2491
+ compact_threshold: compactThreshold
2492
+ }];
2493
+ const applyResponsesApiContextManagement = (payload, maxPromptTokens) => {
2494
+ if (payload.context_management !== void 0) return;
2495
+ if (!responsesUtilsDependencies.isResponsesApiContextManagementModel(payload.model)) return;
2496
+ payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens));
2497
+ };
2498
+ const compactInputByLatestCompaction = (payload) => {
2499
+ if (!Array.isArray(payload.input) || payload.input.length === 0) return;
2500
+ const latestCompactionMessageIndex = getLatestCompactionMessageIndex(payload.input);
2501
+ if (latestCompactionMessageIndex === void 0) return;
2502
+ payload.input = payload.input.slice(latestCompactionMessageIndex);
2503
+ };
2504
+ const getLatestCompactionMessageIndex = (input) => {
2505
+ for (let index = input.length - 1; index >= 0; index -= 1) if (isCompactionInputItem(input[index])) return index;
2506
+ };
2507
+ const isCompactionInputItem = (value) => {
2508
+ return "type" in value && typeof value.type === "string" && value.type === "compaction";
2509
+ };
2510
+ const getPayloadItems = (payload) => {
2511
+ const result = [];
2512
+ const { input } = payload;
2513
+ if (Array.isArray(input)) result.push(...input);
2514
+ return result;
2515
+ };
2516
+ const containsVisionContent = (value) => {
2517
+ if (!value) return false;
2518
+ if (Array.isArray(value)) return value.some((entry) => containsVisionContent(entry));
2519
+ if (typeof value !== "object") return false;
2520
+ const record = value;
2521
+ if ((typeof record.type === "string" ? record.type.toLowerCase() : void 0) === "input_image") return true;
2522
+ if (Array.isArray(record.content)) return record.content.some((entry) => containsVisionContent(entry));
2523
+ return false;
2524
+ };
2429
2525
  //#endregion
2430
2526
  //#region src/services/copilot/create-responses.ts
2431
- const createResponses = async (payload, { vision, initiator, subagentMarker, requestId, sessionId, compactType }) => {
2527
+ const RESPONSES_WEBSOCKET_IDLE_TIMEOUT_MS = 6e4;
2528
+ const createResponses = async (payload, { vision, initiator, subagentMarker, requestId, sessionId, compactType, transport = "http" }) => {
2432
2529
  if (!state.copilotToken) throw new Error("Copilot token not found");
2433
2530
  const headers = {
2434
2531
  ...copilotHeaders(state, requestId, vision),
@@ -2438,6 +2535,17 @@ const createResponses = async (payload, { vision, initiator, subagentMarker, req
2438
2535
  prepareForCompact(headers, compactType);
2439
2536
  payload.service_tier = void 0;
2440
2537
  consola.log(`<-- model: ${payload.model}`);
2538
+ if ((compactType === 1 ? "http" : transport) === "websocket") {
2539
+ const stream = createPooledResponsesWebSocketStream(prepareResponsesWebSocketRequest(payload, headers, {
2540
+ requestId,
2541
+ subagentMarker
2542
+ }));
2543
+ if (payload.stream) return stream;
2544
+ return await consumeResponsesWebSocketStream(stream);
2545
+ }
2546
+ return await createHttpResponses(payload, headers);
2547
+ };
2548
+ const createHttpResponses = async (payload, headers) => {
2441
2549
  const response = await fetch(`${copilotBaseUrl(state)}/responses`, {
2442
2550
  method: "POST",
2443
2551
  headers,
@@ -2451,6 +2559,264 @@ const createResponses = async (payload, { vision, initiator, subagentMarker, req
2451
2559
  if (payload.stream) return events(response);
2452
2560
  return await response.json();
2453
2561
  };
2562
+ const prepareResponsesWebSocketRequest = (payload, preparedHeaders, options) => {
2563
+ const initiator = getResponsesWebSocketInitiator(preparedHeaders);
2564
+ return {
2565
+ headers: copilotWebSocketHeaders(preparedHeaders),
2566
+ poolKey: buildResponsesWebSocketPoolKey(payload, options),
2567
+ payload: buildResponsesWebSocketPayload(payload, initiator)
2568
+ };
2569
+ };
2570
+ const buildResponsesWebSocketPoolKey = (payload, { requestId, subagentMarker }) => {
2571
+ const tokenFingerprint = state.copilotToken ? createHash("sha256").update(state.copilotToken).digest("hex").slice(0, 16) : "missing-token";
2572
+ const subagentKey = subagentMarker ? [
2573
+ subagentMarker.session_id,
2574
+ subagentMarker.agent_id,
2575
+ subagentMarker.agent_type
2576
+ ].join(":") : "main";
2577
+ return [
2578
+ tokenFingerprint,
2579
+ payload.model,
2580
+ requestId,
2581
+ subagentKey
2582
+ ].map(encodePoolKeyPart).join("|");
2583
+ };
2584
+ const getResponsesWebSocketInitiator = (preparedHeaders) => {
2585
+ return getHeaderValue(preparedHeaders, "x-initiator")?.toLowerCase() === "agent" ? "agent" : "user";
2586
+ };
2587
+ const createPooledResponsesWebSocketStream = (request) => runResponsesWebSocketPoolRequest(request);
2588
+ const buildResponsesWebSocketPayload = (payload, initiator) => {
2589
+ const websocketPayload = {
2590
+ ...payload,
2591
+ type: "response.create",
2592
+ initiator
2593
+ };
2594
+ delete websocketPayload.stream;
2595
+ delete websocketPayload["background"];
2596
+ delete websocketPayload.service_tier;
2597
+ return websocketPayload;
2598
+ };
2599
+ const buildResponsesWebSocketUrl = (baseUrl) => {
2600
+ const url = new URL(`${baseUrl.replace(/\/+$/u, "")}/responses`);
2601
+ if (url.protocol === "https:") url.protocol = "wss:";
2602
+ else if (url.protocol === "http:") url.protocol = "ws:";
2603
+ return url.toString();
2604
+ };
2605
+ const responsesWebSocketPool = /* @__PURE__ */ new Map();
2606
+ const runResponsesWebSocketPoolRequest = async function* (request) {
2607
+ const entry = getResponsesWebSocketPoolEntry(request);
2608
+ const release = await acquireResponsesWebSocketPoolEntry(request.poolKey, entry);
2609
+ try {
2610
+ const websocket = await entry.websocketPromise;
2611
+ websocket.send(JSON.stringify(request.payload));
2612
+ for await (const data of createWebSocketMessageStream(websocket)) {
2613
+ const chunk = createResponsesWebSocketStreamChunk(data);
2614
+ yield chunk;
2615
+ if (isTerminalResponsesStreamChunk(chunk)) return;
2616
+ }
2617
+ removeResponsesWebSocketPoolEntry(request.poolKey, entry);
2618
+ throw new Error("Responses websocket ended without a terminal response");
2619
+ } catch (error) {
2620
+ removeResponsesWebSocketPoolEntry(request.poolKey, entry);
2621
+ throw toError(error);
2622
+ } finally {
2623
+ release();
2624
+ }
2625
+ };
2626
+ const getResponsesWebSocketPoolEntry = (request) => {
2627
+ const existing = responsesWebSocketPool.get(request.poolKey);
2628
+ if (existing && !existing.closed) {
2629
+ clearResponsesWebSocketIdleTimer(existing);
2630
+ return existing;
2631
+ }
2632
+ const entry = createResponsesWebSocketPoolEntry(request);
2633
+ responsesWebSocketPool.set(request.poolKey, entry);
2634
+ return entry;
2635
+ };
2636
+ const createResponsesWebSocketPoolEntry = (request) => {
2637
+ const entry = {
2638
+ closed: false,
2639
+ idleTimer: null,
2640
+ lock: Promise.resolve(),
2641
+ websocketPromise: openResponsesWebSocket({
2642
+ headers: request.headers,
2643
+ url: buildResponsesWebSocketUrl(copilotBaseUrl(state))
2644
+ })
2645
+ };
2646
+ entry.websocketPromise.then((websocket) => {
2647
+ websocket.addEventListener("close", () => {
2648
+ removeResponsesWebSocketPoolEntry(request.poolKey, entry);
2649
+ });
2650
+ websocket.addEventListener("error", () => {
2651
+ removeResponsesWebSocketPoolEntry(request.poolKey, entry);
2652
+ });
2653
+ }).catch(() => {
2654
+ removeResponsesWebSocketPoolEntry(request.poolKey, entry);
2655
+ });
2656
+ return entry;
2657
+ };
2658
+ const acquireResponsesWebSocketPoolEntry = async (poolKey, entry) => {
2659
+ clearResponsesWebSocketIdleTimer(entry);
2660
+ let releaseCurrent;
2661
+ const previousLock = entry.lock;
2662
+ entry.lock = new Promise((resolve) => {
2663
+ releaseCurrent = resolve;
2664
+ });
2665
+ await previousLock;
2666
+ clearResponsesWebSocketIdleTimer(entry);
2667
+ let released = false;
2668
+ return () => {
2669
+ if (released) return;
2670
+ released = true;
2671
+ releaseCurrent();
2672
+ if (!entry.closed) scheduleResponsesWebSocketIdleClose(poolKey, entry);
2673
+ };
2674
+ };
2675
+ const scheduleResponsesWebSocketIdleClose = (poolKey, entry) => {
2676
+ clearResponsesWebSocketIdleTimer(entry);
2677
+ entry.idleTimer = setTimeout(() => {
2678
+ removeResponsesWebSocketPoolEntry(poolKey, entry);
2679
+ }, RESPONSES_WEBSOCKET_IDLE_TIMEOUT_MS);
2680
+ unrefTimer(entry.idleTimer);
2681
+ };
2682
+ const clearResponsesWebSocketIdleTimer = (entry) => {
2683
+ if (entry.idleTimer) {
2684
+ clearTimeout(entry.idleTimer);
2685
+ entry.idleTimer = null;
2686
+ }
2687
+ };
2688
+ const removeResponsesWebSocketPoolEntry = (poolKey, entry) => {
2689
+ if (responsesWebSocketPool.get(poolKey) !== entry) return;
2690
+ responsesWebSocketPool.delete(poolKey);
2691
+ entry.closed = true;
2692
+ clearResponsesWebSocketIdleTimer(entry);
2693
+ entry.websocketPromise.then(closeResponsesWebSocket).catch(() => {});
2694
+ };
2695
+ const unrefTimer = (timer) => {
2696
+ if (typeof timer === "object" && "unref" in timer && typeof timer.unref === "function") timer.unref();
2697
+ };
2698
+ const openResponsesWebSocket = async ({ headers, url }) => await new Promise((resolve, reject) => {
2699
+ const dispatcher = getProxyEnvDispatcher();
2700
+ const websocket = new WebSocket(url, dispatcher ? {
2701
+ dispatcher,
2702
+ headers
2703
+ } : { headers });
2704
+ const cleanup = () => {
2705
+ websocket.removeEventListener("open", onOpen);
2706
+ websocket.removeEventListener("error", onError);
2707
+ };
2708
+ const onOpen = () => {
2709
+ cleanup();
2710
+ resolve(websocket);
2711
+ };
2712
+ const onError = () => {
2713
+ cleanup();
2714
+ reject(/* @__PURE__ */ new Error("Failed to create responses websocket"));
2715
+ };
2716
+ websocket.addEventListener("open", onOpen);
2717
+ websocket.addEventListener("error", onError);
2718
+ });
2719
+ const createWebSocketMessageStream = async function* (websocket) {
2720
+ const queue = [];
2721
+ let closed = false;
2722
+ let error = null;
2723
+ let notify = null;
2724
+ const wake = () => {
2725
+ notify?.();
2726
+ notify = null;
2727
+ };
2728
+ const onMessage = (event) => {
2729
+ queue.push(normalizeWebSocketMessageData(event.data));
2730
+ wake();
2731
+ };
2732
+ const onClose = () => {
2733
+ closed = true;
2734
+ wake();
2735
+ };
2736
+ const onError = () => {
2737
+ error = /* @__PURE__ */ new Error("Responses websocket stream error");
2738
+ wake();
2739
+ };
2740
+ websocket.addEventListener("message", onMessage);
2741
+ websocket.addEventListener("close", onClose);
2742
+ websocket.addEventListener("error", onError);
2743
+ try {
2744
+ while (true) {
2745
+ const item = queue.shift();
2746
+ if (item) {
2747
+ yield await item;
2748
+ continue;
2749
+ }
2750
+ if (error) throw toError(error);
2751
+ if (closed) break;
2752
+ await new Promise((resolve) => {
2753
+ notify = resolve;
2754
+ });
2755
+ }
2756
+ } finally {
2757
+ websocket.removeEventListener("message", onMessage);
2758
+ websocket.removeEventListener("close", onClose);
2759
+ websocket.removeEventListener("error", onError);
2760
+ }
2761
+ };
2762
+ const normalizeWebSocketMessageData = async (data) => {
2763
+ if (typeof data === "string") return data;
2764
+ if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);
2765
+ if (ArrayBuffer.isView(data)) {
2766
+ const view = data;
2767
+ return new TextDecoder().decode(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
2768
+ }
2769
+ if (isTextReadable(data)) return await data.text();
2770
+ return String(data);
2771
+ };
2772
+ const isTextReadable = (value) => {
2773
+ if (!value || typeof value !== "object" || !("text" in value)) return false;
2774
+ return typeof value.text === "function";
2775
+ };
2776
+ const toError = (value) => {
2777
+ if (value instanceof Error) return value;
2778
+ return new Error(String(value));
2779
+ };
2780
+ const getHeaderValue = (headers, headerName) => {
2781
+ const normalizedHeaderName = headerName.toLowerCase();
2782
+ return Object.entries(headers).find(([key]) => key.toLowerCase() === normalizedHeaderName)?.[1];
2783
+ };
2784
+ const encodePoolKeyPart = (value) => encodeURIComponent(value);
2785
+ const createResponsesWebSocketStreamChunk = (data) => {
2786
+ if (data === "[DONE]") return { data };
2787
+ try {
2788
+ const parsed = JSON.parse(data);
2789
+ if (parsed.type === "response.completed") logCopilotQuotaSnapshots(parsed.copilot_quota_snapshots);
2790
+ return {
2791
+ data: JSON.stringify(parsed),
2792
+ event: typeof parsed.type === "string" ? parsed.type : void 0,
2793
+ id: typeof parsed.id === "string" ? parsed.id : void 0
2794
+ };
2795
+ } catch {
2796
+ return { data };
2797
+ }
2798
+ };
2799
+ const isTerminalResponsesStreamChunk = (chunk) => {
2800
+ if (!chunk.data || chunk.data === "[DONE]") return false;
2801
+ try {
2802
+ const parsed = JSON.parse(chunk.data);
2803
+ return parsed.type === "response.completed" || parsed.type === "response.failed" || parsed.type === "response.incomplete" || parsed.type === "error";
2804
+ } catch {
2805
+ return false;
2806
+ }
2807
+ };
2808
+ const consumeResponsesWebSocketStream = async (stream) => {
2809
+ for await (const chunk of stream) {
2810
+ if (!chunk.data || chunk.data === "[DONE]") continue;
2811
+ const event = JSON.parse(chunk.data);
2812
+ if (event.type === "error") throw new Error(event.message);
2813
+ if (event.type === "response.completed" || event.type === "response.failed" || event.type === "response.incomplete") return event.response;
2814
+ }
2815
+ throw new Error("Responses websocket ended without a terminal response");
2816
+ };
2817
+ const closeResponsesWebSocket = (websocket) => {
2818
+ if (websocket.readyState === WebSocket.CONNECTING || websocket.readyState === WebSocket.OPEN) websocket.close();
2819
+ };
2454
2820
  //#endregion
2455
2821
  //#region src/routes/messages/responses-translation.ts
2456
2822
  const MESSAGE_TYPE = "message";
@@ -3307,63 +3673,6 @@ const extractFunctionCallDetails = (rawEvent) => {
3307
3673
  };
3308
3674
  };
3309
3675
  //#endregion
3310
- //#region src/routes/responses/utils.ts
3311
- const getResponsesRequestOptions = (payload) => {
3312
- return {
3313
- vision: hasVisionInput(payload),
3314
- initiator: hasAgentInitiator(payload) ? "agent" : "user"
3315
- };
3316
- };
3317
- const hasAgentInitiator = (payload) => {
3318
- const lastItem = getPayloadItems(payload).at(-1);
3319
- if (!lastItem) return false;
3320
- if (!("role" in lastItem) || !lastItem.role) return true;
3321
- return (typeof lastItem.role === "string" ? lastItem.role.toLowerCase() : "") === "assistant";
3322
- };
3323
- const hasVisionInput = (payload) => {
3324
- return getPayloadItems(payload).some((item) => containsVisionContent(item));
3325
- };
3326
- const resolveResponsesCompactThreshold = (maxPromptTokens) => {
3327
- if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * .9);
3328
- return 5e4;
3329
- };
3330
- const createCompactionContextManagement = (compactThreshold) => [{
3331
- type: "compaction",
3332
- compact_threshold: compactThreshold
3333
- }];
3334
- const applyResponsesApiContextManagement = (payload, maxPromptTokens) => {
3335
- if (payload.context_management !== void 0) return;
3336
- if (!isResponsesApiContextManagementModel(payload.model)) return;
3337
- payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens));
3338
- };
3339
- const compactInputByLatestCompaction = (payload) => {
3340
- if (!Array.isArray(payload.input) || payload.input.length === 0) return;
3341
- const latestCompactionMessageIndex = getLatestCompactionMessageIndex(payload.input);
3342
- if (latestCompactionMessageIndex === void 0) return;
3343
- payload.input = payload.input.slice(latestCompactionMessageIndex);
3344
- };
3345
- const getLatestCompactionMessageIndex = (input) => {
3346
- for (let index = input.length - 1; index >= 0; index -= 1) if (isCompactionInputItem(input[index])) return index;
3347
- };
3348
- const isCompactionInputItem = (value) => {
3349
- return "type" in value && typeof value.type === "string" && value.type === "compaction";
3350
- };
3351
- const getPayloadItems = (payload) => {
3352
- const result = [];
3353
- const { input } = payload;
3354
- if (Array.isArray(input)) result.push(...input);
3355
- return result;
3356
- };
3357
- const containsVisionContent = (value) => {
3358
- if (!value) return false;
3359
- if (Array.isArray(value)) return value.some((entry) => containsVisionContent(entry));
3360
- if (typeof value !== "object") return false;
3361
- const record = value;
3362
- if ((typeof record.type === "string" ? record.type.toLowerCase() : void 0) === "input_image") return true;
3363
- if (Array.isArray(record.content)) return record.content.some((entry) => containsVisionContent(entry));
3364
- return false;
3365
- };
3366
- //#endregion
3367
3676
  //#region src/services/copilot/create-messages.ts
3368
3677
  const INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
3369
3678
  const allowedAnthropicBetas = new Set([
@@ -3657,6 +3966,11 @@ const prepareMessagesApiPayload = (payload, selectedModel) => {
3657
3966
  const COPILOT_CONTEXT_CACHE_SYSTEM_MARKER_LIMIT = 2;
3658
3967
  const COPILOT_CONTEXT_CACHE_NON_SYSTEM_MARKER_LIMIT = 2;
3659
3968
  const COPILOT_CONTEXT_CACHE_CONTROL = { type: "ephemeral" };
3969
+ const messagesApiFlowDependencies = {
3970
+ createChatCompletions,
3971
+ createMessages,
3972
+ createResponses
3973
+ };
3660
3974
  const handleWithChatCompletions = async (c, anthropicPayload, options) => {
3661
3975
  const { logger, subagentMarker, requestId, sessionId, compactType } = options;
3662
3976
  const openAIPayload = translateToOpenAI(anthropicPayload);
@@ -3668,7 +3982,7 @@ const handleWithChatCompletions = async (c, anthropicPayload, options) => {
3668
3982
  payload: anthropicPayload
3669
3983
  });
3670
3984
  debugJson(logger, "Translated OpenAI request payload:", openAIPayload);
3671
- const response = await createChatCompletions(openAIPayload, {
3985
+ const response = await messagesApiFlowDependencies.createChatCompletions(openAIPayload, {
3672
3986
  subagentMarker,
3673
3987
  requestId,
3674
3988
  sessionId,
@@ -3731,9 +4045,11 @@ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
3731
4045
  compactInputByLatestCompaction(responsesPayload);
3732
4046
  debugJson(logger, "Translated Responses payload:", responsesPayload);
3733
4047
  const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
3734
- const response = await createResponses(responsesPayload, {
4048
+ const transport = getResponsesTransportForModel(selectedModel, { compactType: requestOptions.compactType }) ?? "http";
4049
+ const response = await messagesApiFlowDependencies.createResponses(responsesPayload, {
3735
4050
  vision,
3736
4051
  initiator,
4052
+ transport,
3737
4053
  ...requestOptions
3738
4054
  });
3739
4055
  if (responsesPayload.stream && isAsyncIterable$1(response)) {
@@ -3798,7 +4114,7 @@ const handleWithMessagesApi = async (c, anthropicPayload, options) => {
3798
4114
  payload: anthropicPayload
3799
4115
  });
3800
4116
  debugJson(logger, "Translated Messages payload:", anthropicPayload);
3801
- const response = await createMessages(anthropicPayload, anthropicBetaHeader, {
4117
+ const response = await messagesApiFlowDependencies.createMessages(anthropicPayload, anthropicBetaHeader, {
3802
4118
  subagentMarker,
3803
4119
  requestId,
3804
4120
  sessionId,
@@ -3961,7 +4277,7 @@ async function handleCompletion(c) {
3961
4277
  compactType,
3962
4278
  logger: logger$3
3963
4279
  });
3964
- if (shouldUseResponsesApi(selectedModel)) return await messagesFlowHandlers.handleWithResponsesApi(c, anthropicPayload, {
4280
+ if (shouldUseResponsesApi(selectedModel, compactType)) return await messagesFlowHandlers.handleWithResponsesApi(c, anthropicPayload, {
3965
4281
  subagentMarker,
3966
4282
  selectedModel,
3967
4283
  requestId,
@@ -3977,10 +4293,9 @@ async function handleCompletion(c) {
3977
4293
  logger: logger$3
3978
4294
  });
3979
4295
  }
3980
- const RESPONSES_ENDPOINT$1 = "/responses";
3981
4296
  const MESSAGES_ENDPOINT = "/v1/messages";
3982
- const shouldUseResponsesApi = (selectedModel) => {
3983
- return selectedModel?.supported_endpoints?.includes(RESPONSES_ENDPOINT$1) ?? false;
4297
+ const shouldUseResponsesApi = (selectedModel, compactType) => {
4298
+ return Boolean(getResponsesTransportForModel(selectedModel, { compactType }));
3984
4299
  };
3985
4300
  const shouldUseMessagesApi = (selectedModel) => {
3986
4301
  if (!isMessagesApiEnabled()) return false;
@@ -4113,9 +4428,14 @@ const handleItemId = (parsed, tracker) => {
4113
4428
  //#endregion
4114
4429
  //#region src/routes/responses/handler.ts
4115
4430
  const logger$1 = createHandlerLogger("responses-handler");
4116
- const RESPONSES_ENDPOINT = "/responses";
4431
+ const responsesHandlerDependencies = {
4432
+ checkRateLimit,
4433
+ createResponses,
4434
+ getConfig,
4435
+ isResponsesApiWebSearchEnabled
4436
+ };
4117
4437
  const handleResponses = async (c) => {
4118
- await checkRateLimit(state);
4438
+ await responsesHandlerDependencies.checkRateLimit(state);
4119
4439
  const payload = await c.req.json();
4120
4440
  debugJson(logger$1, "Responses request payload:", payload);
4121
4441
  const requestId = generateRequestIdFromPayload({ messages: payload.input });
@@ -4129,10 +4449,11 @@ const handleResponses = async (c) => {
4129
4449
  });
4130
4450
  useFunctionApplyPatch(payload);
4131
4451
  removeUnsupportedTools(payload);
4132
- if (!isResponsesApiWebSearchEnabled()) removeWebSearchTool(payload);
4452
+ if (!responsesHandlerDependencies.isResponsesApiWebSearchEnabled()) removeWebSearchTool(payload);
4133
4453
  compactInputByLatestCompaction(payload);
4134
4454
  const selectedModel = state.models?.data.find((model) => model.id === payload.model);
4135
- if (!(selectedModel?.supported_endpoints?.includes(RESPONSES_ENDPOINT) ?? false)) return c.json({ error: {
4455
+ const responsesTransport = getResponsesTransportForModel(selectedModel);
4456
+ if (!responsesTransport) return c.json({ error: {
4136
4457
  message: "This model does not support the responses endpoint. Please choose a different model.",
4137
4458
  type: "invalid_request_error"
4138
4459
  } }, 400);
@@ -4140,11 +4461,12 @@ const handleResponses = async (c) => {
4140
4461
  debugJson(logger$1, "Translated Responses payload:", payload);
4141
4462
  const { vision, initiator } = getResponsesRequestOptions(payload);
4142
4463
  if (state.manualApprove) await awaitApproval();
4143
- const response = await createResponses(payload, {
4464
+ const response = await responsesHandlerDependencies.createResponses(payload, {
4144
4465
  vision,
4145
4466
  initiator,
4146
4467
  requestId,
4147
- sessionId
4468
+ sessionId,
4469
+ transport: responsesTransport
4148
4470
  });
4149
4471
  if (isStreamingRequested(payload) && isAsyncIterable(response)) {
4150
4472
  logger$1.debug("Forwarding native Responses stream");
@@ -4184,7 +4506,7 @@ const parseResponsesStreamEvent = (chunk) => {
4184
4506
  }
4185
4507
  };
4186
4508
  const useFunctionApplyPatch = (payload) => {
4187
- if (getConfig().useFunctionApplyPatch ?? true) {
4509
+ if (responsesHandlerDependencies.getConfig().useFunctionApplyPatch ?? true) {
4188
4510
  logger$1.debug("Using function tool apply_patch for responses");
4189
4511
  if (Array.isArray(payload.tools)) {
4190
4512
  const toolsArr = payload.tools;
@@ -4327,4 +4649,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
4327
4649
  //#endregion
4328
4650
  export { server };
4329
4651
 
4330
- //# sourceMappingURL=server-DkUKa2I6.js.map
4652
+ //# sourceMappingURL=server-BnKth1Jp.js.map