UNPKG

copilot-proxy-api

Version:

Self-hosted GitHub Copilot bridge for Claude Code and Codex CLI with OpenAI Responses, Anthropic Messages, streaming resilience, and context management.

1 lines 241 kB
{"version":3,"file":"main.mjs","names":["process","handleCompletion","isNonStreaming","handleCompletion","CHARS_PER_TOKEN_ESTIMATE","TOKEN_RESERVE","IMAGE_STRIPPED_PLACEHOLDER"],"sources":["../src/lib/paths.ts","../src/lib/state.ts","../src/lib/api-config.ts","../src/services/github/get-copilot-token.ts","../src/services/github/get-device-code.ts","../src/services/github/get-user.ts","../src/services/copilot/get-models.ts","../src/services/get-vscode-version.ts","../src/lib/utils.ts","../src/services/github/poll-access-token.ts","../src/lib/token.ts","../src/auth.ts","../src/services/github/get-copilot-usage.ts","../src/check-usage.ts","../src/debug.ts","../src/lib/local-auth.ts","../src/lib/proxy.ts","../src/lib/shell.ts","../src/lib/request-trace.ts","../src/lib/approval.ts","../src/lib/rate-limit.ts","../src/lib/tokenizer.ts","../src/lib/copilot-fetch.ts","../src/lib/model-limits.ts","../src/lib/prompt-too-long.ts","../src/services/copilot/create-chat-completions.ts","../src/routes/chat-completions/handler.ts","../src/routes/chat-completions/route.ts","../src/routes/debug/route.ts","../src/services/copilot/create-embeddings.ts","../src/routes/embeddings/route.ts","../src/routes/messages/utils.ts","../src/routes/messages/non-stream-translation.ts","../src/routes/messages/count-tokens-handler.ts","../src/lib/context-manager.ts","../src/services/copilot/encrypted-output-recovery.ts","../src/services/copilot/create-responses.ts","../src/routes/messages/responses-bridge.ts","../src/routes/messages/stream-translation.ts","../src/routes/messages/handler.ts","../src/routes/messages/route.ts","../src/routes/models/route.ts","../src/routes/responses/handler.ts","../src/routes/responses/route.ts","../src/routes/token/route.ts","../src/routes/usage/route.ts","../src/server.ts","../src/start.ts","../src/main.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nconst APP_DIR = path.join(os.homedir(), \".local\", \"share\", \"copilot-proxy-api\")\n\nconst GITHUB_TOKEN_PATH = path.join(APP_DIR, \"github_token\")\n\nexport const PATHS = {\n  APP_DIR,\n  GITHUB_TOKEN_PATH,\n}\n\nexport async function ensurePaths(): Promise<void> {\n  await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n  await ensureFile(PATHS.GITHUB_TOKEN_PATH)\n}\n\nasync function ensureFile(filePath: string): Promise<void> {\n  try {\n    await fs.access(filePath, fs.constants.W_OK)\n  } catch {\n    await fs.writeFile(filePath, \"\")\n    await fs.chmod(filePath, 0o600)\n  }\n}\n","import type { ModelsResponse } from \"~/services/copilot/get-models\"\n\nexport interface State {\n  githubToken?: string\n  copilotToken?: string\n\n  accountType: string\n  models?: ModelsResponse\n  vsCodeVersion?: string\n\n  manualApprove: boolean\n  rateLimitWait: boolean\n  showToken: boolean\n  localApiKeys: Array<string>\n\n  // Rate limiting configuration\n  rateLimitSeconds?: number\n  lastRequestTimestamp?: number\n}\n\nexport const state: State = {\n  accountType: \"individual\",\n  manualApprove: false,\n  rateLimitWait: false,\n  showToken: false,\n  localApiKeys: [],\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type { State } from \"./state\"\n\nexport const standardHeaders = () => ({\n  \"content-type\": \"application/json\",\n  accept: \"application/json\",\n})\n\nconst COPILOT_VERSION = \"0.53.0\"\nconst EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`\nconst USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`\n\nconst API_VERSION = \"2025-04-01\"\n\nexport const copilotBaseUrl = (state: State) =>\n  state.accountType === \"individual\" ?\n    \"https://api.githubcopilot.com\"\n  : `https://api.${state.accountType}.githubcopilot.com`\nexport const copilotHeaders = (state: State, vision: boolean = false) => {\n  const headers: Record<string, string> = {\n    Authorization: `Bearer ${state.copilotToken}`,\n    \"content-type\": standardHeaders()[\"content-type\"],\n    \"copilot-integration-id\": \"vscode-chat\",\n    \"editor-version\": `vscode/${state.vsCodeVersion}`,\n    \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n    \"user-agent\": USER_AGENT,\n    \"openai-intent\": \"conversation-panel\",\n    \"x-github-api-version\": API_VERSION,\n    \"x-request-id\": randomUUID(),\n    \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n  }\n\n  if (vision) headers[\"copilot-vision-request\"] = \"true\"\n\n  return headers\n}\n\nexport const GITHUB_API_BASE_URL = \"https://api.github.com\"\nexport const githubHeaders = (state: State) => ({\n  ...standardHeaders(),\n  authorization: `token ${state.githubToken}`,\n  \"editor-version\": `vscode/${state.vsCodeVersion}`,\n  \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n  \"user-agent\": USER_AGENT,\n  \"x-github-api-version\": API_VERSION,\n  \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n})\n\nexport const GITHUB_BASE_URL = \"https://github.com\"\nexport const GITHUB_CLIENT_ID = \"Iv1.b507a08c87ecfe98\"\nexport const GITHUB_APP_SCOPES = [\"read:user\"].join(\" \")\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotToken = async () => {\n  const response = await fetch(\n    `${GITHUB_API_BASE_URL}/copilot_internal/v2/token`,\n    {\n      headers: githubHeaders(state),\n    },\n  )\n\n  if (!response.ok) throw new HTTPError(\"Failed to get Copilot token\", response)\n\n  return (await response.json()) as GetCopilotTokenResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GetCopilotTokenResponse {\n  expires_at: number\n  refresh_in: number\n  token: string\n}\n","import {\n  GITHUB_APP_SCOPES,\n  GITHUB_BASE_URL,\n  GITHUB_CLIENT_ID,\n  standardHeaders,\n} from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\n\nexport async function getDeviceCode(): Promise<DeviceCodeResponse> {\n  const response = await fetch(`${GITHUB_BASE_URL}/login/device/code`, {\n    method: \"POST\",\n    headers: standardHeaders(),\n    body: JSON.stringify({\n      client_id: GITHUB_CLIENT_ID,\n      scope: GITHUB_APP_SCOPES,\n    }),\n  })\n\n  if (!response.ok) throw new HTTPError(\"Failed to get device code\", response)\n\n  return (await response.json()) as DeviceCodeResponse\n}\n\nexport interface DeviceCodeResponse {\n  device_code: string\n  user_code: string\n  verification_uri: string\n  expires_in: number\n  interval: number\n}\n","import { GITHUB_API_BASE_URL, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getGitHubUser() {\n  const response = await fetch(`${GITHUB_API_BASE_URL}/user`, {\n    headers: {\n      authorization: `token ${state.githubToken}`,\n      ...standardHeaders(),\n    },\n  })\n\n  if (!response.ok) throw new HTTPError(\"Failed to get GitHub user\", response)\n\n  return (await response.json()) as GithubUserResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GithubUserResponse {\n  login: string\n}\n","import { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getModels = async () => {\n  const response = await fetch(`${copilotBaseUrl(state)}/models`, {\n    headers: copilotHeaders(state),\n  })\n\n  if (!response.ok) throw new HTTPError(\"Failed to get models\", response)\n\n  return (await response.json()) as ModelsResponse\n}\n\nexport interface ModelsResponse {\n  data: Array<Model>\n  object: string\n}\n\ninterface ModelLimits {\n  max_context_window_tokens?: number\n  max_output_tokens?: number\n  max_prompt_tokens?: number\n  max_inputs?: number\n}\n\ninterface ModelSupports {\n  tool_calls?: boolean\n  parallel_tool_calls?: boolean\n  dimensions?: boolean\n  streaming?: boolean\n  structured_outputs?: boolean\n  vision?: boolean\n  adaptive_thinking?: boolean\n  reasoning_effort?: Array<string>\n}\n\ninterface ModelCapabilities {\n  family: string\n  limits: ModelLimits\n  object: string\n  supports: ModelSupports\n  tokenizer: string\n  type: string\n}\n\nexport interface Model {\n  capabilities: ModelCapabilities\n  id: string\n  model_picker_enabled: boolean\n  name: string\n  object: string\n  preview: boolean\n  vendor: string\n  version: string\n  policy?: {\n    state: string\n    terms: string\n  }\n  supported_endpoints?: Array<string>\n}\n","// GitHub lists VS Code 1.128 as the minimum version for Claude Opus 5.\nconst FALLBACK = \"1.128.0\"\n\nexport async function getVSCodeVersion() {\n  const controller = new AbortController()\n  const timeout = setTimeout(() => {\n    controller.abort()\n  }, 5000)\n\n  try {\n    const response = await fetch(\n      \"https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=visual-studio-code-bin\",\n      {\n        signal: controller.signal,\n      },\n    )\n\n    const pkgbuild = await response.text()\n    const pkgverRegex = /pkgver=([0-9.]+)/\n    const match = pkgbuild.match(pkgverRegex)\n\n    if (match) {\n      return match[1]\n    }\n\n    return FALLBACK\n  } catch {\n    return FALLBACK\n  } finally {\n    clearTimeout(timeout)\n  }\n}\n\nawait getVSCodeVersion()\n","import consola from \"consola\"\n\nimport { getModels } from \"~/services/copilot/get-models\"\nimport { getVSCodeVersion } from \"~/services/get-vscode-version\"\n\nimport { state } from \"./state\"\n\nexport const sleep = (ms: number) =>\n  new Promise((resolve) => {\n    setTimeout(resolve, ms)\n  })\n\nexport const isNullish = (value: unknown): value is null | undefined =>\n  value === null || value === undefined\n\nexport async function cacheModels(): Promise<void> {\n  const models = await getModels()\n  state.models = models\n}\n\nexport const cacheVSCodeVersion = async () => {\n  const response = await getVSCodeVersion()\n  state.vsCodeVersion = response\n\n  consola.info(`Using VSCode version: ${response}`)\n}\n","import consola from \"consola\"\n\nimport {\n  GITHUB_BASE_URL,\n  GITHUB_CLIENT_ID,\n  standardHeaders,\n} from \"~/lib/api-config\"\nimport { sleep } from \"~/lib/utils\"\n\nimport type { DeviceCodeResponse } from \"./get-device-code\"\n\nexport async function pollAccessToken(\n  deviceCode: DeviceCodeResponse,\n): Promise<string> {\n  // Interval is in seconds, we need to multiply by 1000 to get milliseconds\n  // I'm also adding another second, just to be safe\n  const sleepDuration = (deviceCode.interval + 1) * 1000\n  consola.debug(`Polling access token with interval of ${sleepDuration}ms`)\n\n  while (true) {\n    const response = await fetch(\n      `${GITHUB_BASE_URL}/login/oauth/access_token`,\n      {\n        method: \"POST\",\n        headers: standardHeaders(),\n        body: JSON.stringify({\n          client_id: GITHUB_CLIENT_ID,\n          device_code: deviceCode.device_code,\n          grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n        }),\n      },\n    )\n\n    if (!response.ok) {\n      await sleep(sleepDuration)\n      consola.error(\"Failed to poll access token:\", await response.text())\n\n      continue\n    }\n\n    const json = await response.json()\n    consola.debug(\"Polling access token response:\", json)\n\n    const { access_token } = json as AccessTokenResponse\n\n    if (access_token) {\n      return access_token\n    } else {\n      await sleep(sleepDuration)\n    }\n  }\n}\n\ninterface AccessTokenResponse {\n  access_token: string\n  token_type: string\n  scope: string\n}\n","import consola from \"consola\"\nimport fs from \"node:fs/promises\"\n\nimport { PATHS } from \"~/lib/paths\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getDeviceCode } from \"~/services/github/get-device-code\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\nimport { pollAccessToken } from \"~/services/github/poll-access-token\"\n\nimport { HTTPError } from \"./error\"\nimport { state } from \"./state\"\n\nconst readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n\nconst writeGithubToken = (token: string) =>\n  fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token)\n\nlet copilotTokenRefresh: Promise<string> | undefined\n\nexport function refreshCopilotToken(staleToken?: string): Promise<string> {\n  if (staleToken && state.copilotToken && state.copilotToken !== staleToken) {\n    return Promise.resolve(state.copilotToken)\n  }\n\n  copilotTokenRefresh ??= getCopilotToken()\n    .then(({ token }) => {\n      state.copilotToken = token\n      consola.debug(\"Copilot token refreshed\")\n      if (state.showToken) {\n        consola.info(\"Refreshed Copilot token:\", token)\n      }\n      return token\n    })\n    .finally(() => {\n      copilotTokenRefresh = undefined\n    })\n\n  return copilotTokenRefresh\n}\n\nexport const setupCopilotToken = async () => {\n  const { token, refresh_in } = await getCopilotToken()\n  state.copilotToken = token\n\n  // Display the Copilot token to the screen\n  consola.debug(\"GitHub Copilot Token fetched successfully!\")\n  if (state.showToken) {\n    consola.info(\"Copilot token:\", token)\n  }\n\n  const refreshInterval = (refresh_in - 60) * 1000\n\n  const refreshWithRetry = async (maxRetries = 5, baseDelay = 1000) => {\n    for (let attempt = 1; attempt <= maxRetries; attempt++) {\n      try {\n        await refreshCopilotToken()\n        return // Success, exit retry loop\n      } catch (error) {\n        consola.error(\n          `Failed to refresh Copilot token (attempt ${attempt}/${maxRetries}):`,\n          error,\n        )\n\n        if (attempt < maxRetries) {\n          const delay = baseDelay * Math.pow(2, attempt - 1) // Exponential backoff\n          consola.info(`Retrying in ${delay / 1000} seconds...`)\n          await new Promise((resolve) => setTimeout(resolve, delay))\n        } else {\n          consola.error(\n            \"Max retries reached. Token refresh failed, but keeping server alive.\",\n          )\n          // Don't throw - keep the server running with the old token\n        }\n      }\n    }\n  }\n\n  setInterval(() => {\n    consola.debug(\"Refreshing Copilot token\")\n    void refreshWithRetry()\n  }, refreshInterval)\n}\n\ninterface SetupGitHubTokenOptions {\n  force?: boolean\n}\n\nexport async function setupGitHubToken(\n  options?: SetupGitHubTokenOptions,\n): Promise<void> {\n  try {\n    const githubToken = await readGithubToken()\n\n    if (githubToken && !options?.force) {\n      state.githubToken = githubToken\n      if (state.showToken) {\n        consola.info(\"GitHub token:\", githubToken)\n      }\n      await logUser()\n\n      return\n    }\n\n    consola.info(\"Not logged in, getting new access token\")\n    const response = await getDeviceCode()\n    consola.debug(\"Device code response:\", response)\n\n    consola.info(\n      `Please enter the code \"${response.user_code}\" in ${response.verification_uri}`,\n    )\n\n    const token = await pollAccessToken(response)\n    await writeGithubToken(token)\n    state.githubToken = token\n\n    if (state.showToken) {\n      consola.info(\"GitHub token:\", token)\n    }\n    await logUser()\n  } catch (error) {\n    if (error instanceof HTTPError) {\n      consola.error(\"Failed to get GitHub token:\", await error.response.json())\n      throw error\n    }\n\n    consola.error(\"Failed to get GitHub token:\", error)\n    throw error\n  }\n}\n\nasync function logUser() {\n  const user = await getGitHubUser()\n  consola.info(`Logged in as ${user.login}`)\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport { setupGitHubToken } from \"./lib/token\"\n\ninterface RunAuthOptions {\n  verbose: boolean\n  showToken: boolean\n}\n\nexport async function runAuth(options: RunAuthOptions): Promise<void> {\n  if (options.verbose) {\n    consola.level = 5\n    consola.info(\"Verbose logging enabled\")\n  }\n\n  state.showToken = options.showToken\n\n  await ensurePaths()\n  await setupGitHubToken({ force: true })\n  consola.success(\"GitHub token written to\", PATHS.GITHUB_TOKEN_PATH)\n}\n\nexport const auth = defineCommand({\n  meta: {\n    name: \"auth\",\n    description: \"Run GitHub auth flow without running the server\",\n  },\n  args: {\n    verbose: {\n      alias: \"v\",\n      type: \"boolean\",\n      default: false,\n      description: \"Enable verbose logging\",\n    },\n    \"show-token\": {\n      type: \"boolean\",\n      default: false,\n      description: \"Show GitHub token on auth\",\n    },\n  },\n  run({ args }) {\n    return runAuth({\n      verbose: args.verbose,\n      showToken: args[\"show-token\"],\n    })\n  },\n})\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotUsage = async (): Promise<CopilotUsageResponse> => {\n  const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, {\n    headers: githubHeaders(state),\n  })\n\n  if (!response.ok) {\n    throw new HTTPError(\"Failed to get Copilot usage\", response)\n  }\n\n  return (await response.json()) as CopilotUsageResponse\n}\n\nexport interface QuotaDetail {\n  entitlement: number\n  overage_count: number\n  overage_permitted: boolean\n  percent_remaining: number\n  quota_id: string\n  quota_remaining: number\n  remaining: number\n  unlimited: boolean\n}\n\ninterface QuotaSnapshots {\n  chat: QuotaDetail\n  completions: QuotaDetail\n  premium_interactions: QuotaDetail\n}\n\ninterface CopilotUsageResponse {\n  access_type_sku: string\n  analytics_tracking_id: string\n  assigned_date: string\n  can_signup_for_limited: boolean\n  chat_enabled: boolean\n  copilot_plan: string\n  organization_login_list: Array<unknown>\n  organization_list: Array<unknown>\n  quota_reset_date: string\n  quota_snapshots: QuotaSnapshots\n}\n","import { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { setupGitHubToken } from \"./lib/token\"\nimport {\n  getCopilotUsage,\n  type QuotaDetail,\n} from \"./services/github/get-copilot-usage\"\n\nexport const checkUsage = defineCommand({\n  meta: {\n    name: \"check-usage\",\n    description: \"Show current GitHub Copilot usage/quota information\",\n  },\n  async run() {\n    await ensurePaths()\n    await setupGitHubToken()\n    try {\n      const usage = await getCopilotUsage()\n      const premium = usage.quota_snapshots.premium_interactions\n      const premiumTotal = premium.entitlement\n      const premiumUsed = premiumTotal - premium.remaining\n      const premiumPercentUsed =\n        premiumTotal > 0 ? (premiumUsed / premiumTotal) * 100 : 0\n      const premiumPercentRemaining = premium.percent_remaining\n\n      // Helper to summarize a quota snapshot\n      function summarizeQuota(name: string, snap: QuotaDetail | undefined) {\n        if (!snap) return `${name}: N/A`\n        const total = snap.entitlement\n        const used = total - snap.remaining\n        const percentUsed = total > 0 ? (used / total) * 100 : 0\n        const percentRemaining = snap.percent_remaining\n        return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`\n      }\n\n      const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`\n      const chatLine = summarizeQuota(\"Chat\", usage.quota_snapshots.chat)\n      const completionsLine = summarizeQuota(\n        \"Completions\",\n        usage.quota_snapshots.completions,\n      )\n\n      consola.box(\n        `Copilot Usage (plan: ${usage.copilot_plan})\\n`\n          + `Quota resets: ${usage.quota_reset_date}\\n`\n          + `\\nQuotas:\\n`\n          + `  ${premiumLine}\\n`\n          + `  ${chatLine}\\n`\n          + `  ${completionsLine}`,\n      )\n    } catch (err) {\n      consola.error(\"Failed to fetch Copilot usage:\", err)\n      process.exit(1)\n    }\n  },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\nimport fs from \"node:fs/promises\"\nimport os from \"node:os\"\n\nimport { PATHS } from \"./lib/paths\"\n\ninterface DebugInfo {\n  version: string\n  runtime: {\n    name: string\n    version: string\n    platform: string\n    arch: string\n  }\n  paths: {\n    APP_DIR: string\n    GITHUB_TOKEN_PATH: string\n  }\n  tokenExists: boolean\n}\n\ninterface RunDebugOptions {\n  json: boolean\n}\n\nasync function getPackageVersion(): Promise<string> {\n  try {\n    const packageJsonPath = new URL(\"../package.json\", import.meta.url).pathname\n    // @ts-expect-error https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v59.0.1/docs/rules/prefer-json-parse-buffer.md\n    // JSON.parse() can actually parse buffers\n    const packageJson = JSON.parse(await fs.readFile(packageJsonPath)) as {\n      version: string\n    }\n    return packageJson.version\n  } catch {\n    return \"unknown\"\n  }\n}\n\nfunction getRuntimeInfo() {\n  const isBun = typeof Bun !== \"undefined\"\n\n  return {\n    name: isBun ? \"bun\" : \"node\",\n    version: isBun ? Bun.version : process.version.slice(1),\n    platform: os.platform(),\n    arch: os.arch(),\n  }\n}\n\nasync function checkTokenExists(): Promise<boolean> {\n  try {\n    const stats = await fs.stat(PATHS.GITHUB_TOKEN_PATH)\n    if (!stats.isFile()) return false\n\n    const content = await fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n    return content.trim().length > 0\n  } catch {\n    return false\n  }\n}\n\nasync function getDebugInfo(): Promise<DebugInfo> {\n  const [version, tokenExists] = await Promise.all([\n    getPackageVersion(),\n    checkTokenExists(),\n  ])\n\n  return {\n    version,\n    runtime: getRuntimeInfo(),\n    paths: {\n      APP_DIR: PATHS.APP_DIR,\n      GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH,\n    },\n    tokenExists,\n  }\n}\n\nfunction printDebugInfoPlain(info: DebugInfo): void {\n  consola.info(`copilot-proxy-api debug\n\nVersion: ${info.version}\nRuntime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})\n\nPaths:\n- APP_DIR: ${info.paths.APP_DIR}\n- GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}\n\nToken exists: ${info.tokenExists ? \"Yes\" : \"No\"}`)\n}\n\nfunction printDebugInfoJson(info: DebugInfo): void {\n  console.log(JSON.stringify(info, null, 2))\n}\n\nexport async function runDebug(options: RunDebugOptions): Promise<void> {\n  const debugInfo = await getDebugInfo()\n\n  if (options.json) {\n    printDebugInfoJson(debugInfo)\n  } else {\n    printDebugInfoPlain(debugInfo)\n  }\n}\n\nexport const debug = defineCommand({\n  meta: {\n    name: \"debug\",\n    description: \"Print debug information about the application\",\n  },\n  args: {\n    json: {\n      type: \"boolean\",\n      default: false,\n      description: \"Output debug information as JSON\",\n    },\n  },\n  run({ args }) {\n    return runDebug({\n      json: args.json,\n    })\n  },\n})\n","import type { MiddlewareHandler } from \"hono\"\n\nimport { state } from \"./state\"\n\nexport function parseLocalApiKeys(value: string | undefined): Array<string> {\n  if (!value) return []\n  return value\n    .split(\",\")\n    .map((key) => key.trim())\n    .filter((key) => key.length > 0)\n}\n\nexport const optionalLocalAuth: MiddlewareHandler = async (c, next) => {\n  if (state.localApiKeys.length === 0 || c.req.method === \"OPTIONS\") {\n    await next()\n    return\n  }\n\n  const bearerToken = extractBearerToken(c.req.header(\"authorization\"))\n  const apiKey = c.req.header(\"x-api-key\")?.trim()\n\n  if (\n    (bearerToken && state.localApiKeys.includes(bearerToken))\n    || (apiKey && state.localApiKeys.includes(apiKey))\n  ) {\n    await next()\n    return\n  }\n\n  return c.json(\n    {\n      error: {\n        message: \"Missing or invalid API key\",\n        type: \"authentication_error\",\n      },\n    },\n    401,\n  )\n}\n\nfunction extractBearerToken(\n  authorization: string | undefined,\n): string | undefined {\n  if (!authorization) return undefined\n\n  const prefix = \"bearer \"\n  if (!authorization.toLowerCase().startsWith(prefix)) return undefined\n\n  const token = authorization.slice(prefix.length).trim()\n  return token.length > 0 ? token : undefined\n}\n","import consola from \"consola\"\nimport { getProxyForUrl } from \"proxy-from-env\"\nimport { Agent, ProxyAgent, setGlobalDispatcher, type Dispatcher } from \"undici\"\n\nexport function initProxyFromEnv(): void {\n  if (typeof Bun !== \"undefined\") return\n\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    setGlobalDispatcher(dispatcher as unknown as Dispatcher)\n    consola.debug(\"HTTP proxy configured from environment (per-URL)\")\n  } catch (err) {\n    consola.debug(\"Proxy setup skipped:\", err)\n  }\n}\n","import { execSync } from \"node:child_process\"\nimport process from \"node:process\"\n\ntype ShellName = \"bash\" | \"zsh\" | \"fish\" | \"powershell\" | \"cmd\" | \"sh\"\ntype EnvVars = Record<string, string | undefined>\n\nfunction getShell(): ShellName {\n  const { platform, ppid, env } = process\n\n  if (platform === \"win32\") {\n    try {\n      const command = `wmic process get ParentProcessId,Name | findstr \"${ppid}\"`\n      const parentProcess = execSync(command, { stdio: \"pipe\" }).toString()\n\n      if (parentProcess.toLowerCase().includes(\"powershell.exe\")) {\n        return \"powershell\"\n      }\n    } catch {\n      return \"cmd\"\n    }\n\n    return \"cmd\"\n  } else {\n    const shellPath = env.SHELL\n    if (shellPath) {\n      if (shellPath.endsWith(\"zsh\")) return \"zsh\"\n      if (shellPath.endsWith(\"fish\")) return \"fish\"\n      if (shellPath.endsWith(\"bash\")) return \"bash\"\n    }\n\n    return \"sh\"\n  }\n}\n\n/**\n * Generates a copy-pasteable script to set multiple environment variables\n * and run a subsequent command.\n * @param {EnvVars} envVars - An object of environment variables to set.\n * @param {string} commandToRun - The command to run after setting the variables.\n * @returns {string} The formatted script string.\n */\nexport function generateEnvScript(\n  envVars: EnvVars,\n  commandToRun: string = \"\",\n): string {\n  const shell = getShell()\n  const filteredEnvVars = Object.entries(envVars).filter(\n    ([, value]) => value !== undefined,\n  ) as Array<[string, string]>\n\n  let commandBlock: string\n\n  switch (shell) {\n    case \"powershell\": {\n      commandBlock = filteredEnvVars\n        .map(([key, value]) => `$env:${key} = ${value}`)\n        .join(\"; \")\n      break\n    }\n    case \"cmd\": {\n      commandBlock = filteredEnvVars\n        .map(([key, value]) => `set ${key}=${value}`)\n        .join(\" & \")\n      break\n    }\n    case \"fish\": {\n      commandBlock = filteredEnvVars\n        .map(([key, value]) => `set -gx ${key} ${value}`)\n        .join(\"; \")\n      break\n    }\n    default: {\n      // bash, zsh, sh\n      const assignments = filteredEnvVars\n        .map(([key, value]) => `${key}=${value}`)\n        .join(\" \")\n      commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : \"\"\n      break\n    }\n  }\n\n  if (commandBlock && commandToRun) {\n    const separator = shell === \"cmd\" ? \" & \" : \" && \"\n    return `${commandBlock}${separator}${commandToRun}`\n  }\n\n  return commandBlock || commandToRun\n}\n","import type { MiddlewareHandler } from \"hono\"\n\nimport { randomUUID } from \"node:crypto\"\n\nconst MAX_REQUEST_TRACES = 100\n\nexport interface RequestTrace {\n  id: string\n  method: string\n  path: string\n  status: number\n  ok: boolean\n  durationMs: number\n  startedAt: string\n  error?: string\n}\n\nconst requestTraces: Array<RequestTrace> = []\n\nfunction createRequestId(): string {\n  return `req_${randomUUID().replaceAll(\"-\", \"\")}`\n}\n\nfunction errorMessage(error: unknown): string {\n  return error instanceof Error ? error.message : \"Unknown error\"\n}\n\nfunction addRequestTrace(trace: RequestTrace): void {\n  requestTraces.unshift(trace)\n  if (requestTraces.length > MAX_REQUEST_TRACES) {\n    requestTraces.length = MAX_REQUEST_TRACES\n  }\n}\n\nexport function getRequestTraces(): Array<RequestTrace> {\n  return [...requestTraces]\n}\n\nexport function clearRequestTraces(): void {\n  requestTraces.length = 0\n}\n\nexport const requestTraceMiddleware: MiddlewareHandler = async (c, next) => {\n  const startedAtMs = Date.now()\n  const startedAt = new Date(startedAtMs).toISOString()\n  const requestId =\n    c.req.header(\"x-client-request-id\")\n    ?? c.req.header(\"x-request-id\")\n    ?? createRequestId()\n\n  c.header(\"request-id\", requestId)\n  c.header(\"x-request-id\", requestId)\n\n  let error: string | undefined\n  try {\n    await next()\n  } catch (caught) {\n    error = errorMessage(caught)\n    throw caught\n  } finally {\n    const finalRequestId =\n      c.res.headers.get(\"x-request-id\")\n      ?? c.res.headers.get(\"request-id\")\n      ?? requestId\n    const status = error ? 500 : c.res.status\n    addRequestTrace({\n      id: finalRequestId,\n      method: c.req.method,\n      path: c.req.path,\n      status,\n      ok: !error && status < 400,\n      durationMs: Date.now() - startedAtMs,\n      startedAt,\n      error,\n    })\n  }\n}\n","import consola from \"consola\"\n\nimport { HTTPError } from \"./error\"\n\nexport const awaitApproval = async () => {\n  const response = await consola.prompt(`Accept incoming request?`, {\n    type: \"confirm\",\n  })\n\n  if (!response)\n    throw new HTTPError(\n      \"Request rejected\",\n      Response.json({ message: \"Request rejected\" }, { status: 403 }),\n    )\n}\n","import consola from \"consola\"\n\nimport type { State } from \"./state\"\n\nimport { HTTPError } from \"./error\"\nimport { sleep } from \"./utils\"\n\nexport async function checkRateLimit(state: State) {\n  if (state.rateLimitSeconds === undefined) return\n\n  const now = Date.now()\n\n  if (!state.lastRequestTimestamp) {\n    state.lastRequestTimestamp = now\n    return\n  }\n\n  const elapsedSeconds = (now - state.lastRequestTimestamp) / 1000\n\n  if (elapsedSeconds > state.rateLimitSeconds) {\n    state.lastRequestTimestamp = now\n    return\n  }\n\n  const waitTimeSeconds = Math.ceil(state.rateLimitSeconds - elapsedSeconds)\n\n  if (!state.rateLimitWait) {\n    consola.warn(\n      `Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`,\n    )\n    throw new HTTPError(\n      \"Rate limit exceeded\",\n      Response.json({ message: \"Rate limit exceeded\" }, { status: 429 }),\n    )\n  }\n\n  const waitTimeMs = waitTimeSeconds * 1000\n  consola.warn(\n    `Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`,\n  )\n  await sleep(waitTimeMs)\n  // eslint-disable-next-line require-atomic-updates\n  state.lastRequestTimestamp = now\n  consola.info(\"Rate limit wait completed, proceeding with request\")\n  return\n}\n","import type {\n  ChatCompletionsPayload,\n  ContentPart,\n  Message,\n  Tool,\n  ToolCall,\n} from \"~/services/copilot/create-chat-completions\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\n// Encoder type mapping\nconst ENCODING_MAP = {\n  o200k_base: () => import(\"gpt-tokenizer/encoding/o200k_base\"),\n  cl100k_base: () => import(\"gpt-tokenizer/encoding/cl100k_base\"),\n  p50k_base: () => import(\"gpt-tokenizer/encoding/p50k_base\"),\n  p50k_edit: () => import(\"gpt-tokenizer/encoding/p50k_edit\"),\n  r50k_base: () => import(\"gpt-tokenizer/encoding/r50k_base\"),\n} as const\n\ntype SupportedEncoding = keyof typeof ENCODING_MAP\n\n// Define encoder interface\ninterface Encoder {\n  encode: (text: string) => Array<number>\n}\n\n// Cache loaded encoders to avoid repeated imports\nconst encodingCache = new Map<string, Encoder>()\n\n/**\n * Calculate tokens for tool calls\n */\nconst calculateToolCallsTokens = (\n  toolCalls: Array<ToolCall>,\n  encoder: Encoder,\n  constants: ReturnType<typeof getModelConstants>,\n): number => {\n  let tokens = 0\n  for (const toolCall of toolCalls) {\n    tokens += constants.funcInit\n    tokens += encoder.encode(JSON.stringify(toolCall)).length\n  }\n  tokens += constants.funcEnd\n  return tokens\n}\n\n/**\n * Calculate tokens for content parts\n */\nconst calculateContentPartsTokens = (\n  contentParts: Array<ContentPart>,\n  encoder: Encoder,\n): number => {\n  let tokens = 0\n  for (const part of contentParts) {\n    if (part.type === \"image_url\") {\n      tokens += encoder.encode(part.image_url.url).length + 85\n    } else if (part.text) {\n      tokens += encoder.encode(part.text).length\n    }\n  }\n  return tokens\n}\n\n/**\n * Calculate tokens for a single message\n */\nconst calculateMessageTokens = (\n  message: Message,\n  encoder: Encoder,\n  constants: ReturnType<typeof getModelConstants>,\n): number => {\n  const tokensPerMessage = 3\n  const tokensPerName = 1\n  let tokens = tokensPerMessage\n  for (const [key, value] of Object.entries(message)) {\n    if (typeof value === \"string\") {\n      tokens += encoder.encode(value).length\n    }\n    if (key === \"name\") {\n      tokens += tokensPerName\n    }\n    if (key === \"tool_calls\") {\n      tokens += calculateToolCallsTokens(\n        value as Array<ToolCall>,\n        encoder,\n        constants,\n      )\n    }\n    if (key === \"content\" && Array.isArray(value)) {\n      tokens += calculateContentPartsTokens(\n        value as Array<ContentPart>,\n        encoder,\n      )\n    }\n  }\n  return tokens\n}\n\n/**\n * Calculate tokens using custom algorithm\n */\nconst calculateTokens = (\n  messages: Array<Message>,\n  encoder: Encoder,\n  constants: ReturnType<typeof getModelConstants>,\n): number => {\n  if (messages.length === 0) {\n    return 0\n  }\n  let numTokens = 0\n  for (const message of messages) {\n    numTokens += calculateMessageTokens(message, encoder, constants)\n  }\n  // every reply is primed with <|start|>assistant<|message|>\n  numTokens += 3\n  return numTokens\n}\n\n/**\n * Get the corresponding encoder module based on encoding type\n */\nconst getEncodeChatFunction = async (encoding: string): Promise<Encoder> => {\n  if (encodingCache.has(encoding)) {\n    const cached = encodingCache.get(encoding)\n    if (cached) {\n      return cached\n    }\n  }\n\n  const supportedEncoding = encoding as SupportedEncoding\n  if (!(supportedEncoding in ENCODING_MAP)) {\n    const fallbackModule = (await ENCODING_MAP.o200k_base()) as Encoder\n    encodingCache.set(encoding, fallbackModule)\n    return fallbackModule\n  }\n\n  const encodingModule = (await ENCODING_MAP[supportedEncoding]()) as Encoder\n  encodingCache.set(encoding, encodingModule)\n  return encodingModule\n}\n\n/**\n * Get tokenizer type from model information\n */\nexport const getTokenizerFromModel = (model: Model): string => {\n  return model.capabilities.tokenizer || \"o200k_base\"\n}\n\n/**\n * Get model-specific constants for token calculation\n */\nconst getModelConstants = (model: Model) => {\n  return model.id === \"gpt-3.5-turbo\" || model.id === \"gpt-4\" ?\n      {\n        funcInit: 10,\n        propInit: 3,\n        propKey: 3,\n        enumInit: -3,\n        enumItem: 3,\n        funcEnd: 12,\n      }\n    : {\n        funcInit: 7,\n        propInit: 3,\n        propKey: 3,\n        enumInit: -3,\n        enumItem: 3,\n        funcEnd: 12,\n      }\n}\n\n/**\n * Calculate tokens for a single parameter\n */\nconst calculateParameterTokens = (\n  key: string,\n  prop: unknown,\n  context: {\n    encoder: Encoder\n    constants: ReturnType<typeof getModelConstants>\n  },\n): number => {\n  const { encoder, constants } = context\n  let tokens = constants.propKey\n\n  // Early return if prop is not an object\n  if (typeof prop !== \"object\" || prop === null) {\n    return tokens\n  }\n\n  // Type assertion for parameter properties\n  const param = prop as {\n    type?: string\n    description?: string\n    enum?: Array<unknown>\n    [key: string]: unknown\n  }\n\n  const paramName = key\n  const paramType = param.type || \"string\"\n  let paramDesc = param.description || \"\"\n\n  // Handle enum values\n  if (param.enum && Array.isArray(param.enum)) {\n    tokens += constants.enumInit\n    for (const item of param.enum) {\n      tokens += constants.enumItem\n      tokens += encoder.encode(String(item)).length\n    }\n  }\n\n  // Clean up description\n  if (paramDesc.endsWith(\".\")) {\n    paramDesc = paramDesc.slice(0, -1)\n  }\n\n  // Encode the main parameter line\n  const line = `${paramName}:${paramType}:${paramDesc}`\n  tokens += encoder.encode(line).length\n\n  // Handle additional properties (excluding standard ones)\n  const excludedKeys = new Set([\"type\", \"description\", \"enum\"])\n  for (const propertyName of Object.keys(param)) {\n    if (!excludedKeys.has(propertyName)) {\n      const propertyValue = param[propertyName]\n      const propertyText =\n        typeof propertyValue === \"string\" ? propertyValue : (\n          JSON.stringify(propertyValue)\n        )\n      tokens += encoder.encode(`${propertyName}:${propertyText}`).length\n    }\n  }\n\n  return tokens\n}\n\n/**\n * Calculate tokens for function parameters\n */\nconst calculateParametersTokens = (\n  parameters: unknown,\n  encoder: Encoder,\n  constants: ReturnType<typeof getModelConstants>,\n): number => {\n  if (!parameters || typeof parameters !== \"object\") {\n    return 0\n  }\n\n  const params = parameters as Record<string, unknown>\n  let tokens = 0\n\n  for (const [key, value] of Object.entries(params)) {\n    if (key === \"properties\") {\n      const properties = value as Record<string, unknown>\n      if (Object.keys(properties).length > 0) {\n        tokens += constants.propInit\n        for (const propKey of Object.keys(properties)) {\n          tokens += calculateParameterTokens(propKey, properties[propKey], {\n            encoder,\n            constants,\n          })\n        }\n      }\n    } else {\n      const paramText =\n        typeof value === \"string\" ? value : JSON.stringify(value)\n      tokens += encoder.encode(`${key}:${paramText}`).length\n    }\n  }\n\n  return tokens\n}\n\n/**\n * Calculate tokens for a single tool\n */\nconst calculateToolTokens = (\n  tool: Tool,\n  encoder: Encoder,\n  constants: ReturnType<typeof getModelConstants>,\n): number => {\n  let tokens = constants.funcInit\n  const func = tool.function\n  const fName = func.name\n  let fDesc = func.description || \"\"\n  if (fDesc.endsWith(\".\")) {\n    fDesc = fDesc.slice(0, -1)\n  }\n  const line = fName + \":\" + fDesc\n  tokens += encoder.encode(line).length\n  if (\n    typeof func.parameters === \"object\" // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n    && func.parameters !== null\n  ) {\n    tokens += calculateParametersTokens(func.parameters, encoder, constants)\n  }\n  return tokens\n}\n\n/**\n * Calculate token count for tools based on model\n */\nexport const numTokensForTools = (\n  tools: Array<Tool>,\n  encoder: Encoder,\n  constants: ReturnType<typeof getModelConstants>,\n): number => {\n  let funcTokenCount = 0\n  for (const tool of tools) {\n    funcTokenCount += calculateToolTokens(tool, encoder, constants)\n  }\n  funcTokenCount += constants.funcEnd\n  return funcTokenCount\n}\n\n/**\n * Calculate the token count of messages, supporting multiple GPT encoders\n */\nexport const getTokenCount = async (\n  payload: ChatCompletionsPayload,\n  model: Model,\n): Promise<{ input: number; output: number }> => {\n  // Get tokenizer string\n  const tokenizer = getTokenizerFromModel(model)\n\n  // Get corresponding encoder module\n  const encoder = await getEncodeChatFunction(tokenizer)\n\n  const simplifiedMessages = payload.messages\n  const inputMessages = simplifiedMessages.filter(\n    (msg) => msg.role !== \"assistant\",\n  )\n  const outputMessages = simplifiedMessages.filter(\n    (msg) => msg.role === \"assistant\",\n  )\n\n  const constants = getModelConstants(model)\n  let inputTokens = calculateTokens(inputMessages, encoder, constants)\n  if (payload.tools && payload.tools.length > 0) {\n    inputTokens += numTokensForTools(payload.tools, encoder, constants)\n  }\n  const outputTokens = calculateTokens(outputMessages, encoder, constants)\n\n  return {\n    input: inputTokens,\n    output: outputTokens,\n  }\n}\n","import consola from \"consola\"\n\nimport { refreshCopilotToken } from \"./token\"\nimport { sleep } from \"./utils\"\n\nconst DEFAULT_ATTEMPTS = 3\nconst RETRY_DELAY_MS = 250\nconst LARGE_PAYLOAD_CONTEXT_OVERFLOW_BYTES = 2_000_000\n\nexport interface CopilotFetchOptions extends RequestInit {\n  attempts?: number\n  retryDelayMs?: number\n}\n\nexport async function copilotFetch(\n  url: string,\n  options: CopilotFetchOptions,\n): Promise<Response> {\n  const {\n    attempts = DEFAULT_ATTEMPTS,\n    retryDelayMs = RETRY_DELAY_MS,\n    ...init\n  } = options\n  const bodyLength = typeof init.body === \"string\" ? init.body.length : 0\n  const requestLabel = formatRequestLabel(url, init.method)\n  let canRefreshAuth = true\n\n  let lastError: unknown\n  for (let attempt = 1; attempt <= attempts; attempt++) {\n    try {\n      let response = await fetch(url, init)\n      if (canRefreshAuth && isAuthFailure(response)) {\n        canRefreshAuth = false\n        response = await retryWithRefreshedToken(url, init, response)\n      }\n      if (!shouldRetryResponse(response, bodyLength) || attempt === attempts) {\n        return response\n      }\n\n      consola.warn(\n        `Copilot ${requestLabel} returned ${response.status}; retrying (${attempt}/${attempts})`,\n      )\n    } catch (error) {\n      lastError = error\n      if (\n        attempt === attempts\n        || isLikelyContextOverflowTimeout(error, bodyLength)\n      ) {\n        throw error\n      }\n      consola.warn(\n        `Copilot ${requestLabel} failed (${formatErrorMessage(error)}); retrying (${attempt}/${attempts})`,\n      )\n    }\n\n    await sleep(retryDelayMs * attempt)\n  }\n\n  throw lastError instanceof Error ? lastError : (\n      new Error(\"Copilot request failed\")\n    )\n}\n\nfunction isAuthFailure(response: Response): boolean {\n  return response.status === 401 || response.status === 403\n}\n\nasync function retryWithRefreshedToken(\n  url: string,\n  init: RequestInit,\n  response: Response,\n): Promise<Response> {\n  const staleToken = getBearerToken(init.headers)\n  const requestLabel = formatRequestLabel(url, init.method)\n\n  try {\n    const token = await refreshCopilotToken(staleToken)\n    const headers = new Headers(init.headers)\n    headers.set(\"Authorization\", `Bearer ${token}`)\n    init.headers = headers\n    consola.warn(\n      `Copilot ${requestLabel} returned ${response.status}; refreshed token and retrying`,\n    )\n    return await fetch(url, init)\n  } catch (error) {\n    consola.warn(\n      `Copilot token refresh failed after ${requestLabel} returned ${response.status}: ${formatErrorMessage(error)}`,\n    )\n    return response\n  }\n}\n\nfunction getBearerToken(headers: RequestInit[\"headers\"]): string | undefined {\n  const authorization = new Headers(headers).get(\"Authorization\")\n  if (!authorization?.toLowerCase().startsWith(\"bearer \")) return undefined\n  return authorization.slice(7)\n}\n\nfunction formatRequestLabel(url: string, method: string | undefined): string {\n  const verb = method?.toUpperCase() ?? \"GET\"\n\n  try {\n    const parsed = new URL(url)\n    return `${verb} ${parsed.pathname}`\n  } catch {\n    return `${verb} ${url}`\n  }\n}\n\nfunction formatErrorMessage(error: unknown): string {\n  if (error instanceof Error && error.message) return error.message\n  return \"unknown error\"\n}\n\nfunction shouldRetryResponse(response: Response, bodyLength: number): boolean {\n  if (\n    response.status >= 500\n    && bodyLength > LARGE_PAYLOAD_CONTEXT_OVERFLOW_BYTES\n  ) {\n    return false\n  }\n\n  return (\n    response.status === 408\n    || response.status === 409\n    || response.status === 425\n    || response.status === 429\n    || response.status === 499\n    || response.status === 500\n    || response.status === 502\n    || response.status === 503\n    || response.status === 504\n  )\n}\n\nexport function isLikelyContextOverflowTimeout(\n  error: unknown,\n  bodyLength: number,\n): boolean {\n  return (\n    bodyLength > LARGE_PAYLOAD_CONTEXT_OVERFLOW_BYTES\n    && error instanceof Error\n    && /operation timed out|timed out/i.test(error.message)\n  )\n}\n","import type { Model } from \"~/services/copilot/get-models\"\n\nexport const DEFAULT_PROMPT_TOKENS = 200_000\nexport const ONE_M_PROMPT_TOKENS = 936_000\nexport const ONE_M_CONTEXT_TOKENS = 1_000_000\n\nexport function getModelPromptLimit(\n  modelId: string,\n  limits?: Model[\"capabilities\"][\"limits\"],\n): number {\n  return getKnownModelPromptLimit(modelId, limits) ?? DEFAULT_PROMPT_TOKENS\n}\n\nexport function getKnownModelPromptLimit(\n  modelId: string,\n  limits?: Model[\"capabilities\"][\"limits\"],\n): number | undefined {\n  if (limits?.max_prompt_tokens) return limits.max_prompt_tokens\n  if (isOneMillionContextModel(modelId)) return ONE_M_PROMPT_TOKENS\n  return limits?.max_context_window_tokens\n}\n\nexport function getModelContextLimit(\n  modelId: string,\n  limits?: Model[\"capabilities\"][\"limits\"],\n): number {\n  if (limits?.max_context_window_tokens) return limits.max_context_window_tokens\n  if (isOneMillionContextModel(modelId)) return ONE_M_CONTEXT_TOKENS\n  return DEFAULT_PROMPT_TOKENS\n}\n\nfunction isOneMillionContextModel(modelId: string): boolean {\n  return /(?:^|[-_.])1m(?:$|[-_.])/i.test(modelId)\n}\n","import consola from \"consola\"\n\nimport type { ChatCompletionsPayload } from \"~/services/copilot/create-chat-completions\"\n\nimport { HTTPError } from \"./error\"\nimport { getModelPromptLimit } from \"./model-limits\"\nimport { state } from \"./state\"\n\nexport function createPromptTooLongError(\n  payload: ChatCompletionsPayload,\n  bodyLength: number,\n): HTTPError {\n  const estimatedTokens = Math.ceil(bodyLength / 4)\n  const modelCaps = state.models?.data.find((m) => m.id === payload.model)\n    ?.capabilities.limits\n  const modelLimit = getModelPromptLimit(payload.model, modelCaps)\n  const maxOutputTokens = payload.max_tokens ?? 0\n\n  consola.warn(\n    `Context overflow -> returning 400 prompt-too-long (~${estimatedTokens} + ${maxOutputTokens} > ${modelLimit}) to trigger Claude Code reactive compaction`,\n  )\n\n  return new HTTPError(\n    \"Prompt too long\",\n    new Response(\n      JSON.stringify({\n        type: \"error\",\n        error: {\n          type: \"invalid_request_error\",\n          message: `prompt is too long: input length and \\`max_tokens\\` exceed context limit: ${estimatedTokens} + ${maxOutputTokens} > ${modelLimit} tokens`,\n        },\n      }),\n      {\n        status: 400,\n        statusText: \"Bad Request\",\n        headers: { \"content-type\": \"application/json\" },\n      },\n    ),\n  )\n}\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport {\n  copilotFetch,\n  isLikelyContextOverflowTimeout,\n} from \"~/lib/copilot-fetch\"\nimport { HTTPError } from \"~/lib/error\"\nimport { createPromptTooLongError } from \"~/lib/prompt-too-long\"\nimport { state } from \"~/lib/state\"\n\n/* eslint-disable complexity */\nexport const createChatCompletions = async (\n  payload: ChatCompletionsPayload,\n) => {\n  if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n  const enableVision = payload.messages.some(\n    (x) =>\n      typeof x.content !== \"string\"\n      && x.content?.some((x) => x.type === \"image_url\"),\n  )\n\n  // Agent/user check for X-Initiator header\n  const isAgentCall = payload.messages.some((msg) =>\n    [\"assistant\", \"tool\"].includes(msg.role),\n  )\n\n  const headers: Record<string, string> = {\n    ...copilotHeaders(state, enableVision),\n    \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n  }\n\n  const body = JSON.stringify(payload)\n  consola.info(\n    `Sending payload: ${body.length} bytes, ${payload.messages.length} messages, model: ${payload.model}`,\n  )\n\n  let response: Response\n  try {\n    response = await copilotFetch(`${copilotBaseUrl(state)}/chat/completions`, {\n      method: \"POST\",\n      headers,\n      body,\n    })\n  } catch (error) {\n    if (isLikelyContextOverflowTimeout(error, body.length)) {\n      throw createPromptTooLongError(payload, body.length)\n    }\n    throw error\n  }\n\n  if (!response.ok) {\n    const errorBody = await response.text()\n    consola.error(\n      `Failed to create chat completions - Status: ${response.status} ${response.statusText}`,\n    )\n    consola.error(`Response body: ${errorBody}`)\n    consola.error(`Request payload size: ${body.length} bytes`)\n\n    // Detect context overflow errors. Includes:\n    //  - HTTP 413 from Azure Front Door (>~5.4 MB)\n    //  - Backend \"operation timed out\" / 500 in the 2.5 MiB - 5.3 MB dead\n    //    zone (Copilot backend hangs >90s instead of cleanly rejecting;\n    //    Bun fetch eventually surfaces this as a 500 or upstream timeout)\n    //  - Various worded variants Copilot has emitted in the past\n    const isContextOverflow =\n      response.status === 413\n      || /request entity too large/i.test(errorBody)\n      || /exceeds the limit of \\d+/i.test(errorBody)\n      || /context_length_exceeded/i.test(errorBody)\n      || /operation timed out/i.test(errorBody)\n      || /payload too large/i.test(errorBody)\n      || /maximum context length/i.test(errorBody)\n      || (response.status >= 500\n        && response.status < 600\n        && body.length > 2_000_000)\n\n    if (isContextOverflow) {\n      // Return HTTP 400 with \"prompt is too long\" so Claude Code's reactive\n      // compaction kicks in (verified from Claude Code source: services/api/\n      // errors.ts triggers tryReactiveCompact on this exact phrase). Returning\n      // 529/overloaded_error would only trigger retry-with-backoff (3 attempts\n      // then fatal \"Repeated 529 Overloaded errors\").\n      //\n      // Token estimate: bytes/4 is a rough but conservative approximation.\n      // Claude Code uses the gap (estimatedTokens - modelLimit) to decide how\n      // many message groups to peel in a single compaction pass.\n      //\n      // Use max_prompt_tokens (the field Copilot actually enforces — e.g.\n      // 168K for opus-4.7) rather than max_context_window_tokens (the\n      // total window incl. output, ≥200K). Falling back to the larger field\n      // and finally 200K preserves behavior for models lacking metadata.\n      throw createPromptTooLongError(payload, body.length)\n    }\n\n    throw new HTTPError(\n      \"Failed to create chat completions\",\n      new Response(errorBody, {\n        status: response.status,\n        statusText: response.statusText,\n        headers: response.headers,\n      }),\n    )\n  }\n\n  if (payload.stream) {\n    return events(response)\n  }\n\n  return (await response.json()) as ChatCompletionResponse\n}\n\n// Streaming types\n\nexport interface ChatCompletionChunk {\n  id: string\n  object: \"chat.completion.chunk\"\n  created: number\n  model: string\n  choices: Array<Choice>\n  system_fingerprint?: string\n  usage?: {\n    prompt_tokens: number\n    completion_tokens: number\n    total_tokens: number\n    prompt_tokens_details?: {\n      cached_tokens: number\n    }\n    completion_tokens_details?: {\n      accepted_prediction_tokens: number\n      rejected_prediction_tokens: number\n    }\n  }\n}\n\ninterface Delta {\n  content?: string | null\n  role?: \"user\" | \"assistant\" | \"system\" | \"tool\"\n  tool_calls?: Array<{\n    index: number\n    id?: string\n    type?: \"function\"\n    function?: {\n      name?: string\n      arguments?: string\n    }\n  }>\n}\n\ninterface Choice {\n  index: number\n  delta: Delta\n  finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null\n  logprobs: object | null\n}\n\n// Non-streaming types\n\nexport interface ChatCompletionResponse {\n  id: string\n  object: \"chat.completion\"\n  created: number\n  model: string\n  choices: Array<ChoiceNonStreaming>\n  system_fingerprint?: string\n  usage?: {\n    prompt_tokens: number\n    completion_tokens: number\n    total_tokens: number\n    prompt_tokens_details?: {\n      cached_tokens: number\n    }\n  }\n}\n\ninterface ResponseMessage {\n  role: \"assistant\"\n  content: string | null\n  tool_calls?: Array<ToolCall>\n}\n\ninterface ChoiceNonStreaming {\n  index: number\n  message: ResponseMessage\n  logprobs: object | null\n  finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\"\n}\n\n// Payload types\n\nexport interface ChatCompletionsPayload {\n  messages: Array<Message>\n  model: string\n  temperature?: number | null\n  top_p?: number | null\n  max_tokens?: number | null\n  stop?: string | Array<string> | null\n  n?: number | null\n  stream?: boolean | null\n\n  frequency_penalty?: number | null\n  presence_penalty?: number | null\n  logit_bias?: Record<string, number> | null\n  logprobs?: boolean | null\n  response_format?: { type: \"json_object\" } | null\n  seed?: number | null\n  thinking?: { type: \"enabled\" | \"disabled\" } | null\n  reasoning_effort?: \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\" | null\n  tools?: Array<Tool> | null\n  tool_choice?:\n    | \"none\"\n    | \"auto\"\n    | \"required\"\n    | { type: \"function\"; function: { name: string } }\n    | null\n  user?: string | null\n}\n\nexport interface Tool {\n  type: \"function\"\n  function: {\n    name: string\n    description?: string\n    parameters: Record<string, unknown>\n  }\n}\n\nexport interface Message {\n  role: \"user\" | \"assistant\" | \"system\" | \"tool\" | \"developer\"\n  content: string | Array<ContentPart> | null\n\n  name?: string\n  tool_calls?: Array<ToolCall>\n  tool_call_id?: string\n}\n\nexport interface ToolCall {\n  id: string\n  type: \"function\"\n  function: {\n    name: string\n    arguments: string\n  }\n}\n\nexport type ContentPart = TextPart | ImagePart\n\nexport interface TextPart {\n  type: \"text\"\n  text: string\n}\n\nexport interface ImagePart {\n  type: \"image_url\"\n  image_url: {\n    url: string\n    detail?: \"low\" | \"high\" | \"auto\"\n  }\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE, type SSEMessage } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport { getTokenCount } from \"~/lib/tokenizer\"\nimport { isNullish } from \"~/lib/utils\"\nimport {\n  createChatCompletions,\n  type ChatCompletionResponse,\n  type ChatCompletionsPayload,\n} from \"~/services/copilot/create-chat-completions\"\n\nexport async function handleCompletion(c: Context) {\n  await checkRateLimit(state)\n\n  let payload = await c.req.json<ChatCompletionsPayload>()\n  consola.debug(\"Request payload:\", JSON.stringify(payload).slice(-400))\n\n  // Find the selected model\n  const selectedModel = state.models?.data.find(\n    (model) => model.id === payload.model,\n  )\n\n  // Calculate and display token count\n  try {\n    if (selectedModel) {\n      const tokenCount = await getTokenCount(payload, selectedModel)\n      consola.info(\"Current token count:\", tokenCount)\n    } else {\n      consola.warn(\"No model selected, skipping token count calculation\")\n    }\n  } catch (error) {\n    consola.warn(\"Failed to calculate token count:\", error)\n  }\n\n  if (state.manualApprove) await awaitApproval()\n\n  if (isNullish(payload.max_tokens)) {\n    payload = {\n      ...payload,\n      max_tokens: selectedModel?.capabilities.limits.max_output_tokens,\n    }\n    consola.debug(\"Set max_tokens to:\", JSON.stringify(payload.max_tokens))\n  }\n\n  const response = await createChatCompletions(payload)\n\n  if (isNonStreaming(response)) {\n    consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n    return c.json(response)\n  }\n\n  consola.debug(\"Streaming response\")\n  return streamSSE(c, async (stream) => {\n    try {\n      for await (const chunk of response) {\n        consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n        await stream.writeSSE(chunk as SSEMessage)\n      }\n    } catch (error) {\n      consola.error(\"Streaming error:\", error)\n      await stream.writeSSE({\n        data: JSON.stringify({\n          error: {\n            message:\n              error instanceof Error ? error.message : \"Stream interrupted\",\n            type: \"server_error\",\n          },\n        }),\n      })\n    }\n  })\n}\n\nconst isNonStreaming = (\n  response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse => Object.hasOwn(response, \"choices\")\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCompletion } from \"./handler\"\n\nexport const completionRoutes = new Hono()\n\ncompletionRoutes.post(\"/\", async (c) => {\n  try {\n    return await handleCompletion(c)\n  } catch (error) {\n    return await forwardError(c, error)\n  }\n})\n","import { Hono } from \"hono\"\n\nimport { getRequestTraces } from \"~/lib/request-trace\"\n\nexport const debugRoutes = new Hono()\n\ndebugRoutes.get(\"/requests\", (c) =>\n  c.json({\n    object: \"list\",\n    data: getRequestTraces(),\n  }),\n)\n","import { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { copilotFetch } from \"~/lib/copilot-fetch\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createEmbeddings = async (payload: EmbeddingRequest) => {\n  if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n  const response = await copilotFetch(`${copilotBaseUrl(state)}/embeddings`, {\n    method: \"POST\",\n    headers: copilotHeaders(state),\n    body: JSON.stringify(payload),\n  })\n\n  if (!response.ok) throw new HTTPError(\"Failed to create embeddings\", response)\n\n  return (await response.json()) as EmbeddingResponse\n}\n\nexport interface EmbeddingRequest {\n  input: string | Array<string>\n  model: string\n}\n\nexport interface Embedding {\n  object: string\n  embedding: Array<number>\n  index: number\n}\n\nexport interface EmbeddingResponse {\n  object: string\n  data: Array<Embedding>\n  model: string\n  usage: {\n    prompt_tokens: number\n    total_tokens: number\n  }\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport {\n  createEmbeddings,\n  type EmbeddingRequest,\n} from \"~/services/copilot/create-embeddings\"\n\nexport const embeddingRoutes = new Hono()\n\nembeddingRoutes.post(\"/\", async (c) => {\n  try {\n    const payload = await c.req.json<EmbeddingRequest>()\n    const response = await createEmbeddings(payload)\n\n    return c.json(response)\n  } catch (error) {\n    return await forwardError(c, error)\n  }\n})\n","import { type AnthropicResponse } from \"./anthropic-types\"\n\nexport function mapOpenAIStopReasonToAnthropic(\n  finishReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null,\n): AnthropicResponse[\"stop_reason\"] {\n  if (finishReason === null) {\n    return null\n  }\n  const stopReasonMap = {\n    stop: \"end_turn\",\n    length: \"max_tokens\",\n    tool_calls: \"tool_use\",\n    // Anthropic's spec uses \"refusal\" when the model declines to respond\n    // due to safety/content policy. Map Copilot's \"content_filter\" to that\n    // so Claude Code can surface a meaningful UX (it has a special render\n    // path for refusal blocks).\n    content_filter: \"refusal\",\n  } as const\n  return stopReasonMap[finishReason]\n}\n","import consola from \"consola\"\n\nimport { state } from \"~/lib/state\"\nimport {\n  type ChatCompletionResponse,\n  type ChatCompletionsPayload,\n  type ContentPart,\n  type Message,\n  type TextPart,\n  type Tool,\n  type ToolCall,\n} from \"~/services/copilot/create-chat-completions\"\n\nimport {\n  type AnthropicAssistantContentBlock,\n  type AnthropicAssistantMessage,\n  type AnthropicDocumentBlock,\n  type AnthropicMessage,\n  type AnthropicMessagesPayload,\n  type AnthropicResponse,\n  type AnthropicTextBlock,\n  type AnthropicTool,\n  type AnthropicToolResultBlock,\n  type AnthropicToolUseBlock,\n  type AnthropicUserContentBlock,\n  type AnthropicUserMessage,\n} from \"./anthropic-types\"\nimport { mapOpenAIStopReasonToAnthropic } from \"./utils\"\n\n// Payload translation\n\nexport function translateToOpenAI(\n  payload: AnthropicMessagesPayload,\n): ChatCompletionsPayload {\n  const messages = stripTrailingAssistantPrefill(\n    translateAnthropicMessagesToOpenAI(payload.messages, payload.system),\n  )\n  const model = translateModelName(payload.model)\n\n  return {\n    model,\n    messages,\n    max_tokens: payload.max_tokens,\n    stop: payload.stop_sequences,\n    stream: payload.stream,\n    temperature: payload.temperature,\n    top_p: payload.top_p,\n    user: payload.metadata?.user_id,\n    tools: translateAnthropicToolsToOpenAI(payload.tools),\n    tool_choice: translateAnthropicToolChoiceToOpenAI(payload.tool_choice),\n    thinking: translateAnthropicThinkingToOpenAI(payload.thinking),\n    reasoning_effort: translateReasoningEffort(\n      model,\n      payload.output_config?.effort,\n    ),\n  }\n}\n\nfunction translateReasoningEffort(\n  model: string,\n  effort: ChatCompletionsPayload[\"reasoning_effort\"],\n): ChatCompletionsPayload[\"reasoning_effort\"] {\n  if (!effort) return undefined\n\n  const modelMetadata = state.models?.data.find((m) => m.id === model)\n  if (!modelMetadata) return effort\n\n  const supportedEfforts = modelMetadata.capabilities.supports.reasoning_effort\n  if (!supportedEfforts?.length) return undefined\n\n  return supportedEfforts.includes(effort) ? effort : undefined\n}\n\nfunction stripTrailingAssistantPrefill(\n  messages: Array<Message>,\n): Array<Message> {\n  let end = messages.length\n  while (end > 0 && messages[end - 1].role === \"assistant\") {\n    end--\n  }\n\n  if (end === messages.length) {\n    return messages\n  }\n\n  consola.warn(\n    `Stripped ${messages.length - end} trailing assistant prefill message(s) unsupported by Copilot chat completions`,\n  )\n  return messages.slice(0, end)\n}\n\n/**\n * Pre-process the Anthropic payload to handle async / proxy-side concerns\n * (currently: PDF document block extraction). Returns a new payload with\n * `document` blocks replaced by extracted-text blocks.\n *\n * Throws HTTPError (Anthropic-shaped) on PDF extraction failure.\n */\nexport async function preprocessAnthropicPayload(\n  payload: AnthropicMessagesPayload,\n): Promise<AnthropicMessagesPayload> {\n  // Fast path: no document blocks anywhere.\n  const hasDocuments = payload.messages.some(\n    (m) =>\n      Array.isArray(m.content) && m.content.some((b) => b.type === \"document\"),\n  )\n  if (!hasDocuments) return payload\n\n  const newMessages: Array<AnthropicMessage> = []\n  for (const msg of payload.messages) {\n    if (msg.role !== \"user\" || !Array.isArray(msg.content)) {\n      newMessages.push(msg)\n      continue\n    }\n    const newContent: Array<AnthropicUserContentBlock> = []\n    for (const block of msg.content) {\n      if (block.type === \"document\") {\n        newContent.push(...(await extractDocumentBlock(block)))\n      } else {\n        newContent.push(block)\n      }\n    }\n    newMessages.push({ role: \"user\", content: newContent })\n  }\n  return { ...payload, messages: newMessages }\n}\n\nasync function extractDocumentBlock(\n  block: AnthropicDocumentBlock,\n): Promise<Array<AnthropicTextBlock>> {\n  // Plain-text document source — just inline.\n  if (block.source.type === \"text\") {\n    return [\n      {\n        type: \"text\",\n        text: documentHeader(block) + block.source.data,\n      },\n    ]\n  }\n\n  // URL document source — Copilot can't fetch URLs; skip with note.\n  if (block.source.type === \"url\") {\n    return [\n      {\n        type: \"text\",\n        text:\n          documentHeader(block)\n          + `[document at ${block.source.url} not inlined — proxy does not fetch external URLs]`,\n      },\n    ]\n  }\n\n  // base64 PDF — extract via pdf-parse.\n  const { extractPdfText } = await import(\"~/lib/pdf\")\n  const extracted = await extractPdfText(block.source.data)\n  return [\n    {\n      type: \"text\",\n      text:\n        documentHeader(block)\n        + `[Extracted text from PDF (${extracted.pageCount} page${extracted.pageCount === 1 ? \"\" : \"s\"}${extracted.truncated ? \", truncated\" : \"\"}):]\\n\\n`\n        + extracted.text,\n    },\n  ]\n}\n\nfunction documentHeader(block: AnthropicDocumentBlock): string {\n  const parts: Array<string> = []\n  if (block.title) parts.push(`Document: ${block.title}`)\n  if (block.context) parts.push(`Context: ${block.context}`)\n  return parts.length > 0 ? parts.join(\"\\n\") + \"\\n\\n\" : \"\"\n}\n\n// Static fallback mappings, used when state.models hasn't loaded or the\n// dynamic resolver can't find a family match.\nconst MODEL_NAME_FALLBACK: Record<string, string> = {\n  haiku: \"claude-haiku-4.5\",\n  sonnet: \"claude-sonnet-5\",\n  opus: \"claude-opus-5\",\n}\n\nconst LEGACY_OPUS_FALLBACK = \"claude-opus-4.8\"\n\nconst CLAUDE_FAMILIES = [\"opus\", \"sonnet\", \"haiku\"] as const\ntype ClaudeFamily = (typeof CLAUDE_FAMILIES)[number]\n\n/** Detect which Claude family a requested model name belongs to.\n *  Handles all the shapes Claude Code emits: bare (`claude-opus-4-5`),\n *  dated (`claude-opus-4-5-20251101`), AWS (`claude-opus-4-5@20251101`),\n *  Bedrock (`claude-opus-4-5-20251101-v1:0`), short alias (`opus`), etc. */\nfunction detectFamily(model: string): ClaudeFamily | null {\n  const lower = model.toLowerCase()\n  for (const family of CLAUDE_FAMILIES) {\n    if (lower.includes(family)) return family\n  }\n  return null\n}\n\n/** Parse a numeric version tuple from a Copilot model id like\n *  `claude-opus-4.7` → [4, 7] or `claude-sonnet-5` → [5, 0].\n *  Returns [0, 0] if no version found. */\nfunction parseCopilotVersion(id: string): [number, number] {\n  const match =\n    /(?:opus|sonnet|haiku)-(\\d{1,2})(?:[.-](\\d{1,2}))?(?:$|[-_.])/i.exec(id)\n  if (!match) return [0, 0]\n  return [Number(match[1]), match[2] ? Number(match[2]) : 0]\n}\n\n/** Pick the best Copilot model in a family (and optionally a major version).\n *  Highest version wins; among equal versions, prefer the `-1m` variant. */\nfunction pickLatestCopilotModel(\n  family: ClaudeFamily,\n  majorVersion?: number,\n): string | null {\n  const candidates =\n    state.models?.data.filter(\n      (m) =>\n        m.id.toLowerCase().includes(family)\n        && (majorVersion === undefined\n          || parseCopilotVersion(m.id)[0] === majorVersion),\n    ) ?? []\n  if (candidates.length === 0) return null\n\n  let best = candidates[0]\n  let bestVersion = parseCopilotVersion(best.id)\n  let bestIs1m = best.id.includes(\"-1m\")\n\n  for (const m of candidates.slice(1)) {\n    const v = parseCopilotVersion(m.id)\n    const is1m = m.id.includes(\"-1m\")\n    const newer =\n      v[0] > bestVersion[0]\n      || (v[0] === bestVersion[0] && v[1] > bestVersion[1])\n    const sameVersionPrefer1m =\n      v[0] === bestVersion[0] && v[1] === bestVersion[1] && is1m && !bestIs1m\n    if (newer || sameVersionPrefer1m) {\n      best = m\n      bestVersion = v\n      bestIs1m = is1m\n    }\n  }\n  return best.id\n}\n\nfunction parseRequestedClaudeVersion(\n  model: string,\n  family: ClaudeFamily,\n): [number, number] | null {\n  const match = new RegExp(\n    `${family}-(\\\\d{1,2})(?:[.-](\\\\d{1,2}))?(?:$|[-@:.])`,\n  ).exec(model.toLowerCase())\n  if (!match) return null\n  return [Number(match[1]), match[2] ? Number(match[2]) : 0]\n}\n\nfunction isCopilotClaudeModelId(model: string): boolean {\n  const match =\n    /^claude-(?:opus|sonnet|haiku)-(\\d{1,2})(?:\\.(\\d{1,2})(?:-.+)?)?$/i.exec(\n      model,\n    )\n  if (!match) return false\n  return Boolean(match[2]) || Number(match[1]) >= 5\n}\n\nfunction unadvertisedClaudeModelFallback(\n  model: string,\n  family: ClaudeFamily,\n  version: [number, number],\n): string | null {\n  if (family === \"opus\" && version[0] === 5 && version[1] === 0) {\n    return MODEL_NAME_FALLBACK.opus\n  }\n  if (family === \"opus\" && version[0] === 4) return LEGACY_OPUS_FALLBACK\n  if (!state.models && isCopilotClaudeModelId(model)) return model\n  return null\n}\n\n/** Pick the Copilot model matching the user-requested Claude version.\n *  Among equal versions, prefer the `-1m` variant. */\nfunction pickMatchingCopilotModel(\n  family: ClaudeFamily,\n  version: [number, number],\n): string | null {\n  const candidates =\n    state.models?.data.filter((m) => {\n      const candidateVersion = parseCopilotVersion(m.id)\n      return (\n        m.id.toLowerCase().includes(family)\n        && candidateVersion[0] === version[0]\n        && candidateVersion[1] === version[1]\n      )\n    }) ?? []\n  if (candidates.length === 0) return null\n\n  let best = candidates[0]\n  let bestIs1m = best.id.includes(\"-1m\")\n\n  for (const m of candidates.slice(1)) {\n    const is1m = m.id.includes(\"-1m\")\n    if (is1m && !bestIs1m) {\n      best = m\n      bestIs1m = is1m\n    }\n  }\n  return best.id\n}\n\nfunction translateModelName(model: string): string {\n  // Claude Code uses Anthropic model IDs (e.g. claude-opus-4-5-20251101);\n  // Copilot uses version-only names (e.g. claude-opus-4.7). Preserve the\n  // version Claude Code requested instead of upgrading a family to latest.\n\n  const family = detectFamily(model)\n  if (family) {\n    const override = process.env[`COPILOT_OVERRIDE_${family.toUpperCase()}`]\n    if (override) return override\n  }\n\n  // 1. Already a valid Copilot model id → pass through unchanged.\n  if (state.models?.data.some((m) => m.id === model)) {\n    return model\n  }\n\n  // 2. Exact short aliases use pinned defaults. These come from user/tool\n  //    settings, so do not reinterpret them as \"latest family member\".\n  if (MODEL_NAME_FALLBACK[model]) {\n    return MODEL_NAME_FALLBACK[model]\n  }\n\n  // 3. For explicit Claude version names, use the matching Copilot version\n  //    when available. If the input is already a Copilot-shaped dotted id,\n  //    preserve it even when state.models is not loaded yet.\n  if (family) {\n    const requestedVersion = parseRequestedClaudeVersion(model, family)\n    if (requestedVersion) {\n      const matching = pickMatchingCopilotModel(family, requestedVersion)\n      if (matching) return matching\n      const sameMajor = pickLatestCopilotModel(family, requestedVersion[0])\n      if (sameMajor) return sameMajor\n      const fallback = unadvertisedClaudeModelFallback(\n        model,\n        family,\n        requestedVersion,\n      )\n      if (fallback) return fallback\n    }\n\n    const latest = pickLatestCopilotModel(family)\n    if (latest) return latest\n\n    return MODEL_NAME_FALLBACK[family]\n  }\n\n  return model\n}\n\nfunction translateAnthropicMessagesToOpenAI(\n  anthropicMessages: Array<AnthropicMessage>,\n  system: string | Array<AnthropicTextBlock> | undefined,\n): Array<Message> {\n  const systemMessages = handleSystemPrompt(system)\n\n  const otherMessages = anthropicMessages.flatMap((message) =>\n    message.role === \"user\" ?\n      handleUserMessage(message)\n    : handleAssistantMessage(message),\n  )\n\n  return [...systemMessages, ...otherMessages]\n}\n\n// Reserved keywords that GitHub Copilot API blocks in system prompts\n// These will be completely removed from system prompts (case-insensitive)\nconst RESERVED_KEYWORD_PATTERNS = [\n  /x-anthropic-billing-header/gi,\n  /anthropic-billing-header/gi,\n  /x-anthropic-/gi,\n]\n\nfunction sanitizeSystemPrompt(text: string): string {\n  let sanitized = text\n  for (const pattern of RESERVED_KEYWORD_PATTERNS) {\n    sanitized = sanitized.replaceAll(pattern, \"\")\n  }\n  return sanitized\n}\n\nfunction handleSystemPrompt(\n  system: string | Array<AnthropicTextBlock> | undefined,\n): Array<Message> {\n  if (!system) {\n    return []\n  }\n\n  if (typeof system === \"string\") {\n    return [{ role: \"system\", content: sanitizeSystemPrompt(system) }]\n  } else {\n    const systemText = system.map((block) => block.text).join(\"\\n\\n\")\n    return [{ role: \"system\", content: sanitizeSystemPrompt(systemText) }]\n  }\n}\n\nfunction handleUserMessage(message: AnthropicUserMessage): Array<Message> {\n  const newMessages: Array<Message> = []\n\n  if (Array.isArray(message.content)) {\n    const toolResultBlocks = message.content.filter(\n      (block): block is AnthropicToolResultBlock =>\n        block.type === \"tool_result\",\n    )\n    const otherBlocks = message.content.filter(\n      (block) => block.type !== \"tool_result\",\n    )\n\n    // Tool results must come first to maintain protocol: tool_use -> tool_result -> user\n    for (const block of toolResultBlocks) {\n      newMessages.push({\n        role: \"tool\",\n        tool_call_id: block.tool_use_id,\n        content: mapContent(block.content),\n      })\n    }\n\n    if (otherBlocks.length > 0) {\n      newMessages.push({\n        role: \"user\",\n        content: mapContent(otherBlocks),\n      })\n    }\n  } else {\n    newMessages.push({\n      role: \"user\",\n      content: mapContent(message.content),\n    })\n  }\n\n  return newMessages\n}\n\nfunction handleAssistantMessage(\n  message: AnthropicAssistantMessage,\n): Array<Message> {\n  if (!Array.isArray(message.content)) {\n    return [\n      {\n        role: \"assistant\",\n        content: mapContent(message.content),\n      },\n    ]\n  }\n\n  const toolUseBlocks = message.content.filter(\n    (block): block is AnthropicToolUseBlock => block.type === \"tool_use\",\n  )\n\n  const textBlocks = message.content.filter(\n    (block): block is AnthropicTextBlock => block.type === \"text\",\n  )\n\n  // Thinking blocks have signed-by-Anthropic semantics that Copilot can't\n  // verify or replay. Promoting their content to plain text would destroy\n  // the assistant turn semantics (the model would treat its own private\n  // reasoning as visible text). Drop them cleanly on the request side.\n  const allTextContent = textBlocks.map((b) => b.text).join(\"\\n\\n\")\n\n  return toolUseBlocks.length > 0 ?\n      [\n        {\n          role: \"assistant\",\n          content: allTextContent || null,\n          tool_calls: toolUseBlocks.map((toolUse) => ({\n            id: toolUse.id,\n            type: \"function\",\n            function: {\n              name: toolUse.name,\n              arguments: JSON.stringify(toolUse.input),\n            },\n          })),\n        },\n      ]\n    : [\n        {\n          role: \"assistant\",\n          content: mapContent(message.content),\n        },\n      ]\n}\n\nfunction mapContent(\n  content:\n    | string\n    | Array<AnthropicUserContentBlock | AnthropicAssistantContentBlock>,\n): string | Array<ContentPart> | null {\n  if (typeof content === \"string\") {\n    return content\n  }\n  if (!Array.isArray(content)) {\n    return null\n  }\n\n  const hasImage = content.some((block) => block.type === \"image\")\n  if (!hasImage) {\n    return content\n      .filter((block): block is AnthropicTextBlock => block.type === \"text\")\n      .map((block) => block.text)\n      .join(\"\\n\\n\")\n  }\n\n  const contentParts: Array<ContentPart> = []\n  for (const block of content) {\n    switch (block.type) {\n      case \"text\": {\n        contentParts.push({ type: \"text\", text: block.text })\n\n        break\n      }\n      // Thinking blocks dropped — see handleAssistantMessage rationale.\n      case \"image\": {\n        contentParts.push({\n          type: \"image_url\",\n          image_url: {\n            url: `data:${block.source.media_type};base64,${block.source.data}`,\n          },\n        })\n\n        break\n      }\n      // No default\n    }\n  }\n  return contentParts\n}\n\nfunction translateAnthropicToolsToOpenAI(\n  anthropicTools: Array<AnthropicTool> | undefined,\n): Array<Tool> | undefined {\n  if (!anthropicTools) {\n    return undefined\n  }\n  return anthropicTools.map((tool) => ({\n    type: \"function\",\n    function: {\n      name: tool.name,\n      description: tool.description,\n      parameters: tool.input_schema,\n    },\n  }))\n}\n\n/**\n * Map Anthropic `thinking` to the Copilot-compatible format.\n * Anthropic uses `'enabled'` and `'adaptive'`; Copilot only accepts\n * `'enabled'` or `'disabled'`. Both `'enabled'` and `'adaptive'` map to\n * `'enabled'` since they both request extended thinking.\n */\nfunction translateAnthropicThinkingToOpenAI(\n  thinking: AnthropicMessagesPayload[\"thinking\"],\n): ChatCompletionsPayload[\"thinking\"] {\n  if (!thinking) return undefined\n  // Copilot only supports 'enabled' | 'disabled' — map 'adaptive' to 'enabled'\n  return { type: \"enabled\" }\n}\n\nfunction translateAnthropicToolChoiceToOpenAI(\n  anthropicToolChoice: AnthropicMessagesPayload[\"tool_choice\"],\n): ChatCompletionsPayload[\"tool_choice\"] {\n  if (!anthropicToolChoice) {\n    return undefined\n  }\n\n  switch (anthropicToolChoice.type) {\n    case \"auto\": {\n      return \"auto\"\n    }\n    case \"any\": {\n      return \"required\"\n    }\n    case \"tool\": {\n      if (anthropicToolChoice.name) {\n        return {\n          type: \"function\",\n          function: { name: anthropicToolChoice.name },\n        }\n      }\n      return undefined\n    }\n    case \"none\": {\n      return \"none\"\n    }\n    default: {\n      return undefined\n    }\n  }\n}\n\n// Response translation\n\n// eslint-disable-next-line complexity\nexport function translateToAnthropic(\n  response: ChatCompletionResponse,\n  /** Original client-requested model id, echoed back so Claude Code displays\n   *  the model the user asked for rather than Copilot's internal id. */\n  clientModel?: string,\n): AnthropicResponse {\n  // Merge content from all choices\n  const allTextBlocks: Array<AnthropicTextBlock> = []\n  const allToolUseBlocks: Array<AnthropicToolUseBlock> = []\n  let stopReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null =\n    null // default\n  stopReason = response.choices[0]?.finish_reason ?? stopReason\n\n  // Process all choices to extract text and tool use blocks\n  for (const choice of response.choices) {\n    const textBlocks = getAnthropicTextBlocks(choice.message.content)\n    const toolUseBlocks = getAnthropicToolUseBlocks(choice.message.tool_calls)\n\n    allTextBlocks.push(...textBlocks)\n    allToolUseBlocks.push(...toolUseBlocks)\n\n    // Use the finish_reason from the first choice, or prioritize tool_calls\n    if (choice.finish_reason === \"tool_calls\" || stopReason === \"stop\") {\n      stopReason = choice.finish_reason\n    }\n  }\n\n  // Note: GitHub Copilot doesn't generate thinking blocks, so we don't include them in responses\n\n  return {\n    id: response.id,\n    type: \"message\",\n    role: \"assistant\",\n    model: clientModel ?? response.model,\n    content: [...allTextBlocks, ...allToolUseBlocks],\n    stop_reason: mapOpenAIStopReasonToAnthropic(stopReason),\n    stop_sequence: null,\n    usage: {\n      input_tokens:\n        (response.usage?.prompt_tokens ?? 0)\n        - (response.usage?.prompt_tokens_details?.cached_tokens ?? 0),\n      output_tokens: response.usage?.completion_tokens ?? 0,\n      ...(response.usage?.prompt_tokens_details?.cached_tokens\n        !== undefined && {\n        cache_read_input_tokens:\n          response.usage.prompt_tokens_details.cached_tokens,\n      }),\n    },\n  }\n}\n\nfunction getAnthropicTextBlocks(\n  messageContent: Message[\"content\"],\n): Array<AnthropicTextBlock> {\n  if (typeof messageContent === \"string\") {\n    return [{ type: \"text\", text: messageContent }]\n  }\n\n  if (Array.isArray(messageContent)) {\n    return messageContent\n      .filter((part): part is TextPart => part.type === \"text\")\n      .map((part) => ({ type: \"text\", text: part.text }))\n  }\n\n  return []\n}\n\nfunction getAnthropicToolUseBlocks(\n  toolCalls: Array<ToolCall> | undefined,\n): Array<AnthropicToolUseBlock> {\n  if (!toolCalls) {\n    return []\n  }\n  return toolCalls.map((toolCall) => {\n    let input: Record<string, unknown> = {}\n    try {\n      const parsed = JSON.parse(toolCall.function.arguments) as unknown\n      if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n        input = parsed as Record<string, unknown>\n      }\n    } catch {\n      // Copilot can emit malformed JSON for tool args (especially mid-stream\n      // truncation or partial outputs). Fall back to an empty object so the\n      // assistant turn is at least well-formed; Claude Code will surface the\n      // missing args via tool execution failure rather than a hard crash.\n    }\n    return {\n      type: \"tool_use\",\n      id: toolCall.id,\n      name: toolCall.function.name,\n      input,\n    }\n  })\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { state } from \"~/lib/state\"\nimport { getTokenCount } from \"~/lib/tokenizer\"\n\nimport { type AnthropicMessagesPayload } from \"./anthropic-types\"\nimport { translateToOpenAI } from \"./non-stream-translation\"\n\n/**\n * Handles token counting for Anthropic messages\n */\nexport async function handleCountTokens(c: Context) {\n  try {\n    const anthropicBeta = c.req.header(\"anthropic-beta\")\n\n    const anthropicPayload = await c.req.json<AnthropicMessagesPayload>()\n\n    const openAIPayload = translateToOpenAI(anthropicPayload)\n\n    const selectedModel = state.models?.data.find(\n      (model) => model.id === openAIPayload.model,\n    )\n\n    if (!selectedModel) {\n      consola.warn(\"Model not found, returning default token count\")\n      return c.json(\n        {\n          type: \"error\",\n          error: {\n            type: \"not_found_error\",\n            message: `Model '${openAIPayload.model}' not found`,\n          },\n        },\n        404,\n      )\n    }\n\n    const tokenCount = await getTokenCount(openAIPayload, selectedModel)\n\n    if (anthropicPayload.tools && anthropicPayload.tools.length > 0) {\n      let mcpToolExist = false\n      if (anthropicBeta?.startsWith(\"claude-code\")) {\n        mcpToolExist = anthropicPayload.tools.some((tool) =>\n          tool.name.startsWith(\"mcp__\"),\n        )\n      }\n      if (!mcpToolExist) {\n        if (anthropicPayload.model.startsWith(\"claude\")) {\n          // https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/overview#pricing\n          tokenCount.input = tokenCount.input + 346\n        } else if (anthropicPayload.model.startsWith(\"grok\")) {\n          tokenCount.input = tokenCount.input + 480\n        }\n      }\n    }\n\n    // Anthropic's /v1/messages/count_tokens returns INPUT tokens only\n    // (https://docs.anthropic.com/en/api/messages-count-tokens). Including\n    // an estimated output count would mislead Claude Code's auto-compact\n    // accounting (autoCompact.ts uses this to gate when to compact).\n    let finalTokenCount = tokenCount.input\n    if (anthropicPayload.model.startsWith(\"claude\")) {\n      finalTokenCount = Math.round(finalTokenCount * 1.15)\n    } else if (anthropicPayload.model.startsWith(\"grok\")) {\n      finalTokenCount = Math.round(finalTokenCount * 1.03)\n    }\n\n    consola.info(\"Token count:\", finalTokenCount)\n\n    return c.json({\n      input_tokens: finalTokenCount,\n    })\n  } catch (error) {\n    consola.error(\"Error counting tokens:\", error)\n    return c.json(\n      {\n        type: \"error\" as const,\n        error: {\n          type: \"api_error\",\n          message:\n            error instanceof Error ? error.message : \"Failed to count tokens\",\n        },\n      },\n      500,\n    )\n  }\n}\n","/**\n * Context management for Copilot API payloads.\n *\n * Enforces TWO ceilings, whichever is smaller for a given model:\n *   1. Hard byte ceiling (~5 MB) — Copilot's Azure Front Door cliff\n *   2. Token-derived byte ceiling — model's max_prompt_tokens × 3.5 chars\n *\n * The token-derived ceiling prevents `model_max_prompt_tokens_exceeded`\n * rejections on models with stricter caps (e.g. opus-4.7 = 168K tokens),\n * which a 1 MB payload can easily breach.\n *\n * Fast path (~99% of Claude Code requests): byte size check → return.\n * Slow path: prune tool outputs → strip images → drop oldest messages →\n *           byte-based final backstop.\n */\n\nimport consola from \"consola\"\n\nimport type {\n  ChatCompletionsPayload,\n  Message,\n} from \"~/services/copilot/create-chat-completions\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\nimport { getKnownModelPromptLimit } from \"./model-limits\"\n\n// ── Configuration ───────────────────────────────────────────────────────────\n\n/**\n * Hard byte ceiling for Copilot. Empirically the cliff is at ~5.4 MB for\n * Azure Front Door; we set the proxy ceiling at 5,000,000 to leave ~400 KB\n * headroom for headers, tool definitions, and downstream JSON framing.\n *\n * Why 5 MB and not 2.5 MB (v0.9.1-v0.10.2 value):\n *   The 2.5 MB ceiling fired aggressively on normal Claude Code sessions\n *   (typical 6 MB → 0.9 MB prune per turn). The pruned payload causes\n *   Copilot to report a small prompt_tokens count, which Claude Code uses\n *   to compute its local context estimate via tokenCountWithEstimation.\n *   Because Claude Code's local message array still holds the full unpruned\n *   conversation, its local count climbs by the rough delta each turn until\n *   it hits the blocking limit (window - 3K) and Claude Code emits\n *   \"Context limit reached\" via the preempt path in query.ts:641 — without\n *   ever calling our proxy, so auto-compact never fires.\n *\n *   Raising the ceiling to 5 MB lets normal payloads pass through unmodified.\n *   Copilot then returns honest prompt_tokens, and Claude Code's auto-compact\n *   threshold (window - 13K) trips on schedule. Pruning still kicks in as a\n *   last-resort safety net for genuinely oversized payloads (≥5 MB), which\n *   is rare in normal Claude Code use.\n *\n *   This restores the v0.8.0 behavior (no proxy-side context manager) which\n *   the user reports worked reliably for auto-compact.\n */\nconst MAX_PAYLOAD_BYTES = 5_000_000\n\n/** Conservative ceiling for custom Claude Code aliases / effort modes that do\n *  not appear in Copilot model metadata. Copilot can hang for minutes in the\n *  2.5-5 MB range, so unknown models stay below that dead zone. */\nexport const UNKNOWN_MODEL_PAYLOAD_BYTES = 1_900_000\n\n/** Minimum protected byte budget for recent tool outputs before pruning. */\nconst PRUNE_PROTECT_BYTES = 200_000\n\n/** Don't prune unless we'd reclaim at least this many bytes. */\nconst PRUNE_MINIMUM_BYTES = 50_000\n\n/** Per-message hard cap for tool output content even when \"recent\". A single\n *  giant Read of a 1MB file shouldn't blow the budget by itself. */\nconst TOOL_OUTPUT_HARD_CAP = 100_000\n\n/**\n * Empirical chars/token ratio for Claude Code payloads. Used to derive a\n * byte ceiling from the model's `max_prompt_tokens` without paying for a\n * real tokenizer pass. Real ratios on typical code-heavy Claude Code traffic\n * sit in the 3.0-3.8 range (English prose ~4.0, dense code ~3.0). We pick\n * 3.5 as a slightly conservative midpoint — it errs toward pruning a touch\n * earlier rather than letting Copilot reject. Cost: one multiplication per\n * request vs. ~300-1000ms for a real tokenizer pass on the hot path.\n */\nconst CHARS_PER_TOKEN_ESTIMATE = 3.5\n\n/**\n * Reserve this many tokens under max_prompt_tokens for max_tokens output and\n * Copilot framing overhead (function-call encoding, message-wrapping tokens).\n * Copilot's reported prompt_token count typically runs a few thousand higher\n * than ours due to encoding differences; this buffer absorbs that skew.\n */\nconst TOKEN_RESERVE = 8_000\n\nconst PRUNED_PLACEHOLDER = \"[content pruned — tool output was too old]\"\nconst TOOL_TRUNCATED_SUFFIX = \"\\n\\n[…tool output truncated to fit context]\"\nconst IMAGE_STRIPPED_PLACEHOLDER = \"[image removed to save context]\"\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Compute the effective byte ceiling for a given model.\n *\n * The proxy enforces TWO ceilings and uses whichever is smaller:\n *\n *   1. The hard byte ceiling MAX_PAYLOAD_BYTES (~5 MB) — Copilot's Azure\n *      Front Door rejects payloads >5.4 MB regardless of token count.\n *\n *   2. A token-derived byte ceiling — Copilot ALSO rejects when the\n *      tokenized prompt exceeds the model's `max_prompt_tokens` cap, which\n *      varies per model (e.g. claude-opus-4.7 = 168K, others = 200K). A 1 MB\n *      payload on opus-4.7 can easily contain 169K tokens and get rejected\n *      with `model_max_prompt_tokens_exceeded`. To prevent that, we estimate\n *      a byte budget from the token cap using a fixed chars/token ratio.\n *\n * If `max_prompt_tokens` is missing from model metadata, we fall back to\n * MAX_PAYLOAD_BYTES alone (existing behavior, no regression).\n */\nfunction computeEffectiveCeiling(model: Model): number {\n  const maxPromptTokens = getKnownModelPromptLimit(\n    model.id,\n    model.capabilities.limits,\n  )\n  if (!maxPromptTokens) return MAX_PAYLOAD_BYTES\n  const tokenDerivedBytes = Math.floor(\n    (maxPromptTokens - TOKEN_RESERVE) * CHARS_PER_TOKEN_ESTIMATE,\n  )\n  return Math.min(MAX_PAYLOAD_BYTES, tokenDerivedBytes)\n}\n\n/**\n * Fit a payload within the model's effective byte ceiling. Returns the input\n * payload unmodified in the common case (cheap byte size check).\n */\nexport function fitContext(\n  payload: ChatCompletionsPayload,\n  model: Model,\n): ChatCompletionsPayload {\n  const ceiling = computeEffectiveCeiling(model)\n  return fitPayloadToCeiling(payload, ceiling)\n}\n\nexport function fitUnknownModelContext(\n  payload: ChatCompletionsPayload,\n): ChatCompletionsPayload {\n  return fitPayloadToCeiling(payload, UNKNOWN_MODEL_PAYLOAD_BYTES)\n}\n\nexport function isPayloadOverUnknownModelCeiling(\n  payload: ChatCompletionsPayload,\n): boolean {\n  return estimatePayloadBytes(payload) > UNKNOWN_MODEL_PAYLOAD_BYTES\n}\n\nfunction fitPayloadToCeiling(\n  payload: ChatCompletionsPayload,\n  ceiling: number,\n): ChatCompletionsPayload {\n  const initialBytes = estimatePayloadBytes(payload)\n\n  // Fast path: well under the effective ceiling — just send.\n  if (initialBytes <= ceiling) {\n    return payload\n  }\n\n  consola.info(\n    `Context fit: payload ${formatBytes(initialBytes)} exceeds ${formatBytes(ceiling)} ceiling — reducing`,\n  )\n\n  // Slow path: progressive byte-based reduction.\n  let current = pruneToolOutputs(payload)\n  let bytes = estimatePayloadBytes(current)\n  if (bytes <= ceiling) {\n    consola.info(\n      `Context fit: ${formatBytes(initialBytes)} → ${formatBytes(bytes)} after tool pruning`,\n    )\n    return current\n  }\n\n  current = stripOldImages(current)\n  bytes = estimatePayloadBytes(current)\n  if (bytes <= ceiling) {\n    consola.info(\n      `Context fit: ${formatBytes(initialBytes)} → ${formatBytes(bytes)} after stripping old images`,\n    )\n    return current\n  }\n\n  // Aggressive: strip ALL images regardless of age.\n  current = stripAllImages(current)\n  bytes = estimatePayloadBytes(current)\n  if (bytes <= ceiling) {\n    consola.warn(\n      `Context fit: ${formatBytes(initialBytes)} → ${formatBytes(bytes)} after stripping ALL images`,\n    )\n    return current\n  }\n\n  // Truncate any oversized tool outputs that survived pruning (e.g. recent ones).\n  current = truncateOversizedToolOutputs(current)\n  bytes = estimatePayloadBytes(current)\n  if (bytes <= ceiling) {\n    consola.warn(\n      `Context fit: ${formatBytes(initialBytes)} → ${formatBytes(bytes)} after truncating oversized tool outputs`,\n    )\n    return current\n  }\n\n  current = dropOldMessages(current, ceiling)\n  bytes = estimatePayloadBytes(current)\n  consola.warn(\n    `Context fit: ${formatBytes(initialBytes)} → ${formatBytes(bytes)} after dropping old messages`,\n  )\n  return current\n}\n\nfunction formatBytes(b: number): string {\n  if (b < 1024) return `${b}B`\n  if (b < 1024 * 1024) return `${(b / 1024).toFixed(1)}KB`\n  return `${(b / 1024 / 1024).toFixed(2)}MB`\n}\n\n// ── Byte estimation ─────────────────────────────────────────────────────────\n\n/**\n * Cheap byte-size estimate for a payload. Uses content lengths directly\n * instead of JSON.stringify, which is ~10x faster on large payloads. The\n * estimate is a lower bound (ignores JSON framing overhead) but accurate\n * to within a few percent for realistic Claude Code payloads.\n */\nfunction estimatePayloadBytes(payload: ChatCompletionsPayload): number {\n  let bytes = 200 // baseline for top-level JSON framing\n  for (const msg of payload.messages) {\n    bytes += estimateMessageBytes(msg)\n  }\n  if (payload.tools) {\n    for (const tool of payload.tools) {\n      // Tool definitions are dense JSON; conservatively double-count via stringify.\n      bytes += JSON.stringify(tool).length + 20\n    }\n  }\n  return bytes\n}\n\nfunction estimateMessageBytes(msg: Message): number {\n  let bytes = 40 // role + framing\n  if (typeof msg.content === \"string\") {\n    bytes += msg.content.length\n  } else if (Array.isArray(msg.content)) {\n    for (const part of msg.content) {\n      if (\"text\" in part && typeof part.text === \"string\") {\n        bytes += part.text.length + 20\n      } else if (\"type\" in part && part.type === \"image_url\") {\n        bytes += part.image_url.url.length + 40\n      }\n    }\n  }\n  if (msg.tool_calls) {\n    for (const tc of msg.tool_calls) {\n      bytes += tc.function.name.length + tc.function.arguments.length + 80\n    }\n  }\n  if (msg.tool_call_id) bytes += msg.tool_call_id.length + 20\n  return bytes\n}\n\n// ── Reduction step 1: prune old tool outputs ────────────────────────────────\n\nfunction pruneToolOutputs(\n  payload: ChatCompletionsPayload,\n): ChatCompletionsPayload {\n  const messages = payload.messages\n  let protectedBytes = 0\n  let prunedBytes = 0\n  const prunedIndices: Array<number> = []\n\n  // Walk newest → oldest, protecting recent tool outputs.\n  for (let i = messages.length - 1; i >= 0; i--) {\n    const msg = messages[i]\n    if (msg.role !== \"tool\") continue\n\n    const msgBytes = estimateMessageBytes(msg)\n    if (protectedBytes < PRUNE_PROTECT_BYTES) {\n      protectedBytes += msgBytes\n    } else {\n      prunedBytes += msgBytes\n      prunedIndices.push(i)\n    }\n  }\n\n  if (prunedBytes < PRUNE_MINIMUM_BYTES) {\n    return payload\n  }\n\n  const newMessages = [...messages]\n  for (const idx of prunedIndices) {\n    newMessages[idx] = { ...newMessages[idx], content: PRUNED_PLACEHOLDER }\n  }\n\n  consola.info(\n    `Pruned ${prunedIndices.length} old tool outputs (~${prunedBytes} bytes reclaimed)`,\n  )\n  return { ...payload, messages: newMessages }\n}\n\n// ── Reduction step 2: strip base64 images from older messages ───────────────\n\nfunction stripOldImages(\n  payload: ChatCompletionsPayload,\n): ChatCompletionsPayload {\n  const messages = payload.messages\n  const newMessages = [...messages]\n  let strippedCount = 0\n  let strippedBytes = 0\n\n  // Keep images only in the last 4 messages (recent visual context).\n  const protectFromEnd = 4\n  const protectBoundary = Math.max(0, messages.length - protectFromEnd)\n\n  for (let i = 0; i < protectBoundary; i++) {\n    const msg = messages[i]\n    if (!Array.isArray(msg.content)) continue\n\n    const beforeStripped = strippedCount\n    const newContent = msg.content.map((part) => {\n      if (\"type\" in part && part.type === \"image_url\") {\n        strippedCount++\n        strippedBytes += part.image_url.url.length\n        return { type: \"text\" as const, text: IMAGE_STRIPPED_PLACEHOLDER }\n      }\n      return part\n    })\n\n    if (strippedCount > beforeStripped) {\n      newMessages[i] = { ...msg, content: newContent }\n    }\n  }\n\n  if (strippedCount > 0) {\n    consola.info(\n      `Stripped ${strippedCount} base64 images (~${strippedBytes} bytes reclaimed)`,\n    )\n  }\n  return { ...payload, messages: newMessages }\n}\n\n// ── Reduction step 2b: strip ALL images regardless of recency ───────────────\n\nfunction stripAllImages(\n  payload: ChatCompletionsPayload,\n): ChatCompletionsPayload {\n  let strippedCount = 0\n  let strippedBytes = 0\n  const newMessages = payload.messages.map((msg) => {\n    if (!Array.isArray(msg.content)) return msg\n    const before = strippedCount\n    const newContent = msg.content.map((part) => {\n      if (\"type\" in part && part.type === \"image_url\") {\n        strippedCount++\n        strippedBytes += part.image_url.url.length\n        return { type: \"text\" as const, text: IMAGE_STRIPPED_PLACEHOLDER }\n      }\n      return part\n    })\n    return strippedCount > before ? { ...msg, content: newContent } : msg\n  })\n  if (strippedCount > 0) {\n    consola.warn(\n      `Stripped ${strippedCount} ALL images (~${strippedBytes} bytes reclaimed)`,\n    )\n  }\n  return { ...payload, messages: newMessages }\n}\n\n// ── Reduction step 2c: truncate oversized tool outputs ──────────────────────\n\nfunction truncateOversizedToolOutputs(\n  payload: ChatCompletionsPayload,\n): ChatCompletionsPayload {\n  let truncatedCount = 0\n  let reclaimedBytes = 0\n  const newMessages = payload.messages.map((msg) => {\n    if (msg.role !== \"tool\") return msg\n    if (typeof msg.content !== \"string\") return msg\n    if (msg.content.length <= TOOL_OUTPUT_HARD_CAP) return msg\n    const before = msg.content.length\n    const truncated =\n      msg.content.slice(0, TOOL_OUTPUT_HARD_CAP) + TOOL_TRUNCATED_SUFFIX\n    truncatedCount++\n    reclaimedBytes += before - truncated.length\n    return { ...msg, content: truncated }\n  })\n  if (truncatedCount > 0) {\n    consola.warn(\n      `Truncated ${truncatedCount} oversized tool outputs (~${reclaimedBytes} bytes reclaimed)`,\n    )\n  }\n  return { ...payload, messages: newMessages }\n}\n\n// ── Reduction step 3: drop oldest conversation messages ─────────────────────\n\nfunction dropOldMessages(\n  payload: ChatCompletionsPayload,\n  ceiling: number,\n): ChatCompletionsPayload {\n  const systemMessages = payload.messages.filter(\n    (m) => m.role === \"system\" || m.role === \"developer\",\n  )\n  const conversationMessages = payload.messages.filter(\n    (m) => m.role !== \"system\" && m.role !== \"developer\",\n  )\n\n  // Compute reusable system byte total.\n  let baseBytes = 200\n  for (const m of systemMessages) baseBytes += estimateMessageBytes(m)\n  if (payload.tools) {\n    for (const tool of payload.tools) {\n      baseBytes += JSON.stringify(tool).length + 20\n    }\n  }\n\n  // Compute per-message byte sizes once for the conversation tail.\n  const convBytes = conversationMessages.map((m) => estimateMessageBytes(m))\n  let totalBytes = baseBytes + convBytes.reduce((a, b) => a + b, 0)\n\n  let dropped = 0\n  while (conversationMessages.length > 2 && totalBytes > ceiling) {\n    const removedBytes = convBytes.shift() ?? 0\n    conversationMessages.shift()\n    totalBytes -= removedBytes\n    dropped++\n  }\n\n  // Avoid stranding a tool_result whose corresponding tool_use was just\n  // dropped. Copilot/Vertex rejects with \"unexpected tool_use_id ... Each\n  // tool_result block must have a corresponding tool_use block in the\n  // previous message.\" Keep dropping from the front while the new head is\n  // either a `tool` role message OR a user/assistant message whose content\n  // begins with a tool_result/tool_use_id reference. Cheapest heuristic:\n  // drop while head.role === \"tool\".\n  let orphansDropped = 0\n  while (\n    conversationMessages.length > 2\n    && conversationMessages[0].role === \"tool\"\n  ) {\n    const removedBytes = convBytes.shift() ?? 0\n    conversationMessages.shift()\n    totalBytes -= removedBytes\n    orphansDropped++\n  }\n\n  if (dropped > 0 || orphansDropped > 0) {\n    consola.warn(\n      `Dropped ${dropped} oldest conversation messages + ${orphansDropped} orphaned tool results (~${totalBytes} bytes remaining, limit ${ceiling})`,\n    )\n  }\n\n  if (totalBytes > ceiling) {\n    consola.error(\n      `Payload still over ${ceiling}B after all reductions (${totalBytes}B). Forwarding anyway — Copilot will likely return 413 → 400 prompt-too-long for reactive compaction.`,\n    )\n  }\n\n  return {\n    ...payload,\n    messages: [...systemMessages, ...conversationMessages],\n  }\n}\n","import consola from \"consola\"\nimport { createHash } from \"node:crypto\"\n\nimport type {\n  ResponsesApiRequest,\n  ResponsesInputItem,\n} from \"~/routes/responses/types\"\n\nconst ENCRYPTED_OUTPUT_ERROR =\n  \"Encrypted function output content could not be decrypted or decoded.\"\nconst MAX_REJECTED_ENCRYPTED_OUTPUTS = 256\nconst REJECTED_ENCRYPTED_OUTPUT_TTL_MS = 30 * 60 * 1000\nconst STREAM_FAILURE_INSPECTION_TIMEOUT_MS = 100\nconst MAX_STREAM_FAILURE_INSPECTION_BYTES = 64 * 1024\nconst MAX_STREAM_FAILURE_INSPECTION_EVENTS = 8\nconst rejectedEncryptedOutputs = new Map<string, number>()\n\nexport function createEncryptedOutputScope(\n  url: string,\n  model: string,\n  accountIdentity: string,\n): string {\n  return fingerprintEncryptedOutput(`${url}\\0${model}\\0${accountIdentity}`)\n}\n\nexport function isEncryptedOutputError(\n  response: Response,\n  errorBody: string,\n): boolean {\n  return response.status === 400 && errorBody.includes(ENCRYPTED_OUTPUT_ERROR)\n}\n\nexport async function isImmediateEncryptedOutputStreamFailure(\n  response: Response,\n): Promise<boolean> {\n  if (!response.body) return false\n  if (!response.headers.get(\"content-type\")?.includes(\"text/event-stream\")) {\n    return false\n  }\n\n  const reader = response.clone().body?.getReader()\n  if (!reader) return false\n\n  try {\n    return await readImmediateEncryptedOutputStreamFailure(reader)\n  } catch (error) {\n    consola.debug(\"Failed to inspect Copilot Responses stream:\", error)\n  } finally {\n    void reader.cancel().catch(() => undefined)\n  }\n\n  return false\n}\n\nexport function stripEncryptedOutputParts(\n  payload: ResponsesApiRequest,\n  selected?: (fingerprint: string) => boolean,\n): {\n  count: number\n  fingerprints: Array<string>\n  payload: ResponsesApiRequest\n} {\n  if (typeof payload.input === \"string\") {\n    return { count: 0, fingerprints: [], payload }\n  }\n\n  let count = 0\n  const fingerprints: Array<string> = []\n  let input: Array<ResponsesInputItem> | undefined\n  for (const [index, item] of payload.input.entries()) {\n    if (!Array.isArray(item.content)) continue\n    const hasReadableText = item.content.some(\n      (part) =>\n        (part.type === \"input_text\" || part.type === \"output_text\")\n        && typeof part.text === \"string\",\n    )\n    if (!hasReadableText) continue\n\n    const content = item.content.filter((part) => {\n      if (\n        part.type !== \"encrypted_content\"\n        || typeof part.encrypted_content !== \"string\"\n      ) {\n        return true\n      }\n      const fingerprint = fingerprintEncryptedOutput(part.encrypted_content)\n      if (selected && !selected(fingerprint)) return true\n      fingerprints.push(fingerprint)\n      return false\n    })\n    if (content.length === item.content.length || content.length === 0) continue\n\n    count += item.content.length - content.length\n    input ??= [...payload.input]\n    input[index] = { ...item, content }\n  }\n\n  return {\n    count,\n    fingerprints,\n    payload: input ? { ...payload, input } : payload,\n  }\n}\n\nexport function isRejectedEncryptedOutput(\n  scope: string,\n  fingerprint: string,\n): boolean {\n  const key = rejectedEncryptedOutputKey(scope, fingerprint)\n  const expiresAt = rejectedEncryptedOutputs.get(key)\n  if (!expiresAt) return false\n  if (expiresAt > Date.now()) return true\n\n  rejectedEncryptedOutputs.delete(key)\n  return false\n}\n\nexport function rememberRejectedEncryptedOutputs(\n  scope: string,\n  fingerprints: Array<string>,\n): void {\n  if (fingerprints.length !== 1) return\n\n  const key = rejectedEncryptedOutputKey(scope, fingerprints[0])\n  rejectedEncryptedOutputs.delete(key)\n  rejectedEncryptedOutputs.set(\n    key,\n    Date.now() + REJECTED_ENCRYPTED_OUTPUT_TTL_MS,\n  )\n  while (rejectedEncryptedOutputs.size > MAX_REJECTED_ENCRYPTED_OUTPUTS) {\n    const oldest = rejectedEncryptedOutputs.keys().next().value\n    if (!oldest) break\n    rejectedEncryptedOutputs.delete(oldest)\n  }\n}\n\nasync function readImmediateEncryptedOutputStreamFailure(\n  reader: Pick<ReadableStreamDefaultReader<Uint8Array>, \"read\">,\n): Promise<boolean> {\n  const decoder = new TextDecoder()\n  const deadline = performance.now() + STREAM_FAILURE_INSPECTION_TIMEOUT_MS\n  let buffer = \"\"\n  let bytesRead = 0\n  let eventsRead = 0\n\n  while (true) {\n    const remainingMs = deadline - performance.now()\n    if (remainingMs <= 0) return false\n\n    const result = await readStreamChunkWithTimeout(reader, remainingMs)\n    if (!result) return false\n\n    const { done, value } = result\n    if (value) {\n      bytesRead += value.byteLength\n      if (bytesRead > MAX_STREAM_FAILURE_INSPECTION_BYTES) return false\n      buffer += decoder.decode(value, { stream: !done })\n    } else if (done) {\n      buffer += decoder.decode()\n    }\n\n    while (true) {\n      const next = takeNextSseBlock(buffer)\n      if (!next) break\n      buffer = next.remaining\n      const event = parseResponseEvent(next.block)\n      if (!event) continue\n\n      eventsRead++\n      if (isEncryptedOutputFailureEvent(event)) return true\n      if (!isProvisionalResponseEvent(event)) return false\n      if (eventsRead >= MAX_STREAM_FAILURE_INSPECTION_EVENTS) return false\n    }\n\n    if (done) {\n      const event = parseResponseEvent(buffer)\n      return event ? isEncryptedOutputFailureEvent(event) : false\n    }\n  }\n}\n\nasync function readStreamChunkWithTimeout(\n  reader: Pick<ReadableStreamDefaultReader<Uint8Array>, \"read\">,\n  timeoutMs: number,\n): Promise<{ done: boolean; value?: Uint8Array } | undefined> {\n  return await Promise.race([\n    reader.read(),\n    new Promise<undefined>((resolve) => {\n      setTimeout(resolve, timeoutMs)\n    }),\n  ])\n}\n\nfunction takeNextSseBlock(\n  buffer: string,\n): { block: string; remaining: string } | undefined {\n  const boundary = /\\r\\n\\r\\n|\\r\\r|\\n\\n/.exec(buffer)\n  if (boundary?.index === undefined) return undefined\n\n  return {\n    block: buffer.slice(0, boundary.index),\n    remaining: buffer.slice(boundary.index + boundary[0].length),\n  }\n}\n\ninterface ResponseStreamEvent {\n  type?: unknown\n  [key: string]: unknown\n}\n\nfunction parseResponseEvent(block: string): ResponseStreamEvent | undefined {\n  const data = block\n    .split(/\\r\\n|\\r|\\n/)\n    .filter((line) => line.startsWith(\"data:\"))\n    .map((line) => line.slice(5).trimStart())\n    .join(\"\\n\")\n  if (!data || data === \"[DONE]\") return undefined\n\n  try {\n    const event = JSON.parse(data) as unknown\n    return event && typeof event === \"object\" ?\n        (event as ResponseStreamEvent)\n      : undefined\n  } catch {\n    return undefined\n  }\n}\n\nfunction isEncryptedOutputFailureEvent(event: ResponseStreamEvent): boolean {\n  return (\n    event.type === \"response.failed\"\n    && JSON.stringify(event).includes(ENCRYPTED_OUTPUT_ERROR)\n  )\n}\n\nfunction isProvisionalResponseEvent(event: ResponseStreamEvent): boolean {\n  return (\n    event.type === \"response.created\" || event.type === \"response.in_progress\"\n  )\n}\n\nfunction fingerprintEncryptedOutput(value: string): string {\n  return createHash(\"sha256\").update(value).digest(\"base64url\")\n}\n\nfunction rejectedEncryptedOutputKey(\n  scope: string,\n  fingerprint: string,\n): string {\n  return `${scope}:${fingerprint}`\n}\n","import consola from \"consola\"\n\nimport type {\n  ResponsesApiRequest,\n  ResponsesContentPart,\n  ResponsesInputItem,\n} from \"~/routes/responses/types\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { copilotFetch } from \"~/lib/copilot-fetch\"\nimport { HTTPError } from \"~/lib/error\"\nimport {\n  getKnownModelPromptLimit,\n  getModelPromptLimit,\n} from \"~/lib/model-limits\"\nimport { state } from \"~/lib/state\"\nimport {\n  createEncryptedOutputScope,\n  isEncryptedOutputError,\n  isImmediateEncryptedOutputStreamFailure,\n  isRejectedEncryptedOutput,\n  rememberRejectedEncryptedOutputs,\n  stripEncryptedOutputParts,\n} from \"~/services/copilot/encrypted-output-recovery\"\n\nconst MAX_RESPONSES_PAYLOAD_BYTES = 5_000_000\nconst CHARS_PER_TOKEN_ESTIMATE = 3.5\nconst TOKEN_RESERVE = 8_000\nconst IMAGE_STRIPPED_PLACEHOLDER =\n  \"[image removed to stay under upstream payload limit]\"\nconst INVALID_OUTPUT_IMAGE_PLACEHOLDER =\n  \"[image output removed because its URL is not valid for Copilot Responses]\"\nconst INPUT_DROPPED_PLACEHOLDER =\n  \"[older response input omitted to stay under context limit]\"\nconst INPUT_TRUNCATED_PREFIX =\n  \"[older response input truncated to stay under context limit]\\n\\n\"\nconst PRESERVED_INPUT_STRING_KEYS = new Set([\n  \"call_id\",\n  \"id\",\n  \"model\",\n  \"name\",\n  \"previous_response_id\",\n  \"role\",\n  \"status\",\n  \"tool_call_id\",\n  \"type\",\n])\n\nexport async function createResponses(\n  payload: ResponsesApiRequest,\n): Promise<Response> {\n  if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n  const url = `${copilotBaseUrl(state)}/responses`\n  const encryptedOutputScope = createEncryptedOutputScope(\n    url,\n    payload.model,\n    state.githubToken ?? state.copilotToken,\n  )\n  const knownRejected = stripEncryptedOutputParts(\n    sanitizeResponsesPayload(payload),\n    (fingerprint) =>\n      isRejectedEncryptedOutput(encryptedOutputScope, fingerprint),\n  )\n  const upstreamPayload = fitResponsesPayload(\n    knownRejected.payload,\n    computeResponsesPayloadCeiling(payload.model),\n  )\n  const headers: Record<string, string> = {\n    ...copilotHeaders(state, responsesPayloadHasImages(upstreamPayload)),\n    accept: upstreamPayload.stream ? \"text/event-stream\" : \"application/json\",\n    \"X-Initiator\": \"agent\",\n  }\n  const bodyLength = JSON.stringify(upstreamPayload).length\n\n  consola.info(\n    `Sending responses payload: ${bodyLength} bytes, model: ${payload.model}`,\n  )\n\n  const result = await fetchResponsesWithEncryptedOutputFallback(\n    { url, headers, encryptedOutputScope },\n    upstreamPayload,\n  )\n  const { response } = result\n\n  if (!response.ok) {\n    const errorBody = result.errorBody ?? (await response.text())\n    consola.error(\n      `Failed to create responses - Status: ${response.status} ${response.statusText}`,\n    )\n    consola.error(`Response body: ${errorBody}`)\n    consola.error(`Request payload size: ${result.body.length} bytes`)\n\n    if (isContextOverflow(response, errorBody, result.body.length)) {\n      const estimatedTokens = Math.ceil(result.body.length / 4)\n      const modelCaps = state.models?.data.find((m) => m.id === payload.model)\n        ?.capabilities.limits\n      const modelLimit = getModelPromptLimit(payload.model, modelCaps)\n      const maxOutputTokens = payload.max_output_tokens ?? 0\n\n      consola.warn(\n        `Responses context overflow -> returning 400 prompt-too-long (~${estimatedTokens} + ${maxOutputTokens} > ${modelLimit})`,\n      )\n\n      throw new HTTPError(\n        \"Prompt too long\",\n        new Response(\n          JSON.stringify({\n            type: \"error\",\n            error: {\n              type: \"invalid_request_error\",\n              message: `prompt is too long: input length and \\`max_tokens\\` exceed context limit: ${estimatedTokens} + ${maxOutputTokens} > ${modelLimit} tokens`,\n            },\n          }),\n          {\n            status: 400,\n            statusText: \"Bad Request\",\n            headers: { \"content-type\": \"application/json\" },\n          },\n        ),\n      )\n    }\n\n    throw new HTTPError(\n      \"Failed to create responses\",\n      new Response(errorBody, {\n        status: response.status,\n        statusText: response.statusText,\n        headers: response.headers,\n      }),\n    )\n  }\n\n  return response\n}\n\ninterface ResponsesFetchResult {\n  body: string\n  errorBody?: string\n  response: Response\n}\n\ninterface ResponsesFetchContext {\n  encryptedOutputScope: string\n  headers: Record<string, string>\n  url: string\n}\n\nasync function fetchResponsesWithEncryptedOutputFallback(\n  context: ResponsesFetchContext,\n  payload: ResponsesApiRequest,\n): Promise<ResponsesFetchResult> {\n  const { encryptedOutputScope, headers, url } = context\n  const fallback = stripEncryptedOutputParts(payload)\n  const initial = await sendResponsesRequest(url, headers, payload)\n  if (fallback.count === 0) return initial\n\n  if (\n    !initial.response.ok\n    && initial.errorBody\n    && isEncryptedOutputError(initial.response, initial.errorBody)\n  ) {\n    consola.warn(\n      `Copilot could not decrypt ${fallback.count} encrypted output part(s); retrying without them`,\n    )\n    rememberRejectedEncryptedOutputs(\n      encryptedOutputScope,\n      fallback.fingerprints,\n    )\n    return sendResponsesRequest(url, headers, fallback.payload)\n  }\n\n  if (\n    initial.response.ok\n    && payload.stream\n    && (await isImmediateEncryptedOutputStreamFailure(initial.response))\n  ) {\n    void initial.response.body?.cancel().catch(() => undefined)\n    consola.warn(\n      `Copilot stream failed before output; retrying without ${fallback.count} encrypted output part(s)`,\n    )\n    rememberRejectedEncryptedOutputs(\n      encryptedOutputScope,\n      fallback.fingerprints,\n    )\n    return sendResponsesRequest(url, headers, fallback.payload)\n  }\n\n  return initial\n}\n\nasync function sendResponsesRequest(\n  url: string,\n  headers: Record<string, string>,\n  payload: ResponsesApiRequest,\n): Promise<ResponsesFetchResult> {\n  const body = JSON.stringify(payload)\n  const response = await copilotFetch(url, { method: \"POST\", headers, body })\n  const errorBody = response.ok ? undefined : await response.text()\n  return { body, errorBody, response }\n}\n\nfunction fitResponsesPayload(\n  payload: ResponsesApiRequest,\n  ceiling: number,\n): ResponsesApiRequest {\n  const initialBody = JSON.stringify(payload)\n  if (initialBody.length <= ceiling) return payload\n\n  consola.info(\n    `Responses context fit: payload ${initialBody.length} bytes exceeds ${ceiling} byte ceiling - reducing`,\n  )\n\n  if (typeof payload.input === \"string\") {\n    const current = truncateStringInput(payload, ceiling)\n    const currentBodyLength = JSON.stringify(current).length\n    consola.warn(\n      `Responses context fit: truncated string input (${initialBody.length} -> ${currentBodyLength} bytes)`,\n    )\n    return current\n  }\n\n  let current = payload\n  let currentBodyLength = initialBody.length\n\n  const imageLocations = collectImageLocations(payload)\n  let strippedCount = 0\n\n  for (const location of imageLocations) {\n    current = replaceImageWithPlaceholder(current, location)\n    strippedCount++\n    currentBodyLength = JSON.stringify(current).length\n    if (currentBodyLength <= ceiling) break\n  }\n\n  if (strippedCount > 0) {\n    consola.warn(\n      `Responses context fit: stripped ${strippedCount} images (${initialBody.length} -> ${currentBodyLength} bytes)`,\n    )\n  }\n\n  if (currentBodyLength <= ceiling) return current\n\n  const dropped = dropOldInputItems(current, ceiling)\n  current = dropOrphanedToolCallOutputs(dropped.payload)\n  currentBodyLength = JSON.stringify(current).length\n  if (dropped.count > 0) {\n    consola.warn(\n      `Responses context fit: dropped ${dropped.count} old input items (${initialBody.length} -> ${currentBodyLength} bytes)`,\n    )\n  }\n\n  if (currentBodyLength <= ceiling) return current\n\n  current = truncateLargestInputContent(current, ceiling)\n  currentBodyLength = JSON.stringify(current).length\n  consola.warn(\n    `Responses context fit: truncated input content (${initialBody.length} -> ${currentBodyLength} bytes)`,\n  )\n\n  if (currentBodyLength <= ceiling) return current\n\n  current = minimizeResponsesInput(current, ceiling)\n  currentBodyLength = JSON.stringify(current).length\n  consola.warn(\n    `Responses context fit: minimized input history (${initialBody.length} -> ${currentBodyLength} bytes)`,\n  )\n\n  if (currentBodyLength <= ceiling) return current\n\n  current = truncateLargestPayloadStrings(current, ceiling)\n  currentBodyLength = JSON.stringify(current).length\n  consola.warn(\n    `Responses context fit: truncated payload strings (${initialBody.length} -> ${currentBodyLength} bytes)`,\n  )\n\n  return current\n}\n\nfunction computeResponsesPayloadCeiling(modelId: string): number {\n  const limits = state.models?.data.find((m) => m.id === modelId)?.capabilities\n    .limits\n  const maxPromptTokens = getKnownModelPromptLimit(modelId, limits)\n  if (!maxPromptTokens) return MAX_RESPONSES_PAYLOAD_BYTES\n\n  const tokenDerivedBytes = Math.floor(\n    (maxPromptTokens - TOKEN_RESERVE) * CHARS_PER_TOKEN_ESTIMATE,\n  )\n  return Math.min(MAX_RESPONSES_PAYLOAD_BYTES, tokenDerivedBytes)\n}\n\nfunction truncateStringInput(\n  payload: ResponsesApiRequest,\n  ceiling: number,\n): ResponsesApiRequest {\n  if (typeof payload.input !== \"string\") return payload\n\n  const overhead = JSON.stringify({ ...payload, input: \"\" }).length\n  const maxInputLength = Math.max(\n    INPUT_TRUNCATED_PREFIX.length,\n    ceiling - overhead,\n  )\n  const tailLength = Math.max(0, maxInputLength - INPUT_TRUNCATED_PREFIX.length)\n  return {\n    ...payload,\n    input: INPUT_TRUNCATED_PREFIX + payload.input.slice(-tailLength),\n  }\n}\n\ninterface ImageLocation {\n  contentIndex: number\n  inputIndex: number\n}\n\nfunction collectImageLocations(\n  payload: ResponsesApiRequest,\n): Array<ImageLocation> {\n  if (typeof payload.input === \"string\") return []\n\n  const locations: Array<ImageLocation> = []\n  for (const [inputIndex, item] of payload.input.entries()) {\n    if (!Array.isArray(item.content)) continue\n\n    for (const [contentIndex, part] of item.content.entries()) {\n      if (part.type === \"input_image\") {\n        locations.push({ contentIndex, inputIndex })\n      }\n    }\n  }\n  return locations\n}\n\nfunction replaceImageWithPlaceholder(\n  payload: ResponsesApiRequest,\n  location: ImageLocation,\n): ResponsesApiRequest {\n  if (typeof payload.input === \"string\") return payload\n\n  const input = [...payload.input]\n  const item = input[location.inputIndex]\n  if (!Array.isArray(item.content)) return payload\n\n  const content = [...item.content]\n  content[location.contentIndex] = {\n    type: \"input_text\",\n    text: IMAGE_STRIPPED_PLACEHOLDER,\n  }\n\n  input[location.inputIndex] = { ...item, content }\n  return { ...payload, input }\n}\n\nfunction dropOldInputItems(\n  payload: ResponsesApiRequest,\n  ceiling: number,\n): { bodyLength: number; count: number; payload: ResponsesApiRequest } {\n  if (typeof payload.input === \"string\") {\n    return { bodyLength: JSON.stringify(payload).length, count: 0, payload }\n  }\n\n  const input = [...payload.input]\n  let bodyLength = JSON.stringify({ ...payload, input }).length\n  let count = 0\n\n  for (let index = 0; index < input.length && bodyLength > ceiling; index++) {\n    const item = input[index]\n    if (item.role === \"system\" || item.role === \"developer\") continue\n    if (countRecentDroppableItems(input, index) <= 2) continue\n\n    input[index] = createDroppedInputItem(item)\n    count++\n    bodyLength = JSON.stringify({ ...payload, input }).length\n  }\n\n  return { bodyLength, count, payload: { ...payload, input } }\n}\n\nfunction createDroppedInputItem(item: ResponsesInputItem): ResponsesInputItem {\n  return {\n    role: item.role === \"assistant\" ? \"assistant\" : \"user\",\n    content: INPUT_DROPPED_PLACEHOLDER,\n  }\n}\n\nfunction dropOrphanedToolCallOutputs(\n  payload: ResponsesApiRequest,\n): ResponsesApiRequest {\n  if (typeof payload.input === \"string\") return payload\n\n  const callIds = new Set(\n    payload.input\n      .filter((item) => isToolCallItem(item) && item.call_id)\n      .map((item) => item.call_id),\n  )\n  let droppedCount = 0\n  const input = payload.input.map((item) => {\n    if (\n      !isToolCallOutputItem(item)\n      || !item.call_id\n      || callIds.has(item.call_id)\n    ) {\n      return item\n    }\n\n    droppedCount++\n    return createDroppedInputItem(item)\n  })\n\n  if (droppedCount === 0) return payload\n  consola.warn(\n    `Responses context fit: dropped ${droppedCount} orphaned tool call outputs`,\n  )\n  return { ...payload, input }\n}\n\nfunction isToolCallItem(item: ResponsesInputItem): boolean {\n  return typeof item.type === \"string\" && item.type.endsWith(\"_call\")\n}\n\nfunction isToolCallOutputItem(item: ResponsesInputItem): boolean {\n  return typeof item.type === \"string\" && item.type.endsWith(\"_call_output\")\n}\n\nfunction countRecentDroppableItems(\n  input: Array<ResponsesInputItem>,\n  index: number,\n): number {\n  let count = 0\n  for (let i = index; i < input.length; i++) {\n    if (input[i].role !== \"system\" && input[i].role !== \"developer\") count++\n  }\n  return count\n}\n\nfunction truncateLargestInputContent(\n  payload: ResponsesApiRequest,\n  ceiling: number,\n): ResponsesApiRequest {\n  if (typeof payload.input === \"string\") {\n    return truncateStringInput(payload, ceiling)\n  }\n\n  let current = payload\n  let bodyLength = JSON.stringify(current).length\n\n  while (bodyLength > ceiling) {\n    const target = findLargestInputString(current)\n    if (!target) return current\n\n    current = truncateStringAtLocation(current, target, bodyLength - ceiling)\n    const nextBodyLength = JSON.stringify(current).length\n    if (nextBodyLength >= bodyLength) return current\n    bodyLength = nextBodyLength\n  }\n\n  return current\n}\n\ninterface StringLocation {\n  inputIndex: number\n  length: number\n  path: Array<number | string>\n}\n\nfunction findLargestInputString(\n  payload: ResponsesApiRequest,\n): StringLocation | null {\n  if (typeof payload.input === \"string\") return null\n\n  let largest: StringLocation | null = null\n  for (const [inputIndex, item] of payload.input.entries()) {\n    if (item.role === \"system\" || item.role === \"developer\") continue\n\n    const candidate = findLargestStringInValue(item, [])\n    if (candidate && (!largest || candidate.length > largest.length)) {\n      largest = { inputIndex, ...candidate }\n    }\n  }\n\n  return largest\n}\n\nfunction truncateStringAtLocation(\n  payload: ResponsesApiRequest,\n  location: StringLocation,\n  excessBytes: number,\n): ResponsesApiRequest {\n  if (typeof payload.input === \"string\") return payload\n\n  const input = [...payload.input]\n  const item = input[location.inputIndex]\n  const keepLength = Math.max(\n    0,\n    location.length - excessBytes - INPUT_TRUNCATED_PREFIX.length - 10_000,\n  )\n\n  input[location.inputIndex] = truncateStringAtPath(\n    item,\n    location.path,\n    keepLength,\n  ) as ResponsesInputItem\n  return { ...payload, input }\n}\n\ninterface StringCandidate {\n  length: number\n  path: Array<number | string>\n}\n\nfunction findLargestStringInValue(\n  value: unknown,\n  path: Array<number | string>,\n): StringCandidate | null {\n  if (typeof value === \"string\") {\n    const key = path.at(-1)\n    if (typeof key === \"string\" && PRESERVED_INPUT_STRING_KEYS.has(key)) {\n      return null\n    }\n    return { length: value.length, path }\n  }\n\n  if (Array.isArray(value)) {\n    return value.reduce<StringCandidate | null>((largest, item, index) => {\n      const candidate = findLargestStringInValue(item, [...path, index])\n      if (!candidate) return largest\n      return !largest || candidate.length > largest.length ? candidate : largest\n    }, null)\n  }\n\n  if (!isRecord(value)) return null\n\n  let largest: StringCandidate | null = null\n  for (const [key, nested] of Object.entries(value)) {\n    const candidate = findLargestStringInValue(nested, [...path, key])\n    if (candidate && (!largest || candidate.length > largest.length)) {\n      largest = candidate\n    }\n  }\n  return largest\n}\n\nfunction truncateStringAtPath(\n  value: unknown,\n  path: Array<number | string>,\n  keepLength: number,\n): unknown {\n  if (path.length === 0) {\n    if (typeof value !== \"string\") return value\n    return INPUT_TRUNCATED_PREFIX + value.slice(-keepLength)\n  }\n\n  const [head, ...tail] = path\n  if (Array.isArray(value) && typeof head === \"number\") {\n    const arrayValue = value as Array<unknown>\n    const next = [...arrayValue]\n    next[head] = truncateStringAtPath(next[head], tail, keepLength)\n    return next\n  }\n\n  if (isRecord(value) && typeof head === \"string\") {\n    return {\n      ...value,\n      [head]: truncateStringAtPath(value[head], tail, keepLength),\n    }\n  }\n\n  return value\n}\n\nfunction minimizeResponsesInput(\n  payload: ResponsesApiRequest,\n  ceiling: number,\n): ResponsesApiRequest {\n  if (typeof payload.input === \"string\") {\n    return truncateStringInput(payload, ceiling)\n  }\n\n  const protectedItems = payload.input.filter(\n    (item) => item.role === \"system\" || item.role === \"developer\",\n  )\n  const latest = [...payload.input]\n    .reverse()\n    .find((item) => item.role !== \"system\" && item.role !== \"developer\")\n\n  return {\n    ...payload,\n    input: [\n      ...protectedItems,\n      {\n        role: latest?.role === \"assistant\" ? \"assistant\" : \"user\",\n        content: INPUT_DROPPED_PLACEHOLDER,\n      },\n    ],\n  }\n}\n\nfunction truncateLargestPayloadStrings(\n  payload: ResponsesApiRequest,\n  ceiling: number,\n): ResponsesApiRequest {\n  let current = payload\n  let bodyLength = JSON.stringify(current).length\n\n  while (bodyLength > ceiling) {\n    const target = findLargestStringInValue(current, [])\n    if (!target) return current\n\n    current = truncateStringAtPath(\n      current,\n      target.path,\n      bodyLength - ceiling,\n    ) as ResponsesApiRequest\n    const nextBodyLength = JSON.stringify(current).length\n    if (nextBodyLength >= bodyLength) return current\n    bodyLength = nextBodyLength\n  }\n\n  return current\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === \"object\" && value !== null\n}\n\nfunction isContextOverflow(\n  response: Response,\n  errorBody: string,\n  bodyLength: number,\n): boolean {\n  return (\n    response.status === 413\n    || /request entity too large/i.test(errorBody)\n    || /exceeds the limit of \\d+/i.test(errorBody)\n    || /context_length_exceeded/i.test(errorBody)\n    || /operation timed out/i.test(errorBody)\n    || /payload too large/i.test(errorBody)\n    || /maximum context length/i.test(errorBody)\n    || (response.status >= 500\n      && response.status < 600\n      && bodyLength > 2_000_000)\n  )\n}\n\nfunction sanitizeResponsesPayload(\n  payload: ResponsesApiRequest,\n): ResponsesApiRequest {\n  const sanitized = normalizeToolDescriptions(\n    sanitizeInvalidOutputImages(payload),\n  )\n\n  // Codex sends ChatGPT-only fast mode metadata; Copilot Responses rejects it.\n  delete (sanitized as ResponsesApiRequest & { service_tier?: unknown })\n    .service_tier\n\n  if (!sanitized.tools?.some((tool) => tool.type === \"image_generation\")) {\n    return sanitized\n  }\n\n  return {\n    ...sanitized,\n    tools: sanitized.tools.filter((tool) => tool.type !== \"image_generation\"),\n  }\n}\n\nfunction normalizeToolDescriptions(\n  payload: ResponsesApiRequest,\n): ResponsesApiRequest {\n  const tools = normalizeToolList(payload.tools)\n  let sanitized = tools === payload.tools ? payload : { ...payload, tools }\n\n  if (typeof payload.input === \"string\") return sanitized\n\n  let input: Array<ResponsesInputItem> | undefined\n  for (const [index, item] of payload.input.entries()) {\n    const itemTools = normalizeToolList(item.tools, true)\n    if (itemTools === item.tools) continue\n\n    input ??= [...payload.input]\n    input[index] = { ...item, tools: itemTools }\n  }\n\n  if (input) sanitized = { ...sanitized, input }\n  return sanitized\n}\n\nfunction normalizeToolList(\n  tools: ResponsesApiRequest[\"tools\"],\n  descriptionRequired = false,\n): ResponsesApiRequest[\"tools\"] {\n  if (\n    !Array.isArray(tools)\n    || !tools.some(\n      (tool) =>\n        (descriptionRequired && !isNonBlankString(tool.description))\n        || (tool.description !== undefined\n          && !isNonBlankString(tool.description))\n        || (tool.function?.description !== undefined\n          && !isNonBlankString(tool.function.description)),\n    )\n  ) {\n    return tools\n  }\n\n  return tools.map((tool) => {\n    const sanitizedTool = { ...tool }\n    if (descriptionRequired && !isNonBlankString(sanitizedTool.description)) {\n      const nestedDescription = sanitizedTool.function?.description\n      let name: string | undefined\n      if (isNonBlankString(sanitizedTool.name)) {\n        name = sanitizedTool.name\n      } else if (isNonBlankString(sanitizedTool.function?.name)) {\n        name = sanitizedTool.function.name\n      }\n      sanitizedTool.description = name ? `Tool ${name}` : \"Tool\"\n      if (isNonBlankString(nestedDescription)) {\n        sanitizedTool.description = nestedDescription\n      }\n    } else if (\n      sanitizedTool.description !== undefined\n      && !isNonBlankString(sanitizedTool.description)\n    ) {\n      delete sanitizedTool.description\n    }\n    if (\n      sanitizedTool.function?.description !== undefined\n      && !isNonBlankString(sanitizedTool.function.description)\n    ) {\n      sanitizedTool.function = { ...sanitizedTool.function }\n      delete sanitizedTool.function.description\n    }\n    return sanitizedTool\n  })\n}\n\nfunction isNonBlankString(value: unknown): value is string {\n  return typeof value === \"string\" && value.trim().length > 0\n}\n\nfunction sanitizeInvalidOutputImages(\n  payload: ResponsesApiRequest,\n): ResponsesApiRequest {\n  if (typeof payload.input === \"string\") return payload\n\n  let input: Array<ResponsesInputItem> | undefined\n  for (const [index, item] of payload.input.entries()) {\n    if (!Array.isArray(item.output)) continue\n\n    const sanitizedOutput = sanitizeOutputParts(item.output)\n    if (sanitizedOutput === item.output) continue\n\n    input ??= [...payload.input]\n    input[index] = { ...item, output: sanitizedOutput }\n  }\n\n  return input ? { ...payload, input } : payload\n}\n\nfunction sanitizeOutputParts(\n  output: NonNullable<ResponsesInputItem[\"output\"]>,\n): ResponsesInputItem[\"output\"] {\n  if (typeof output === \"string\") return output\n\n  const sanitizedOutput = output.map((part) => sanitizeOutputPart(part))\n  const changed = sanitizedOutput.some((part, index) => part !== output[index])\n\n  return changed ? sanitizedOutput : output\n}\n\nfunction sanitizeOutputPart(part: ResponsesContentPart): ResponsesContentPart {\n  if (hasInvalidImageUrl(part)) {\n    return {\n      type: \"input_text\",\n      text: INVALID_OUTPUT_IMAGE_PLACEHOLDER,\n    }\n  }\n\n  if (typeof part.image_url === \"string\" && part.type !== \"input_image\") {\n    return {\n      type: \"input_image\",\n      image_url: part.image_url,\n      detail: part.detail,\n    }\n  }\n\n  if (part.type === \"output_text\") {\n    return {\n      type: \"input_text\",\n      text: part.text ?? \"\",\n    }\n  }\n\n  return part\n}\n\nfunction hasInvalidImageUrl(part: { image_url?: unknown }): boolean {\n  if (\n    !(\"image_url\" in part)\n    || part.image_url === null\n    || part.image_url === undefined\n  ) {\n    return false\n  }\n  return typeof part.image_url !== \"string\" || !isValidHttpUrl(part.image_url)\n}\n\nfunction isValidHttpUrl(value: string): boolean {\n  try {\n    const url = new URL(value)\n    return url.protocol === \"http:\" || url.protocol === \"https:\"\n  } catch {\n    return false\n  }\n}\n\nfunction responsesPayloadHasImages(payload: ResponsesApiRequest): boolean {\n  if (typeof payload.input === \"string\") return false\n\n  return payload.input.some(\n    (item) =>\n      Array.isArray(item.content)\n      && item.content.some((part) => part.type === \"input_image\"),\n  )\n}\n","import type {\n  ResponsesApiRequest,\n  ResponsesApiResponse,\n  ResponsesContentPart,\n  ResponsesInputItem,\n  ResponsesOutputItem,\n} from \"~/routes/responses/types\"\n\nimport type {\n  AnthropicAssistantContentBlock,\n  AnthropicImageBlock,\n  AnthropicMessagesPayload,\n  AnthropicResponse,\n  AnthropicTextBlock,\n  AnthropicToolResultBlock,\n  AnthropicToolUseBlock,\n  AnthropicUserContentBlock,\n} from \"./anthropic-types\"\n\ninterface SSEStream {\n  writeSSE(event: { data: string; event: string }): Promise<void>\n}\n\nexport function translateAnthropicMessagesToResponses(\n  payload: AnthropicMessagesPayload,\n  model: string,\n): ResponsesApiRequest {\n  return {\n    model,\n    input: payload.messages.flatMap((message) => translateMessage(message)),\n    instructions: translateSystem(payload.system),\n    max_output_tokens: payload.max_tokens,\n    temperature: payload.temperature,\n    top_p: payload.top_p,\n    stream: false,\n    tools: payload.tools?.map((tool) => ({\n      type: \"function\",\n      name: tool.name,\n      description: tool.description,\n      parameters: tool.input_schema,\n    })),\n    tool_choice: translateToolChoice(payload.tool_choice),\n  }\n}\n\nexport function translateResponsesToAnthropicMessage(\n  response: ResponsesApiResponse,\n  clientModel: string,\n): AnthropicResponse {\n  const content = response.output.flatMap((item) => translateOutputItem(item))\n  const hasToolUse = content.some((block) => block.type === \"tool_use\")\n\n  return {\n    id: response.id,\n    type: \"message\",\n    role: \"assistant\",\n    content,\n    model: clientModel,\n    stop_reason: hasToolUse ? \"tool_use\" : \"end_turn\",\n    stop_sequence: null,\n    usage: {\n      input_tokens: response.usage?.input_tokens ?? 0,\n      output_tokens: response.usage?.output_tokens ?? 0,\n    },\n  }\n}\n\nexport async function writeResponsesAsAnthropicStream(\n  stream: SSEStream,\n  response: ResponsesApiResponse,\n  clientModel: string,\n) {\n  const message = translateResponsesToAnthropicMessage(response, clientModel)\n\n  await stream.writeSSE({\n    event: \"message_start\",\n    data: JSON.stringify({\n      type: \"message_start\",\n      message: {\n        ...message,\n        content: [],\n        stop_reason: null,\n        stop_sequence: null,\n        usage: { ...message.usage, output_tokens: 0 },\n      },\n    }),\n  })\n\n  for (const [index, block] of message.content.entries()) {\n    if (block.type === \"text\") {\n      await writeTextBlock(stream, index, block.text)\n    } else if (block.type === \"tool_use\") {\n      await writeToolUseBlock(stream, index, block)\n    }\n  }\n\n  await stream.writeSSE({\n    event: \"message_delta\",\n    data: JSON.stringify({\n      type: \"message_delta\",\n      delta: {\n        stop_reason: message.stop_reason,\n        stop_sequence: null,\n      },\n      usage: { output_tokens: message.usage.output_tokens },\n    }),\n  })\n  await stream.writeSSE({\n    event: \"message_stop\",\n    data: JSON.stringify({ type: \"message_stop\" }),\n  })\n}\n\nfunction translateSystem(\n  system: AnthropicMessagesPayload[\"system\"],\n): string | undefined {\n  if (!system) return undefined\n  if (typeof system === \"string\") return system\n  return system.map((block) => block.text).join(\"\\n\\n\")\n}\n\nfunction translateMessage(\n  message: AnthropicMessagesPayload[\"messages\"][number],\n): Array<ResponsesInputItem> {\n  if (message.role === \"user\") return translateUserMessage(message.content)\n  return translateAssistantMessage(message.content)\n}\n\nfunction translateUserMessage(\n  content: string | Array<AnthropicUserContentBlock>,\n): Array<ResponsesInputItem> {\n  if (typeof content === \"string\") return [{ role: \"user\", content }]\n\n  const items: Array<ResponsesInputItem> = []\n  const messageParts: Array<\n    Exclude<AnthropicUserContentBlock, AnthropicToolResultBlock>\n  > = []\n\n  for (const block of content) {\n    if (block.type === \"tool_result\") {\n      items.push({\n        type: \"function_call_output\",\n        call_id: block.tool_use_id,\n        output: stringifyToolResult(block.content),\n      })\n    } else {\n      messageParts.push(block)\n    }\n  }\n\n  const messageContent = translateInputContent(messageParts)\n  if (messageContent) items.push({ role: \"user\", content: messageContent })\n  return items\n}\n\nfunction translateAssistantMessage(\n  content: string | Array<AnthropicAssistantContentBlock>,\n): Array<ResponsesInputItem> {\n  if (typeof content === \"string\") return [{ role: \"assistant\", content }]\n\n  const items: Array<ResponsesInputItem> = []\n  const text = content\n    .filter((block): block is AnthropicTextBlock => block.type === \"text\")\n    .map((block) => block.text)\n    .join(\"\\n\\n\")\n  if (text) items.push({ role: \"assistant\", content: text })\n\n  for (const block of content) {\n    if (block.type !== \"tool_use\") continue\n    items.push({\n      type: \"function_call\",\n      call_id: block.id,\n      name: block.name,\n      arguments: JSON.stringify(block.input),\n    })\n  }\n\n  return items\n}\n\nfunction translateInputContent(\n  content: Array<Exclude<AnthropicUserContentBlock, AnthropicToolResultBlock>>,\n): string | Array<ResponsesContentPart> | null {\n  const hasImage = content.some((block) => block.type === \"image\")\n  if (!hasImage) {\n    const text = content\n      .filter((block): block is AnthropicTextBlock => block.type === \"text\")\n      .map((block) => block.text)\n      .join(\"\\n\\n\")\n    return text || null\n  }\n\n  const parts: Array<ResponsesContentPart> = []\n  for (const block of content) {\n    if (block.type === \"text\") {\n      parts.push({ type: \"input_text\", text: block.text })\n    } else if (block.type === \"image\") {\n      parts.push(translateImageBlock(block))\n    }\n  }\n  return parts.length > 0 ? parts : null\n}\n\nfunction translateImageBlock(block: AnthropicImageBlock): ResponsesContentPart {\n  return {\n    type: \"input_image\",\n    image_url: `data:${block.source.media_type};base64,${block.source.data}`,\n  }\n}\n\nfunction translateToolChoice(\n  toolChoice: AnthropicMessagesPayload[\"tool_choice\"],\n): ResponsesApiRequest[\"tool_choice\"] {\n  if (!toolChoice) return undefined\n  if (toolChoice.type === \"auto\" || toolChoice.type === \"none\") {\n    return toolChoice.type\n  }\n  if (toolChoice.type === \"any\") return \"required\"\n  if (toolChoice.name) {\n    return { type: \"function\", name: toolChoice.name }\n  }\n  return undefined\n}\n\nfunction stringifyToolResult(\n  content: AnthropicToolResultBlock[\"content\"],\n): string {\n  return typeof content === \"string\" ? content : JSON.stringify(content)\n}\n\nfunction translateOutputItem(\n  item: ResponsesOutputItem,\n): Array<AnthropicAssistantContentBlock> {\n  if (item.type === \"function_call\" && item.name && item.call_id) {\n    return [\n      {\n        type: \"tool_use\",\n        id: item.call_id,\n        name: item.name,\n        input: parseToolInput(item.arguments),\n      },\n    ]\n  }\n\n  if (item.type !== \"message\" || !item.content) return []\n  return item.content.flatMap((part) => {\n    if (part.type !== \"output_text\" || !part.text) return []\n    return [{ type: \"text\", text: part.text }]\n  })\n}\n\nfunction parseToolInput(\n  argumentsText: string | undefined,\n): Record<string, unknown> {\n  if (!argumentsText) return {}\n  try {\n    const parsed = JSON.parse(argumentsText) as unknown\n    if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n      return parsed as Record<string, unknown>\n    }\n  } catch {\n    return {}\n  }\n  return {}\n}\n\nasync function writeTextBlock(stream: SSEStream, index: number, text: string) {\n  await stream.writeSSE({\n    event: \"content_block_start\",\n    data: JSON.stringify({\n      type: \"content_block_start\",\n      index,\n      content_block: { type: \"text\", text: \"\" },\n    }),\n  })\n  await stream.writeSSE({\n    event: \"content_block_delta\",\n    data: JSON.stringify({\n      type: \"content_block_delta\",\n      index,\n      delta: { type: \"text_delta\", text },\n    }),\n  })\n  await stream.writeSSE({\n    event: \"content_block_stop\",\n    data: JSON.stringify({ type: \"content_block_stop\", index }),\n  })\n}\n\nasync function writeToolUseBlock(\n  stream: SSEStream,\n  index: number,\n  block: AnthropicToolUseBlock,\n) {\n  await stream.writeSSE({\n    event: \"content_block_start\",\n    data: JSON.stringify({\n      type: \"content_block_start\",\n      index,\n      content_block: {\n        type: \"tool_use\",\n        id: block.id,\n        name: block.name,\n        input: {},\n      },\n    }),\n  })\n  await stream.writeSSE({\n    event: \"content_block_delta\",\n    data: JSON.stringify({\n      type: \"content_block_delta\",\n      index,\n      delta: {\n        type: \"input_json_delta\",\n        partial_json: JSON.stringify(block.input),\n      },\n    }),\n  })\n  await stream.writeSSE({\n    event: \"content_block_stop\",\n    data: JSON.stringify({ type: \"content_block_stop\", index }),\n  })\n}\n","import { type ChatCompletionChunk } from \"~/services/copilot/create-chat-completions\"\n\nimport {\n  type AnthropicStreamEventData,\n  type AnthropicStreamState,\n} from \"./anthropic-types\"\nimport { mapOpenAIStopReasonToAnthropic } from \"./utils\"\n\nfunction isToolBlockOpen(state: AnthropicStreamState): boolean {\n  if (!state.contentBlockOpen) {\n    return false\n  }\n  // Check if the current block index corresponds to any known tool call\n  return Object.values(state.toolCalls).some(\n    (tc) => tc.anthropicBlockIndex === state.contentBlockIndex,\n  )\n}\n\n// eslint-disable-next-line max-lines-per-function, complexity\nexport function translateChunkToAnthropicEvents(\n  chunk: ChatCompletionChunk,\n  state: AnthropicStreamState,\n): Array<AnthropicStreamEventData> {\n  const events: Array<AnthropicStreamEventData> = []\n\n  if (chunk.choices.length === 0) {\n    return events\n  }\n\n  const choice = chunk.choices[0]\n  const { delta } = choice\n\n  if (!state.messageStartSent) {\n    events.push({\n      type: \"message_start\",\n      message: {\n        id: chunk.id,\n        type: \"message\",\n        role: \"assistant\",\n        content: [],\n        model: chunk.model,\n        stop_reason: null,\n        stop_sequence: null,\n        usage: {\n          input_tokens:\n            (chunk.usage?.prompt_tokens ?? 0)\n            - (chunk.usage?.prompt_tokens_details?.cached_tokens ?? 0),\n          output_tokens: 0, // Will be updated in message_delta when finished\n          ...(chunk.usage?.prompt_tokens_details?.cached_tokens\n            !== undefined && {\n            cache_read_input_tokens:\n              chunk.usage.prompt_tokens_details.cached_tokens,\n          }),\n        },\n      },\n    })\n    state.messageStartSent = true\n  }\n\n  if (delta.content) {\n    if (isToolBlockOpen(state)) {\n      // A tool block was open, so close it before starting a text block.\n      events.push({\n        type: \"content_block_stop\",\n        index: state.contentBlockIndex,\n      })\n      state.contentBlockIndex++\n      state.contentBlockOpen = false\n    }\n\n    if (!state.contentBlockOpen) {\n      events.push({\n        type: \"content_block_start\",\n        index: state.contentBlockIndex,\n        content_block: {\n          type: \"text\",\n          text: \"\",\n        },\n      })\n      state.contentBlockOpen = true\n    }\n\n    events.push({\n      type: \"content_block_delta\",\n      index: state.contentBlockIndex,\n      delta: {\n        type: \"text_delta\",\n        text: delta.content,\n      },\n    })\n  }\n\n  if (delta.tool_calls) {\n    for (const toolCall of delta.tool_calls) {\n      if (toolCall.id && toolCall.function?.name) {\n        // New tool call starting.\n        if (state.contentBlockOpen) {\n          // Close any previously open block.\n          events.push({\n            type: \"content_block_stop\",\n            index: state.contentBlockIndex,\n          })\n          state.contentBlockIndex++\n          state.contentBlockOpen = false\n        }\n\n        const anthropicBlockIndex = state.contentBlockIndex\n        state.toolCalls[toolCall.index] = {\n          id: toolCall.id,\n          name: toolCall.function.name,\n          anthropicBlockIndex,\n        }\n\n        events.push({\n          type: \"content_block_start\",\n          index: anthropicBlockIndex,\n          content_block: {\n            type: \"tool_use\",\n            id: toolCall.id,\n            name: toolCall.function.name,\n            input: {},\n          },\n        })\n        state.contentBlockOpen = true\n      }\n\n      if (toolCall.function?.arguments) {\n        const toolCallInfo = state.toolCalls[toolCall.index]\n        // Tool call can still be empty\n        // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n        if (toolCallInfo) {\n          events.push({\n            type: \"content_block_delta\",\n            index: toolCallInfo.anthropicBlockIndex,\n            delta: {\n              type: \"input_json_delta\",\n              partial_json: toolCall.function.arguments,\n            },\n          })\n        }\n      }\n    }\n  }\n\n  if (choice.finish_reason) {\n    if (state.contentBlockOpen) {\n      events.push({\n        type: \"content_block_stop\",\n        index: state.contentBlockIndex,\n      })\n      state.contentBlockOpen = false\n    }\n\n    events.push(\n      {\n        type: \"message_delta\",\n        delta: {\n          stop_reason: mapOpenAIStopReasonToAnthropic(choice.finish_reason),\n          stop_sequence: null,\n        },\n        usage: {\n          input_tokens:\n            (chunk.usage?.prompt_tokens ?? 0)\n            - (chunk.usage?.prompt_tokens_details?.cached_tokens ?? 0),\n          output_tokens: chunk.usage?.completion_tokens ?? 0,\n          ...(chunk.usage?.prompt_tokens_details?.cached_tokens\n            !== undefined && {\n            cache_read_input_tokens:\n              chunk.usage.prompt_tokens_details.cached_tokens,\n          }),\n        },\n      },\n      {\n        type: \"message_stop\",\n      },\n    )\n  }\n\n  return events\n}\n\nexport function translateErrorToAnthropicErrorEvent(\n  message?: string,\n): AnthropicStreamEventData {\n  if (isContextOverflowMessage(message)) {\n    return {\n      type: \"error\",\n      error: {\n        type: \"invalid_request_error\",\n        message:\n          \"prompt is too long: upstream operation timed out while streaming the response\",\n      },\n    }\n  }\n\n  return {\n    type: \"error\",\n    error: {\n      type: \"api_error\",\n      message: message ?? \"An unexpected error occurred during streaming.\",\n    },\n  }\n}\n\nfunction isContextOverflowMessage(message: string | undefined): boolean {\n  return (\n    message !== undefined\n    && (/prompt is too long/i.test(message)\n      || /operation timed out/i.test(message)\n      || /request entity too large/i.test(message)\n      || /context_length_exceeded/i.test(message)\n      || /payload too large/i.test(message)\n      || /maximum context length/i.test(message))\n  )\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE } from \"hono/streaming\"\n\nimport type { ResponsesApiResponse } from \"~/routes/responses/types\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport {\n  fitContext,\n  fitUnknownModelContext,\n  isPayloadOverUnknownModelCeiling,\n} from \"~/lib/context-manager\"\nimport { HTTPError } from \"~/lib/error\"\nimport { createPromptTooLongError } from \"~/lib/prompt-too-long\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport {\n  createChatCompletions,\n  type ChatCompletionChunk,\n  type ChatCompletionsPayload,\n  type ChatCompletionResponse,\n} from \"~/services/copilot/create-chat-completions\"\nimport { createResponses } from \"~/services/copilot/create-responses\"\n\nimport {\n  type AnthropicMessagesPayload,\n  type AnthropicStreamState,\n} from \"./anthropic-types\"\nimport {\n  preprocessAnthropicPayload,\n  translateToAnthropic,\n  translateToOpenAI,\n} from \"./non-stream-translation\"\nimport {\n  translateAnthropicMessagesToResponses,\n  translateResponsesToAnthropicMessage,\n  writeResponsesAsAnthropicStream,\n} from \"./responses-bridge\"\nimport {\n  translateChunkToAnthropicEvents,\n  translateErrorToAnthropicErrorEvent,\n} from \"./stream-translation\"\n\n/** Heartbeat interval for SSE keepalive. Claude Code's idle timeout is 90s\n *  (CLAUDE_STREAM_IDLE_TIMEOUT_MS); 15s gives a 6× safety margin. */\nconst PING_INTERVAL_MS = 15_000\nconst CHAT_COMPLETIONS_ENDPOINT = \"/chat/completions\"\nconst RESPONSES_ENDPOINT = \"/responses\"\n\ntype SSEStream = Parameters<Parameters<typeof streamSSE>[1]>[0]\ntype ChatCompletionResult = Awaited<ReturnType<typeof createChatCompletions>>\ntype CreateChatCompletionResponse = () => Promise<ChatCompletionResult>\n\ninterface ChatCompletionFlowOptions {\n  clientModel: string\n  requestId: string\n}\n\ninterface ResponsesFlowOptions extends ChatCompletionFlowOptions {\n  model: string\n}\n\ninterface ChatCompletionStreamOptions extends ChatCompletionFlowOptions {\n  createResponse: CreateChatCompletionResponse\n  streamState: AnthropicStreamState\n}\n\ninterface StreamCleanupOptions {\n  error: unknown\n  requestId: string\n  streamState: AnthropicStreamState\n}\n\nfunction generateRequestId(): string {\n  // RFC 4122 v4-ish; sufficient for response correlation.\n  return `req_${crypto.randomUUID().replaceAll(\"-\", \"\")}`\n}\n\nexport async function handleCompletion(c: Context) {\n  await checkRateLimit(state)\n\n  const requestId = c.req.header(\"x-client-request-id\") ?? generateRequestId()\n  c.header(\"request-id\", requestId)\n  c.header(\"x-request-id\", requestId)\n\n  const anthropicPayload = await c.req.json<AnthropicMessagesPayload>()\n  // Lazy debug logging — JSON.stringify on a large payload is 5-30ms even\n  // when debug output is suppressed. Guard with level check (debug = 4).\n  if (consola.level >= 4) {\n    consola.debug(\n      `[${requestId}] Anthropic request payload:`,\n      JSON.stringify(anthropicPayload).slice(0, 2000),\n    )\n  }\n\n  // Preserve the client-requested model name so we can echo it back in the\n  // response (Claude Code reads `response.model` for display/telemetry).\n  const clientModel = anthropicPayload.model\n\n  // Async preprocessing: PDF document block extraction, etc.\n  const preprocessed = await preprocessAnthropicPayload(anthropicPayload)\n  const openAIPayload = translateToOpenAI(preprocessed)\n  const model = state.models?.data.find((m) => m.id === openAIPayload.model)\n\n  if (shouldUseResponsesForMessages(model)) {\n    return await handleResponsesMessages(c, preprocessed, {\n      clientModel,\n      model: openAIPayload.model,\n      requestId,\n    })\n  }\n\n  return await handleChatCompletions(c, openAIPayload, {\n    clientModel,\n    requestId,\n  })\n}\n\nasync function handleChatCompletions(\n  c: Context,\n  openAIPayload: ChatCompletionsPayload,\n  options: ChatCompletionFlowOptions,\n) {\n  if (consola.level >= 4) {\n    consola.debug(\n      `[${options.requestId}] Translated OpenAI request payload:`,\n      JSON.stringify(openAIPayload),\n    )\n  }\n\n  // Byte-based context management — fast path returns input unchanged.\n  const model = state.models?.data.find((m) => m.id === openAIPayload.model)\n  const fittedPayload =\n    model ?\n      fitContext(openAIPayload, model)\n    : fitUnknownModelContext(openAIPayload)\n\n  if (!model && isPayloadOverUnknownModelCeiling(fittedPayload)) {\n    throw createPromptTooLongError(\n      fittedPayload,\n      JSON.stringify(fittedPayload).length,\n    )\n  }\n\n  if (fittedPayload.messages.length !== openAIPayload.messages.length) {\n    consola.info(\n      `[${options.requestId}] Context management: ${openAIPayload.messages.length} → ${fittedPayload.messages.length} messages`,\n    )\n  }\n\n  if (state.manualApprove) {\n    await awaitApproval()\n  }\n\n  if (fittedPayload.stream) {\n    consola.debug(`[${options.requestId}] Streaming response from Copilot`)\n    return handleStreamingChatCompletion(\n      c,\n      () => createChatCompletions(fittedPayload),\n      options,\n    )\n  }\n\n  const response = await createChatCompletions(fittedPayload)\n  if (!isNonStreaming(response)) {\n    throw new Error(\"Expected non-streaming response from Copilot\")\n  }\n  return handleNonStreamingChatCompletion(c, response, options)\n}\n\nasync function handleResponsesMessages(\n  c: Context,\n  payload: AnthropicMessagesPayload,\n  options: ResponsesFlowOptions,\n) {\n  if (state.manualApprove) {\n    await awaitApproval()\n  }\n\n  const responsesPayload = translateAnthropicMessagesToResponses(\n    payload,\n    options.model,\n  )\n\n  if (payload.stream) {\n    return streamSSE(c, async (stream) => {\n      const stopPings = startPings(stream)\n      try {\n        const response = await createResponses(responsesPayload)\n        const body = (await response.json()) as ResponsesApiResponse\n        await writeResponsesAsAnthropicStream(stream, body, options.clientModel)\n      } catch (error) {\n        await stream.writeSSE({\n          event: \"error\",\n          data: JSON.stringify(\n            translateErrorToAnthropicErrorEvent(\n              error instanceof Error ? error.message : undefined,\n            ),\n          ),\n        })\n      } finally {\n        stopPings()\n      }\n    })\n  }\n\n  const response = await createResponses(responsesPayload)\n  const body = (await response.json()) as ResponsesApiResponse\n  return c.json(translateResponsesToAnthropicMessage(body, options.clientModel))\n}\n\nfunction shouldUseResponsesForMessages(model: Model | undefined): boolean {\n  if (!model?.supported_endpoints) return false\n  return (\n    model.supported_endpoints.includes(RESPONSES_ENDPOINT)\n    && !model.supported_endpoints.includes(CHAT_COMPLETIONS_ENDPOINT)\n  )\n}\n\nfunction handleNonStreamingChatCompletion(\n  c: Context,\n  response: ChatCompletionResponse,\n  options: ChatCompletionFlowOptions,\n) {\n  if (consola.level >= 4) {\n    consola.debug(\n      `[${options.requestId}] Non-streaming response from Copilot:`,\n      JSON.stringify(response).slice(-400),\n    )\n  }\n\n  try {\n    const anthropicResponse = translateToAnthropic(\n      response,\n      options.clientModel,\n    )\n    if (consola.level >= 4) {\n      consola.debug(\n        `[${options.requestId}] Translated Anthropic response:`,\n        JSON.stringify(anthropicResponse),\n      )\n    }\n    return c.json(anthropicResponse)\n  } catch (error) {\n    return c.json(createTranslationErrorBody(error, options.requestId), 500)\n  }\n}\n\nfunction createTranslationErrorBody(error: unknown, requestId: string) {\n  consola.error(\n    `[${requestId}] Failed to translate non-streaming response:`,\n    error,\n  )\n  return {\n    type: \"error\" as const,\n    error: {\n      type: \"api_error\",\n      message:\n        error instanceof Error ?\n          `Translation failed: ${error.message}`\n        : \"Translation failed\",\n    },\n  }\n}\n\nfunction handleStreamingChatCompletion(\n  c: Context,\n  createResponse: CreateChatCompletionResponse,\n  options: ChatCompletionFlowOptions,\n) {\n  return streamSSE(c, async (stream) => {\n    const streamState: AnthropicStreamState = {\n      messageStartSent: false,\n      contentBlockIndex: 0,\n      contentBlockOpen: false,\n      toolCalls: {},\n    }\n\n    const stopPings = startPings(stream)\n\n    try {\n      await writePing(stream)\n      await forwardChatCompletionStream(stream, {\n        ...options,\n        createResponse,\n        streamState,\n      })\n    } catch (error) {\n      await emitStreamErrorCleanup(stream, {\n        error,\n        requestId: options.requestId,\n        streamState,\n      })\n    } finally {\n      stopPings()\n    }\n  })\n}\n\nfunction startPings(stream: SSEStream): () => void {\n  const pingTimer = setInterval(() => {\n    void writePing(stream).catch(() => {})\n  }, PING_INTERVAL_MS)\n\n  return () => clearInterval(pingTimer)\n}\n\nasync function writePing(stream: SSEStream): Promise<void> {\n  await stream.writeSSE({\n    event: \"ping\",\n    data: JSON.stringify({ type: \"ping\" }),\n  })\n}\n\nasync function forwardChatCompletionStream(\n  stream: SSEStream,\n  options: ChatCompletionStreamOptions,\n) {\n  const response = await options.createResponse()\n  if (isNonStreaming(response)) {\n    throw new Error(\"Expected streaming response from Copilot\")\n  }\n\n  for await (const rawEvent of response) {\n    if (rawEvent.data === \"[DONE]\") break\n    if (!rawEvent.data) continue\n\n    const chunk = parseChatCompletionChunk(rawEvent.data, options.requestId)\n    if (!chunk) continue\n\n    if (!options.streamState.messageStartSent) chunk.model = options.clientModel\n\n    for (const event of translateChunkToAnthropicEvents(\n      chunk,\n      options.streamState,\n    )) {\n      await stream.writeSSE({ event: event.type, data: JSON.stringify(event) })\n    }\n  }\n}\n\nfunction parseChatCompletionChunk(\n  data: string,\n  requestId: string,\n): ChatCompletionChunk | null {\n  try {\n    return JSON.parse(data) as ChatCompletionChunk\n  } catch (parseError) {\n    consola.warn(\n      `[${requestId}] Skipping unparseable Copilot chunk:`,\n      parseError,\n    )\n    return null\n  }\n}\n\nasync function emitStreamErrorCleanup(\n  stream: SSEStream,\n  options: StreamCleanupOptions,\n) {\n  consola.error(`[${options.requestId}] Streaming error:`, options.error)\n\n  try {\n    const errorMessage = await extractStreamErrorMessage(options.error)\n    await closeOpenContentBlock(stream, options.streamState)\n    await closeStartedMessage(stream, options.streamState)\n    await stream.writeSSE({\n      event: \"error\",\n      data: JSON.stringify(translateErrorToAnthropicErrorEvent(errorMessage)),\n    })\n  } catch (cleanupError) {\n    consola.error(\n      `[${options.requestId}] Failed to emit stream cleanup events:`,\n      cleanupError,\n    )\n  }\n}\n\nasync function extractStreamErrorMessage(\n  error: unknown,\n): Promise<string | undefined> {\n  if (error instanceof HTTPError) {\n    try {\n      return extractMessageFromErrorText(await error.response.text())\n    } catch {\n      return error.message\n    }\n  }\n\n  return error instanceof Error ? error.message : undefined\n}\n\nfunction extractMessageFromErrorText(errorText: string): string {\n  try {\n    const parsed = JSON.parse(errorText) as unknown\n    const extracted = extractMessageFromParsedError(parsed)\n    if (extracted) return extracted\n  } catch {\n    return errorText\n  }\n\n  return errorText\n}\n\nfunction extractMessageFromParsedError(parsed: unknown): string | undefined {\n  if (typeof parsed === \"string\") return parsed\n  if (typeof parsed !== \"object\" || parsed === null) return undefined\n\n  const obj = parsed as Record<string, unknown>\n  const error = obj.error\n  if (typeof error === \"string\") return error\n  if (typeof error === \"object\" && error !== null) {\n    const nested = error as Record<string, unknown>\n    if (typeof nested.message === \"string\") return nested.message\n  }\n  if (typeof obj.message === \"string\") return obj.message\n\n  return undefined\n}\n\nasync function closeOpenContentBlock(\n  stream: SSEStream,\n  streamState: AnthropicStreamState,\n) {\n  if (!streamState.contentBlockOpen) return\n\n  await stream.writeSSE({\n    event: \"content_block_stop\",\n    data: JSON.stringify({\n      type: \"content_block_stop\",\n      index: streamState.contentBlockIndex,\n    }),\n  })\n}\n\nasync function closeStartedMessage(\n  stream: SSEStream,\n  streamState: AnthropicStreamState,\n) {\n  if (!streamState.messageStartSent) return\n\n  await stream.writeSSE({\n    event: \"message_delta\",\n    data: JSON.stringify({\n      type: \"message_delta\",\n      delta: { stop_reason: \"end_turn\", stop_sequence: null },\n      usage: { output_tokens: 0 },\n    }),\n  })\n  await stream.writeSSE({\n    event: \"message_stop\",\n    data: JSON.stringify({ type: \"message_stop\" }),\n  })\n}\n\nconst isNonStreaming = (\n  response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse => Object.hasOwn(response, \"choices\")\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCountTokens } from \"./count-tokens-handler\"\nimport { handleCompletion } from \"./handler\"\n\nexport const messageRoutes = new Hono()\n\nmessageRoutes.post(\"/\", async (c) => {\n  try {\n    return await handleCompletion(c)\n  } catch (error) {\n    return await forwardError(c, error)\n  }\n})\n\nmessageRoutes.post(\"/count_tokens\", async (c) => {\n  try {\n    return await handleCountTokens(c)\n  } catch (error) {\n    return await forwardError(c, error)\n  }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\nimport { cacheModels } from \"~/lib/utils\"\n\nexport const modelRoutes = new Hono()\n\nmodelRoutes.get(\"/\", async (c) => {\n  try {\n    // Codex appends client_version and expects its own model-catalog schema.\n    // An empty catalog keeps Codex's bundled metadata and instructions; partial\n    // remote entries would replace them instead of merging individual fields.\n    if (c.req.query(\"client_version\") !== undefined) {\n      return c.json({ models: [] })\n    }\n\n    if (!state.models) {\n      // This should be handled by startup logic, but as a fallback.\n      await cacheModels()\n    }\n\n    const models = state.models?.data.map((model) => ({\n      id: model.id,\n      object: \"model\",\n      type: \"model\",\n      created: 0, // No date available from source\n      created_at: new Date(0).toISOString(), // No date available from source\n      owned_by: model.vendor,\n      display_name: model.name,\n      capabilities: model.capabilities,\n      supported_capabilities: inferClaudeCodeCapabilities(model),\n    }))\n\n    return c.json({\n      object: \"list\",\n      data: models,\n      has_more: false,\n    })\n  } catch (error) {\n    return await forwardError(c, error)\n  }\n})\n\nfunction inferClaudeCodeCapabilities(\n  model: NonNullable<typeof state.models>[\"data\"][number],\n): Array<string> {\n  const capabilities = new Set<string>()\n  const supports = model.capabilities.supports\n\n  if (supports.reasoning_effort?.length) {\n    capabilities.add(\"effort\")\n    if (supports.reasoning_effort.includes(\"xhigh\")) {\n      capabilities.add(\"xhigh_effort\")\n    }\n    if (supports.reasoning_effort.includes(\"max\")) {\n      capabilities.add(\"max_effort\")\n    }\n  }\n\n  if (supports.adaptive_thinking) {\n    capabilities.add(\"thinking\")\n    capabilities.add(\"adaptive_thinking\")\n    capabilities.add(\"interleaved_thinking\")\n  }\n\n  return [...capabilities]\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport { createResponses } from \"~/services/copilot/create-responses\"\n\nimport type { ResponsesApiRequest } from \"./types\"\n\nexport async function handleResponses(c: Context): Promise<Response> {\n  await checkRateLimit(state)\n\n  const request = await c.req.json<ResponsesApiRequest>()\n  consola.debug(\"Responses API request:\", JSON.stringify(request).slice(-400))\n\n  if (state.manualApprove) await awaitApproval()\n\n  return createResponses(request)\n}\n","import consola from \"consola\"\nimport { Hono } from \"hono\"\n\nimport { forwardError, HTTPError } from \"~/lib/error\"\n\nimport { handleResponses } from \"./handler\"\n\nexport const responsesRoutes = new Hono()\n\nresponsesRoutes.post(\"/\", async (c) => {\n  try {\n    return await handleResponses(c)\n  } catch (error) {\n    if (error instanceof HTTPError) {\n      const errorText = await error.response.text()\n      let parsed: unknown\n      try {\n        parsed = JSON.parse(errorText)\n      } catch {\n        parsed = errorText\n      }\n      consola.error(\"Responses HTTP error body:\", parsed)\n\n      return new Response(errorText, {\n        status: error.response.status,\n        statusText: error.response.statusText,\n        headers: {\n          \"content-type\":\n            error.response.headers.get(\"content-type\") ?? \"application/json\",\n        },\n      })\n    }\n\n    return await forwardError(c, error)\n  }\n})\n","import consola from \"consola\"\nimport { Hono } from \"hono\"\n\nimport { state } from \"~/lib/state\"\n\nexport const tokenRoute = new Hono()\n\ntokenRoute.get(\"/\", (c) => {\n  try {\n    return c.json({\n      token: state.copilotToken,\n    })\n  } catch (error) {\n    consola.error(\"Error fetching token:\", error)\n    return c.json({ error: \"Failed to fetch token\", token: null }, 500)\n  }\n})\n","import consola from \"consola\"\nimport { Hono } from \"hono\"\n\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\n\nexport const usageRoute = new Hono()\n\nusageRoute.get(\"/\", async (c) => {\n  try {\n    const usage = await getCopilotUsage()\n    return c.json(usage)\n  } catch (error) {\n    consola.error(\"Error fetching Copilot usage:\", error)\n    return c.json({ error: \"Failed to fetch Copilot usage\" }, 500)\n  }\n})\n","import { Hono } from \"hono\"\nimport { cors } from \"hono/cors\"\nimport { logger } from \"hono/logger\"\n\nimport { optionalLocalAuth } from \"./lib/local-auth\"\nimport { requestTraceMiddleware } from \"./lib/request-trace\"\nimport { completionRoutes } from \"./routes/chat-completions/route\"\nimport { debugRoutes } from \"./routes/debug/route\"\nimport { embeddingRoutes } from \"./routes/embeddings/route\"\nimport { messageRoutes } from \"./routes/messages/route\"\nimport { modelRoutes } from \"./routes/models/route\"\nimport { responsesRoutes } from \"./routes/responses/route\"\nimport { tokenRoute } from \"./routes/token/route\"\nimport { usageRoute } from \"./routes/usage/route\"\n\nexport const server = new Hono()\n\nserver.use(logger())\nserver.use(cors())\nserver.use(requestTraceMiddleware)\n\nserver.get(\"/\", (c) => c.text(\"Server running\"))\n\nserver.use(optionalLocalAuth)\n\nserver.route(\"/chat/completions\", completionRoutes)\nserver.route(\"/debug\", debugRoutes)\nserver.route(\"/models\", modelRoutes)\nserver.route(\"/embeddings\", embeddingRoutes)\nserver.route(\"/usage\", usageRoute)\nserver.route(\"/token\", tokenRoute)\n\n// Compatibility with tools that expect v1/ prefix\nserver.route(\"/v1/chat/completions\", completionRoutes)\nserver.route(\"/v1/models\", modelRoutes)\nserver.route(\"/v1/embeddings\", embeddingRoutes)\n\n// OpenAI Responses API endpoint\nserver.route(\"/v1/responses\", responsesRoutes)\n\n// Anthropic compatible endpoints\nserver.route(\"/v1/messages\", messageRoutes)\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport clipboard from \"clipboardy\"\nimport consola from \"consola\"\nimport { serve, type ServerHandler } from \"srvx\"\nimport invariant from \"tiny-invariant\"\n\nimport { parseLocalApiKeys } from \"./lib/local-auth\"\nimport { ensurePaths } from \"./lib/paths\"\nimport { initProxyFromEnv } from \"./lib/proxy\"\nimport { generateEnvScript } from \"./lib/shell\"\nimport { state } from \"./lib/state\"\nimport { setupCopilotToken, setupGitHubToken } from \"./lib/token\"\nimport { cacheModels, cacheVSCodeVersion } from \"./lib/utils\"\nimport { server } from \"./server\"\n\ninterface RunServerOptions {\n  port: number\n  verbose: boolean\n  accountType: string\n  manual: boolean\n  rateLimit?: number\n  rateLimitWait: boolean\n  githubToken?: string\n  claudeCode: boolean\n  showToken: boolean\n  proxyEnv: boolean\n  apiKey?: string\n}\n\nexport async function runServer(options: RunServerOptions): Promise<void> {\n  if (options.proxyEnv) {\n    initProxyFromEnv()\n  }\n\n  if (options.verbose) {\n    consola.level = 5\n    consola.info(\"Verbose logging enabled\")\n  }\n\n  state.accountType = options.accountType\n  if (options.accountType !== \"individual\") {\n    consola.info(`Using ${options.accountType} plan GitHub account`)\n  }\n\n  state.manualApprove = options.manual\n  state.rateLimitSeconds = options.rateLimit\n  state.rateLimitWait = options.rateLimitWait\n  state.showToken = options.showToken\n  state.localApiKeys = parseLocalApiKeys(options.apiKey)\n  if (state.localApiKeys.length > 0) {\n    consola.info(\"Local API-key auth enabled\")\n  }\n\n  if (options.githubToken) {\n    state.githubToken = options.githubToken\n    consola.info(\"Using provided GitHub token\")\n  }\n\n  await ensurePaths()\n  await cacheVSCodeVersion()\n\n  if (!options.githubToken) {\n    await setupGitHubToken()\n  }\n\n  await setupCopilotToken()\n  await cacheModels()\n\n  consola.info(\n    `Available models: \\n${state.models?.data.map((model) => `- ${model.id}`).join(\"\\n\")}`,\n  )\n\n  const serverUrl = `http://localhost:${options.port}`\n\n  if (options.claudeCode) {\n    invariant(state.models, \"Models should be loaded by now\")\n\n    const selectedModel = await consola.prompt(\n      \"Select a model to use with Claude Code\",\n      {\n        type: \"select\",\n        options: state.models.data.map((model) => model.id),\n      },\n    )\n\n    const selectedSmallModel = await consola.prompt(\n      \"Select a small model to use with Claude Code\",\n      {\n        type: \"select\",\n        options: state.models.data.map((model) => model.id),\n      },\n    )\n\n    const command = generateEnvScript(\n      {\n        ANTHROPIC_BASE_URL: serverUrl,\n        ANTHROPIC_AUTH_TOKEN: \"dummy\",\n        ANTHROPIC_MODEL: selectedModel,\n        ANTHROPIC_DEFAULT_SONNET_MODEL: selectedModel,\n        ANTHROPIC_SMALL_FAST_MODEL: selectedSmallModel,\n        ANTHROPIC_DEFAULT_HAIKU_MODEL: selectedSmallModel,\n        DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n        CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\n      },\n      \"claude\",\n    )\n\n    try {\n      clipboard.writeSync(command)\n      consola.success(\"Copied Claude Code command to clipboard!\")\n    } catch {\n      consola.warn(\n        \"Failed to copy to clipboard. Here is the Claude Code command:\",\n      )\n      consola.log(command)\n    }\n  }\n\n  consola.box(\n    `🌐 Usage Viewer: https://voidsteed.github.io/copilot-proxy-api/dashboard.html?endpoint=${serverUrl}/usage`,\n  )\n\n  serve({\n    fetch: server.fetch as ServerHandler,\n    port: options.port,\n    // Bun's HTTP server defaults to a 10s idleTimeout, which closes the\n    // client socket while we're still waiting on Copilot's upstream\n    // response (Copilot can take 10-60s for large opus requests). Setting\n    // to 0 disables the idle timeout entirely. Claude Code reports this\n    // as \"API Error: The socket connection was closed unexpectedly\".\n    bun: { idleTimeout: 0 },\n  })\n}\n\nexport const start = defineCommand({\n  meta: {\n    name: \"start\",\n    description: \"Start the Copilot API server\",\n  },\n  args: {\n    port: {\n      alias: \"p\",\n      type: \"string\",\n      default: \"4141\",\n      description: \"Port to listen on\",\n    },\n    verbose: {\n      alias: \"v\",\n      type: \"boolean\",\n      default: false,\n      description: \"Enable verbose logging\",\n    },\n    \"account-type\": {\n      alias: \"a\",\n      type: \"string\",\n      default: \"individual\",\n      description: \"Account type to use (individual, business, enterprise)\",\n    },\n    manual: {\n      type: \"boolean\",\n      default: false,\n      description: \"Enable manual request approval\",\n    },\n    \"rate-limit\": {\n      alias: \"r\",\n      type: \"string\",\n      description: \"Rate limit in seconds between requests\",\n    },\n    wait: {\n      alias: \"w\",\n      type: \"boolean\",\n      default: false,\n      description:\n        \"Wait instead of error when rate limit is hit. Has no effect if rate limit is not set\",\n    },\n    \"github-token\": {\n      alias: \"g\",\n      type: \"string\",\n      description:\n        \"Provide GitHub token directly (must be generated using the `auth` subcommand)\",\n    },\n    \"claude-code\": {\n      alias: \"c\",\n      type: \"boolean\",\n      default: false,\n      description:\n        \"Generate a command to launch Claude Code with Copilot API config\",\n    },\n    \"show-token\": {\n      type: \"boolean\",\n      default: false,\n      description: \"Show GitHub and Copilot tokens on fetch and refresh\",\n    },\n    \"proxy-env\": {\n      type: \"boolean\",\n      default: false,\n      description: \"Initialize proxy from environment variables\",\n    },\n    \"api-key\": {\n      type: \"string\",\n      description:\n        \"Require one of these comma-separated local API keys for proxy routes\",\n    },\n  },\n  run({ args }) {\n    const rateLimitRaw = args[\"rate-limit\"]\n    const rateLimit =\n      rateLimitRaw === undefined ? undefined : Number.parseInt(rateLimitRaw, 10)\n\n    return runServer({\n      port: Number.parseInt(args.port, 10),\n      verbose: args.verbose,\n      accountType: args[\"account-type\"],\n      manual: args.manual,\n      rateLimit,\n      rateLimitWait: args.wait,\n      githubToken: args[\"github-token\"],\n      claudeCode: args[\"claude-code\"],\n      showToken: args[\"show-token\"],\n      proxyEnv: args[\"proxy-env\"],\n      apiKey: args[\"api-key\"],\n    })\n  },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand, runMain } from \"citty\"\n\nimport { auth } from \"./auth\"\nimport { checkUsage } from \"./check-usage\"\nimport { debug } from \"./debug\"\nimport { start } from \"./start\"\n\nconst main = defineCommand({\n  meta: {\n    name: \"copilot-proxy-api\",\n    description:\n      \"A wrapper around GitHub Copilot API to make it OpenAI compatible, making it usable for other tools.\",\n  },\n  subCommands: { auth, start, \"check-usage\": checkUsage, debug },\n})\n\nawait runMain(main)\n"],"mappings":"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"}