github-router 0.3.261 → 0.3.263

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/{attribution-settings-Bl0HHJQF.js → attribution-settings-DFIVIRG8.js} +3 -3
  2. package/dist/{attribution-settings-Bl0HHJQF.js.map → attribution-settings-DFIVIRG8.js.map} +1 -1
  3. package/dist/{auth-I8k2OOvA.js → auth-WA88cE9q.js} +2 -2
  4. package/dist/{auth-I8k2OOvA.js.map → auth-WA88cE9q.js.map} +1 -1
  5. package/dist/browser-ext/manifest.json +1 -1
  6. package/dist/{check-usage-SOn7-cWc.js → check-usage-v2apGKz7.js} +3 -3
  7. package/dist/{check-usage-SOn7-cWc.js.map → check-usage-v2apGKz7.js.map} +1 -1
  8. package/dist/{claude-CEaI47j7.js → claude-BCI3Sx6_.js} +9 -10
  9. package/dist/{claude-CEaI47j7.js.map → claude-BCI3Sx6_.js.map} +1 -1
  10. package/dist/{codex-C6Eyz3EV.js → codex-DyJIrbJt.js} +5 -6
  11. package/dist/{codex-C6Eyz3EV.js.map → codex-DyJIrbJt.js.map} +1 -1
  12. package/dist/engine-D8dlcSW6.js +2 -0
  13. package/dist/{gate-discovery-BnPhH_AC.js → gate-discovery-cMbt8Ct2.js} +3 -3
  14. package/dist/{gate-discovery-BnPhH_AC.js.map → gate-discovery-cMbt8Ct2.js.map} +1 -1
  15. package/dist/{get-copilot-usage-CYpAsYrM.js → get-copilot-usage-DOFJWJaQ.js} +2 -2
  16. package/dist/{get-copilot-usage-CYpAsYrM.js.map → get-copilot-usage-DOFJWJaQ.js.map} +1 -1
  17. package/dist/{internal-prompt-submit-CSJR24-y.js → internal-prompt-submit-C0XOPgcP.js} +2 -2
  18. package/dist/{internal-prompt-submit-CSJR24-y.js.map → internal-prompt-submit-C0XOPgcP.js.map} +1 -1
  19. package/dist/{internal-stop-hook-CiflCJO-.js → internal-stop-hook-CBcE2Js8.js} +4 -4
  20. package/dist/{internal-stop-hook-CiflCJO-.js.map → internal-stop-hook-CBcE2Js8.js.map} +1 -1
  21. package/dist/main.js +9 -9
  22. package/dist/{models-uQgsKNNC.js → models-Cv6gprpy.js} +2 -2
  23. package/dist/{models-uQgsKNNC.js.map → models-Cv6gprpy.js.map} +1 -1
  24. package/dist/{orchestration-BiZviyam.js → orchestration-B6qidQAd.js} +2 -2
  25. package/dist/{orchestration-BiZviyam.js.map → orchestration-B6qidQAd.js.map} +1 -1
  26. package/dist/{peer-mcp-personas-V4AXhm9B.js → peer-mcp-personas-B22ncnbQ.js} +38 -23
  27. package/dist/peer-mcp-personas-B22ncnbQ.js.map +1 -0
  28. package/dist/{provision-BLwsOFCI.js → provision-DSpLQHC3.js} +2 -2
  29. package/dist/{provision-BLwsOFCI.js.map → provision-DSpLQHC3.js.map} +1 -1
  30. package/dist/{serve-De-kqWXM.js → serve-D9tBVVoK.js} +16 -11
  31. package/dist/{serve-De-kqWXM.js.map → serve-D9tBVVoK.js.map} +1 -1
  32. package/dist/{server-setup-BeeT8m-w.js → server-setup-BM9Smfek.js} +317 -20
  33. package/dist/server-setup-BM9Smfek.js.map +1 -0
  34. package/dist/{start-DEC0M8UH.js → start-D7Hx2T_T.js} +3 -3
  35. package/dist/{start-DEC0M8UH.js.map → start-D7Hx2T_T.js.map} +1 -1
  36. package/dist/{stop-gate-hook-DoYD9Wt8.js → stop-gate-hook-Bmwla_2u.js} +10 -5
  37. package/dist/{stop-gate-hook-DoYD9Wt8.js.map → stop-gate-hook-Bmwla_2u.js.map} +1 -1
  38. package/dist/{token-DWknHe9M.js → token-C8Uh7aUe.js} +73 -12
  39. package/dist/{token-DWknHe9M.js.map → token-C8Uh7aUe.js.map} +1 -1
  40. package/package.json +1 -1
  41. package/dist/engine-B4Ohhv5i.js +0 -2
  42. package/dist/file-log-reporter-vI8qCFNM.js +0 -158
  43. package/dist/file-log-reporter-vI8qCFNM.js.map +0 -1
  44. package/dist/peer-mcp-personas-V4AXhm9B.js.map +0 -1
  45. package/dist/server-setup-BeeT8m-w.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"server-setup-BeeT8m-w.js","names":["NPM_PACKAGE","THROTTLE_HOURS","NPM_VIEW_TIMEOUT_MS","cacheFilePath","readCache","fs","writeCache","shouldCheckNow","getLatestVersion","fs","process","process","spawnChild","get","ENCODER","formatSSE","handleCompletion","injectWebSearchIfNeeded","isNonStreaming","extractUserQuery","handleCompletion","makeToolUseId","parseToolArgs","isWebSearchTool","extractUserQuery","resolveModelInBody","sanitizeCacheControl","stripAnthropicOnlyFields","packageJson.name","packageJson.version","app"],"sources":["../src/lib/claude-version-check.ts","../src/lib/self-update.ts","../src/lib/model-validation.ts","../src/lib/keep-awake/flags.ts","../src/lib/keep-awake/helper.ts","../src/lib/keep-awake/index.ts","../src/lib/first-mate/scheduler/autospawn.ts","../src/lib/proxy.ts","../package.json","../src/lib/approval.ts","../src/lib/rate-limit.ts","../src/lib/request-log.ts","../src/routes/chat-completions/handler.ts","../src/routes/chat-completions/route.ts","../src/services/copilot/create-embeddings.ts","../src/routes/embeddings/route.ts","../src/routes/mcp/route.ts","../src/lib/sanitize-anthropic-body.ts","../src/lib/anthropic-translate/anthropic-sse.ts","../src/lib/reasoning-effort.ts","../src/lib/anthropic-translate/anthropic-request.ts","../src/lib/anthropic-translate/chat-request.ts","../src/lib/anthropic-translate/chat-egress.ts","../src/lib/anthropic-translate/responses-egress.ts","../src/lib/anthropic-translate/classifier.ts","../src/lib/anthropic-translate/index.ts","../src/routes/messages/handler.ts","../src/routes/messages/count-tokens-handler.ts","../src/routes/messages/route.ts","../src/routes/models/route.ts","../src/routes/responses/handler.ts","../src/routes/responses/route.ts","../src/routes/search/route.ts","../src/routes/token/route.ts","../src/routes/usage/route.ts","../src/server.ts","../src/lib/server-setup.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nimport consola from \"consola\"\n\nimport {\n resolveExecutable,\n runCommandCapture,\n runCommandVoid,\n} from \"./exec\"\nimport { withInstallLock } from \"./update-lock\"\n\nconst NPM_PACKAGE = \"@anthropic-ai/claude-code\"\nconst THROTTLE_HOURS = 1\nconst NPM_VIEW_TIMEOUT_MS = 5000\nconst CLAUDE_VERSION_TIMEOUT_MS = 3000\nconst NPM_INSTALL_TIMEOUT_MS = 120_000 // 2 min — npm install can be slow on cold caches\n\ninterface VersionCheckCache {\n /** ISO timestamp of last check */\n checkedAt: string\n /** Installed version at last check */\n installedVersion: string | null\n /** Latest version on npm at last check */\n latestVersion: string | null\n}\n\n/** Path to the throttle cache. Created on demand. */\nfunction cacheFilePath(): string {\n return path.join(\n os.homedir(),\n \".local\",\n \"share\",\n \"github-router\",\n \"last-update-check\",\n )\n}\n\n/**\n * Read the throttle cache. Returns null on missing/corrupt file —\n * triggers a fresh check.\n */\nasync function readCache(): Promise<VersionCheckCache | null> {\n try {\n const raw = await fs.readFile(cacheFilePath(), \"utf8\")\n const parsed = JSON.parse(raw) as VersionCheckCache\n if (\n typeof parsed.checkedAt !== \"string\"\n || (parsed.installedVersion !== null\n && typeof parsed.installedVersion !== \"string\")\n || (parsed.latestVersion !== null\n && typeof parsed.latestVersion !== \"string\")\n ) {\n return null\n }\n return parsed\n } catch {\n return null\n }\n}\n\nasync function writeCache(cache: VersionCheckCache): Promise<void> {\n try {\n await fs.mkdir(path.dirname(cacheFilePath()), { recursive: true })\n await fs.writeFile(cacheFilePath(), JSON.stringify(cache), {\n mode: 0o600,\n })\n } catch (err) {\n // Throttle cache is best-effort — a write failure means we'll re-check\n // on next launch. Not worth surfacing.\n consola.debug(\"Failed to write claude version-check cache:\", err)\n }\n}\n\n/** Check if it's been more than THROTTLE_HOURS since the last check. */\nfunction shouldCheckNow(cache: VersionCheckCache | null): boolean {\n if (!cache) return true\n const lastCheck = new Date(cache.checkedAt).getTime()\n if (Number.isNaN(lastCheck)) return true\n const hoursSince = (Date.now() - lastCheck) / 1000 / 3600\n return hoursSince >= THROTTLE_HOURS\n}\n\n/**\n * Read the installed `claude` version. Returns null if claude is not\n * on PATH or the version probe fails (e.g. older versions that don't\n * support `--version` cleanly).\n *\n * Windows-safe: `claude` is a `.cmd` shim that `execFile` cannot launch\n * directly. We resolve it to an absolute path (excluding the cwd, so a\n * planted `claude.cmd` in an untrusted repo can't run) and invoke it\n * through the shared exec helper.\n */\nasync function getInstalledVersion(): Promise<string | null> {\n const claudePath = resolveExecutable(\"claude\")\n if (!claudePath) return null\n try {\n const { stdout, code } = await runCommandCapture(\n [claudePath, \"--version\"],\n { timeoutMs: CLAUDE_VERSION_TIMEOUT_MS },\n )\n if (code !== 0) return null\n // Output shape: \"2.1.139 (Claude Code)\\n\"\n const match = stdout.match(/(\\d+\\.\\d+\\.\\d+)/)\n return match ? match[1] : null\n } catch {\n return null\n }\n}\n\n/**\n * Fetch the latest version of @anthropic-ai/claude-code from the npm\n * registry. Returns null on network failure / npm unavailable.\n *\n * Windows-safe: `npm` is `npm.cmd`; resolved to an absolute path\n * (excluding cwd) before invocation.\n */\nasync function getLatestVersion(): Promise<string | null> {\n const npmPath = resolveExecutable(\"npm\")\n if (!npmPath) return null\n try {\n const { stdout, code } = await runCommandCapture(\n [npmPath, \"view\", NPM_PACKAGE, \"version\", \"--silent\"],\n { timeoutMs: NPM_VIEW_TIMEOUT_MS },\n )\n if (code !== 0) return null\n const v = stdout.trim()\n return /^\\d+\\.\\d+\\.\\d+/.test(v) ? v : null\n } catch {\n return null\n }\n}\n\n/**\n * Compare two semver-shaped strings (only the leading X.Y.Z, no\n * pre-release / metadata handling — sufficient for npm-published\n * stable releases). Returns true if `latest` is strictly higher than\n * `installed`.\n */\nexport function isNewer(installed: string | null, latest: string | null): boolean {\n if (!installed || !latest) return false\n const a = installed.split(\".\").map((n) => parseInt(n, 10))\n const b = latest.split(\".\").map((n) => parseInt(n, 10))\n for (let i = 0; i < 3; i++) {\n const av = a[i] ?? 0\n const bv = b[i] ?? 0\n if (av < bv) return true\n if (av > bv) return false\n }\n return false\n}\n\nexport interface VersionCheckResult {\n /** Whether claude is on PATH at all */\n installed: boolean\n installedVersion: string | null\n latestVersion: string | null\n /** True if a newer version is available */\n needsUpdate: boolean\n /** Whether the check was skipped (throttled or disabled) */\n skipped: boolean\n skipReason?: \"throttled\" | \"disabled\" | \"no-npm\" | \"no-claude\"\n}\n\n/**\n * Run a version check (subject to throttle). Side-effect: updates the\n * throttle cache. Returns the comparison result.\n */\nexport async function checkClaudeVersion(opts: {\n noCheck?: boolean\n /** Bypass the throttle (used when the check is the user's main intent) */\n force?: boolean\n} = {}): Promise<VersionCheckResult> {\n if (opts.noCheck) {\n return {\n installed: false,\n installedVersion: null,\n latestVersion: null,\n needsUpdate: false,\n skipped: true,\n skipReason: \"disabled\",\n }\n }\n\n const cache = await readCache()\n if (!opts.force && !shouldCheckNow(cache)) {\n return {\n installed: cache?.installedVersion !== null,\n installedVersion: cache?.installedVersion ?? null,\n latestVersion: cache?.latestVersion ?? null,\n needsUpdate: isNewer(\n cache?.installedVersion ?? null,\n cache?.latestVersion ?? null,\n ),\n skipped: true,\n skipReason: \"throttled\",\n }\n }\n\n const installedVersion = await getInstalledVersion()\n if (installedVersion === null) {\n return {\n installed: false,\n installedVersion: null,\n latestVersion: null,\n needsUpdate: false,\n skipped: true,\n skipReason: \"no-claude\",\n }\n }\n\n const latestVersion = await getLatestVersion()\n // Update cache regardless of whether latest fetched (so we still\n // throttle if npm is offline).\n await writeCache({\n checkedAt: new Date().toISOString(),\n installedVersion,\n latestVersion,\n })\n\n if (latestVersion === null) {\n return {\n installed: true,\n installedVersion,\n latestVersion: null,\n needsUpdate: false,\n skipped: true,\n skipReason: \"no-npm\",\n }\n }\n\n return {\n installed: true,\n installedVersion,\n latestVersion,\n needsUpdate: isNewer(installedVersion, latestVersion),\n skipped: false,\n }\n}\n\n/**\n * Heuristic: did `claude update` fail because the subcommand does not\n * exist (a build predating `claude update`), as opposed to a transient\n * update error? We only npm-fall-back on this specific signal — falling\n * back on any failure would install a conflicting npm copy on\n * native-installer machines.\n *\n * Matches the usage/Commander-style \"unknown command\" messages CLIs emit\n * for an unrecognized subcommand. Deliberately narrow.\n */\nexport function looksLikeUnknownUpdateCommand(output: string): boolean {\n return /unknown command|unknown subcommand|unrecognized (sub)?command|invalid command|command not found|is not a (known|valid) command/i.test(\n output,\n )\n}\n\n/**\n * Update Claude Code to the latest version.\n *\n * Strategy (decided in the plan, corrected after a real-world false\n * negative): run `claude update` directly — it respects the user's\n * actual install method (native installer or npm), so it never creates a\n * conflicting second install, and it is NOT blocked by the\n * `DISABLE_AUTOUPDATER` the proxy sets in the *child* env (this runs from\n * the proxy's own env, and `claude update` is a manual command\n * unaffected by that flag).\n *\n * Only if `claude update` reports the subcommand is unknown (a build too\n * old to have it) do we fall back to `npm install -g\n * @anthropic-ai/claude-code@latest` with a VISIBLE warning. The earlier\n * `claude --help` capability probe was removed: it timed out / mismatched\n * on slow cold starts and wrongly forced the npm path every launch,\n * creating dual npm-global + native installs.\n *\n * Serialized across concurrent proxies via an install lock. Throws on\n * failure — the caller decides whether to warn and continue.\n */\nexport interface UpdateClaudeDeps {\n resolveExecutable: typeof resolveExecutable\n runCommandCapture: typeof runCommandCapture\n runCommandVoid: typeof runCommandVoid\n withInstallLock: typeof withInstallLock\n}\n\nexport async function updateClaude(\n latestVersion: string,\n deps: Partial<UpdateClaudeDeps> = {},\n): Promise<void> {\n const _resolve = deps.resolveExecutable ?? resolveExecutable\n const _capture = deps.runCommandCapture ?? runCommandCapture\n const _void = deps.runCommandVoid ?? runCommandVoid\n const _lock = deps.withInstallLock ?? withInstallLock\n\n const claudePath = _resolve(\"claude\")\n if (!claudePath) throw new Error(\"claude not found on PATH\")\n\n const ran = await _lock(\"claude-update.lock\", async () => {\n consola.info(`Updating Claude Code to ${latestVersion} via \\`claude update\\`...`)\n // Capture (not inherit) so we can detect an unknown-command signal;\n // echo the output afterward so the user still sees what happened.\n const { code, stdout, stderr } = await _capture([claudePath, \"update\"], {\n timeoutMs: NPM_INSTALL_TIMEOUT_MS,\n })\n const combined = `${stdout}${stderr}`\n const trimmed = combined.trim()\n if (trimmed) process.stdout.write(trimmed.endsWith(\"\\n\") ? trimmed : `${trimmed}\\n`)\n\n if (code === 0) {\n consola.success(`Claude Code updated to ${latestVersion}`)\n return\n }\n\n if (!looksLikeUnknownUpdateCommand(combined)) {\n throw new Error(`\\`claude update\\` exited with code ${code}`)\n }\n\n // Fallback: npm. Only reachable on installs too old to have\n // `claude update` at all.\n const npmPath = _resolve(\"npm\")\n if (!npmPath) {\n throw new Error(\n \"this Claude Code build predates `claude update` and npm is not on PATH; \" +\n `update manually: npm install -g ${NPM_PACKAGE}@latest`,\n )\n }\n consola.warn(\n \"This Claude Code build predates `claude update`; falling back to \" +\n `\\`npm install -g ${NPM_PACKAGE}@latest\\`.`,\n )\n const { code: npmCode, stderr: npmStderr } = await _void(\n [npmPath, \"install\", \"-g\", `${NPM_PACKAGE}@latest`, \"--silent\"],\n { timeoutMs: NPM_INSTALL_TIMEOUT_MS },\n )\n if (npmCode !== 0) {\n throw new Error(`npm install failed: ${npmStderr.trim() || `exit ${npmCode}`}`)\n }\n consola.success(`${NPM_PACKAGE} updated to ${latestVersion}`)\n })\n\n if (!ran) {\n consola.debug(\"Claude Code update already in progress in another process; skipping.\")\n }\n}\n","/**\n * Self-update for the `github-router` proxy.\n *\n * The proxy is a *running* process, so updating its own global install\n * in place (`npm install -g github-router@latest`) deletes/overwrites\n * files the OS holds open — on Windows that fails deterministically\n * (EPERM/EBUSY) and can corrupt the install. So we never install in\n * place: when a newer version exists we spawn a **detached updater that\n * waits for this process to exit**, then installs. The update takes\n * effect on the next launch — no re-exec, no restart prompt.\n *\n * Best-effort throughout: every failure is swallowed to debug/warn and\n * never blocks startup. The startup probe is bounded and the install is\n * off the critical path (detached), so even a blackholed network can't\n * delay the proxy from serving.\n */\n\nimport { spawn } from \"node:child_process\"\nimport fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nimport consola from \"consola\"\n\nimport { isNewer } from \"./claude-version-check\"\nimport {\n parseBoolEnv,\n resolveExecutable,\n runCommandCapture,\n} from \"./exec\"\nimport { withInstallLock } from \"./update-lock\"\nimport { getPackageVersion } from \"./version\"\n\n// The published, installable package is the UNSCOPED name. The scoped\n// `@animeshkundu/github-router` is GitHub-Packages-only and must NOT be\n// used for `npm view` / `npm install` here.\nconst NPM_PACKAGE = \"github-router\"\nconst THROTTLE_HOURS = 1\nconst NPM_VIEW_TIMEOUT_MS = 5000\n\ninterface SelfUpdateCache {\n checkedAt: string\n installedVersion: string | null\n latestVersion: string | null\n}\n\nfunction cacheFilePath(): string {\n return path.join(\n os.homedir(),\n \".local\",\n \"share\",\n \"github-router\",\n // Distinct from the Claude Code check's `last-update-check` so the\n // two throttles don't cross-suppress.\n \"last-self-update-check\",\n )\n}\n\nasync function readCache(): Promise<SelfUpdateCache | null> {\n try {\n const parsed = JSON.parse(\n await fs.readFile(cacheFilePath(), \"utf8\"),\n ) as SelfUpdateCache\n if (typeof parsed.checkedAt !== \"string\") return null\n return parsed\n } catch {\n return null\n }\n}\n\nasync function writeCache(cache: SelfUpdateCache): Promise<void> {\n try {\n await fs.mkdir(path.dirname(cacheFilePath()), { recursive: true })\n await fs.writeFile(cacheFilePath(), JSON.stringify(cache), { mode: 0o600 })\n } catch (err) {\n consola.debug(\"Failed to write self-update cache:\", err)\n }\n}\n\nfunction shouldCheckNow(cache: SelfUpdateCache | null): boolean {\n if (!cache) return true\n const last = new Date(cache.checkedAt).getTime()\n if (Number.isNaN(last)) return true\n return (Date.now() - last) / 1000 / 3600 >= THROTTLE_HOURS\n}\n\nasync function getLatestVersion(npmPath: string): Promise<string | null> {\n try {\n const { stdout, code } = await runCommandCapture(\n [npmPath, \"view\", NPM_PACKAGE, \"version\", \"--silent\"],\n { timeoutMs: NPM_VIEW_TIMEOUT_MS },\n )\n if (code !== 0) return null\n const v = stdout.trim()\n return /^\\d+\\.\\d+\\.\\d+/.test(v) ? v : null\n } catch {\n return null\n }\n}\n\n/**\n * Spawn a detached process that waits for THIS proxy (pid) to exit,\n * then runs `npm install -g github-router@latest`. Fully detached and\n * unref'd so it outlives the proxy; output discarded.\n *\n * The waiter is a tiny inline Node script (Node is guaranteed present —\n * the proxy runs on it) that polls `process.kill(pid, 0)` until the\n * parent is gone, then execs npm. This avoids the Windows file-lock by\n * never touching the global install while the proxy holds it open.\n */\nfunction spawnDetachedUpdater(npmPath: string): void {\n const parentPid = process.pid\n // Inline waiter: poll until the parent disappears, then install.\n const waiter = `\n const pid = ${parentPid};\n const { spawn } = require(\"node:child_process\");\n function alive() { try { process.kill(pid, 0); return true } catch { return false } }\n const timer = setInterval(() => {\n if (alive()) return;\n clearInterval(timer);\n const args = [\"install\", \"-g\", ${JSON.stringify(`${NPM_PACKAGE}@latest`)}, \"--silent\"];\n const isWin = process.platform === \"win32\";\n const child = spawn(${JSON.stringify(npmPath)}, args, {\n stdio: \"ignore\", windowsHide: true, shell: isWin, detached: !isWin,\n });\n child.on(\"error\", () => process.exit(0));\n child.on(\"exit\", () => process.exit(0));\n // Safety: never hang forever.\n setTimeout(() => process.exit(0), 180000).unref();\n }, 500);\n // Safety cap on the wait itself (e.g. extremely long sessions still\n // eventually give up rather than leak the waiter).\n setTimeout(() => { clearInterval(timer); process.exit(0); }, 24 * 3600 * 1000).unref();\n `.trim()\n\n const child = spawn(process.execPath, [\"-e\", waiter], {\n detached: true,\n stdio: \"ignore\",\n windowsHide: true,\n })\n child.unref()\n}\n\nexport interface RunSelfUpdateOpts {\n /** From `args[\"self-update\"]` (default true). */\n selfUpdate: boolean\n /** Bypass the throttle (used by tests / explicit forcing). */\n force?: boolean\n}\n\n/**\n * Probe npm for a newer `github-router` and, if found, queue a detached\n * post-exit update. Returns quickly; never throws. Call AFTER the\n * server is listening so the bounded probe can't delay binding.\n */\nexport async function runSelfUpdate(opts: RunSelfUpdateOpts): Promise<void> {\n if (!opts.selfUpdate) return\n if (parseBoolEnv(process.env.GH_ROUTER_NO_SELF_UPDATE) === true) return\n\n try {\n const cache = await readCache()\n if (!opts.force && !shouldCheckNow(cache)) return\n\n const installed = getPackageVersion()\n if (installed === \"unknown\") return // can't compare; skip silently\n\n const npmPath = resolveExecutable(\"npm\")\n if (!npmPath) return // npm not on PATH; skip\n\n const latest = await getLatestVersion(npmPath)\n // Write the throttle BEFORE acting so concurrent/next launches back\n // off even if the install is still settling (optimistic lock).\n await writeCache({\n checkedAt: new Date().toISOString(),\n installedVersion: installed,\n latestVersion: latest,\n })\n if (!latest || !isNewer(installed, latest)) return\n\n const queued = await withInstallLock(\"self-update.lock\", async () => {\n spawnDetachedUpdater(npmPath)\n })\n if (queued) {\n consola.info(\n `github-router ${installed} → ${latest} update queued; it takes effect on the next launch.`,\n )\n }\n } catch (err) {\n consola.debug(\"Self-update check failed:\", err)\n }\n}\n","import consola from \"consola\"\n\nimport { state } from \"./state\"\n\ntype Endpoint = \"/chat/completions\" | \"/responses\" | \"/v1/messages\"\n\nconst ENDPOINT_ALIASES: Record<string, Endpoint> = {\n \"/chat/completions\": \"/chat/completions\",\n \"/v1/chat/completions\": \"/chat/completions\",\n \"/responses\": \"/responses\",\n \"/v1/responses\": \"/responses\",\n \"/v1/messages\": \"/v1/messages\",\n}\n\n/**\n * Check whether a model supports the given endpoint, based on cached\n * `supported_endpoints` metadata from the Copilot `/models` response.\n *\n * Returns `true` (allow) when:\n * - the model is not found in the cache (don't block unknown models)\n * - the model has no `supported_endpoints` field (backward-compat)\n * - the endpoint is listed in `supported_endpoints`\n */\nexport function modelSupportsEndpoint(\n modelId: string,\n path: string,\n): boolean {\n const endpoint = ENDPOINT_ALIASES[path] ?? path\n const model = state.models?.data.find((m) => m.id === modelId)\n if (!model) return true\n\n const supported = model.supported_endpoints\n if (!supported || supported.length === 0) return true\n\n return supported.includes(endpoint)\n}\n\n/**\n * Log an error when a model is used on an endpoint it doesn't support.\n * Returns `true` if a mismatch was detected (for testing).\n */\nexport function logEndpointMismatch(\n modelId: string,\n path: string,\n): boolean {\n if (modelSupportsEndpoint(modelId, path)) return false\n\n const model = state.models?.data.find((m) => m.id === modelId)\n const supported = model?.supported_endpoints ?? []\n\n consola.error(\n `Model \"${modelId}\" does not support ${path}. `\n + `Supported endpoints: ${supported.join(\", \")}`,\n )\n return true\n}\n\n/**\n * Return model IDs that support the given endpoint.\n */\nexport function listModelsForEndpoint(path: string): string[] {\n const endpoint = ENDPOINT_ALIASES[path] ?? path\n const models = state.models?.data ?? []\n\n return models\n .filter((m) => {\n const supported = m.supported_endpoints\n if (!supported || supported.length === 0) return true\n return supported.includes(endpoint)\n })\n .map((m) => m.id)\n}\n","/**\n * Env-flag parsing for the Windows keep-awake feature. Pure +\n * unit-testable (no spawn, no platform branch — the platform gate lives\n * in `keepAwakeEnabled()`).\n */\n\nimport process from \"node:process\"\n\nimport { parseBoolEnv } from \"../exec\"\n\n/**\n * True unless the operator opted out via `GH_ROUTER_DISABLE_KEEP_AWAKE`.\n * Keep-awake is ON BY DEFAULT (the win32-only platform gate is applied\n * separately in `keepAwakeEnabled()`). Mirrors the colbert opt-out idiom\n * (`parseBoolEnv(...) !== true`) so on/off semantics don't drift.\n */\nexport function keepAwakeOptedIn(): boolean {\n return parseBoolEnv(process.env.GH_ROUTER_DISABLE_KEEP_AWAKE) !== true\n}\n\n/**\n * True iff the operator opted IN to keeping the DISPLAY awake too via\n * `GH_ROUTER_KEEP_DISPLAY_ON=1`. Default OFF: the machine stays awake\n * (`ES_SYSTEM_REQUIRED`) but the panel is allowed to sleep.\n */\nexport function keepDisplayOn(): boolean {\n return parseBoolEnv(process.env.GH_ROUTER_KEEP_DISPLAY_ON) === true\n}\n","/**\n * The persistent PowerShell helper that holds a Win32\n * `SetThreadExecutionState` assertion for the proxy's lifetime.\n *\n * `SetThreadExecutionState` is THREAD-scoped: a one-shot process that\n * sets it and exits releases the assertion immediately. So a long-lived\n * helper holds it on its own main thread and blocks on stdin; when the\n * proxy dies (clean exit, signal, SIGKILL/taskkill, OOM) the stdin pipe\n * closes, the helper hits EOF, clears the assertion, and exits — and\n * Windows releases the thread's assertion on process death regardless.\n * The helper therefore cannot outlive the proxy, so no orphan sweep is\n * needed (unlike colbert/worktrees, which leave on-disk artifacts).\n *\n * Best-effort: every failure path (no powershell, Constrained Language\n * Mode blocking `Add-Type`, spawn error) degrades to a clean no-op. We\n * NEVER attempt to install, enable, or bypass language-mode/WDAC policy.\n */\n\nimport { spawn } from \"node:child_process\"\n\nimport { killManagedTree, resolveExecutable } from \"../exec\"\n\nexport interface HelperHandle {\n child: ReturnType<typeof spawn>\n}\n\nexport interface SpawnHelperResult {\n /** null when powershell.exe couldn't be resolved or spawn threw. */\n handle: HelperHandle | null\n /**\n * Resolves `true` once the helper prints its `OK` readiness line\n * (the assertion took), or `false` on early child exit / timeout /\n * no-powershell (Constrained Language Mode blocks `Add-Type`, etc.).\n */\n ready: Promise<boolean>\n}\n\n// Win32 EXECUTION_STATE flags (winbase.h).\nconst ES_CONTINUOUS = 0x80000000\nconst ES_SYSTEM_REQUIRED = 0x00000001\nconst ES_DISPLAY_REQUIRED = 0x00000002\n\n/** Default time to wait for the helper's `OK` readiness line.\n *\n * Sized for the slowest LEGITIMATE path, not the typical one. The script's\n * `Add-Type -MemberDefinition` compiles a C# P/Invoke shim through csc.exe on\n * first use, and that compile happens BEFORE the `OK` line is printed. On a\n * cold machine (a fresh CI runner, a laptop that just booted, a host with\n * aggressive on-access AV scanning) it routinely takes well over five seconds.\n *\n * CORRECTION to the rationale this constant shipped with. An earlier version of\n * this comment (and the commit that raised the value) claimed a short timeout\n * made the user \"silently lose keep-awake\". That is wrong, and a cross-lab\n * reviewer caught it: `startKeepAwake` does nothing with `ready` but\n * `consola.debug` it (`index.ts:128`). The handle is retained and the child\n * keeps running, so the assertion is still set, just later than we observed it.\n *\n * The real cost of a tight value is therefore a LYING LOG, not a lost feature:\n * we report \"inactive\" for a helper that is about to work. That is still worth\n * fixing, because a false negative in a diagnostic is how you lose an afternoon\n * chasing a working feature. Waiting longer costs nothing either way, since the\n * readiness promise is awaited in the background and never blocks launch. */\nconst DEFAULT_READY_TIMEOUT_MS = 20_000\n\n/**\n * The execution-state flags to assert. Always `ES_CONTINUOUS |\n * ES_SYSTEM_REQUIRED` (machine stays awake); adds `ES_DISPLAY_REQUIRED`\n * (screen stays on) when `displayRequired`. `>>> 0` forces an unsigned\n * 32-bit value so the hex literal handed to PowerShell is positive.\n */\nexport function executionStateFlags(displayRequired: boolean): number {\n let flags = ES_CONTINUOUS | ES_SYSTEM_REQUIRED\n if (displayRequired) flags |= ES_DISPLAY_REQUIRED\n return flags >>> 0\n}\n\n/** Format a uint32 as a PowerShell `[uint32]<decimal>` literal.\n *\n * Decimal, NOT hex: in Windows PowerShell a hex literal like `0x80000001`\n * parses as a *negative* Int32 (`-2147483647`) and fails to convert to\n * the `uint` parameter (\"Value was either too large or too small for a\n * UInt32\"). A decimal literal over Int32.MaxValue auto-promotes to a\n * positive Int64, and the explicit `[uint32]` cast then fits. Verified\n * against a real win32 host before shipping. */\nfunction psUint32(n: number): string {\n return `[uint32]${n >>> 0}`\n}\n\n/**\n * Build the PowerShell script the persistent helper runs. PURE — the\n * flag value is our own constant templated as a numeric literal, so\n * there is no injection surface. The script:\n * 1. P/Invokes `SetThreadExecutionState` with the requested flags.\n * 2. Prints `OK` once the assertion succeeds (the readiness signal;\n * no `OK` => `Add-Type` was CLM-blocked or the call returned 0).\n * 3. Blocks reading stdin so it self-exits on parent death (pipe EOF).\n * 4. Clears the assertion (`ES_CONTINUOUS` only) on the way out.\n *\n * The C# member-definition is a PowerShell SINGLE-quoted string so its\n * embedded `\"kernel32.dll\"` double-quotes need no escaping.\n */\nexport function buildKeepAwakeScript(displayRequired: boolean): string {\n const assert = psUint32(executionStateFlags(displayRequired))\n const clear = psUint32(ES_CONTINUOUS)\n return [\n `Add-Type -Name P -Namespace W -MemberDefinition '[System.Runtime.InteropServices.DllImport(\"kernel32.dll\")] public static extern uint SetThreadExecutionState(uint e);'`,\n `if ([W.P]::SetThreadExecutionState(${assert}) -ne 0) { [Console]::Out.WriteLine('OK'); [Console]::Out.Flush() }`,\n `while ($null -ne [Console]::In.ReadLine()) {}`,\n `[void][W.P]::SetThreadExecutionState(${clear})`,\n ].join(\"\\n\")\n}\n\n/** The argv passed to powershell.exe (excluding the executable itself). */\nexport function buildHelperArgs(displayRequired: boolean): string[] {\n return [\n \"-NoProfile\",\n \"-NonInteractive\",\n \"-Command\",\n buildKeepAwakeScript(displayRequired),\n ]\n}\n\n/**\n * Spawn the persistent helper. Returns a null handle (and `ready` →\n * `false`) when powershell.exe can't be resolved or spawn throws — both\n * clean no-op degradations. The helper's stdout is piped only to detect\n * the `OK` readiness line; stderr is ignored.\n */\nexport function spawnHelper(opts: {\n displayRequired: boolean\n readyTimeoutMs?: number\n}): SpawnHelperResult {\n const ps = resolveExecutable(\"powershell.exe\")\n if (!ps) return { handle: null, ready: Promise.resolve(false) }\n\n let child: ReturnType<typeof spawn>\n try {\n child = spawn(ps, buildHelperArgs(opts.displayRequired), {\n stdio: [\"pipe\", \"pipe\", \"ignore\"],\n windowsHide: true,\n shell: false,\n })\n } catch {\n return { handle: null, ready: Promise.resolve(false) }\n }\n // A spawn 'error' (e.g. ENOENT slipping past resolveExecutable) must\n // never surface as an unhandled error event.\n child.on(\"error\", () => {})\n\n const handle: HelperHandle = { child }\n const ready = new Promise<boolean>((resolve) => {\n let settled = false\n let buf = \"\"\n const done = (v: boolean): void => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n resolve(v)\n }\n const timer = setTimeout(\n () => done(false),\n opts.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS,\n )\n timer.unref?.()\n\n child.stdout?.on(\"data\", (c: Buffer) => {\n // Inert + bounded after settle: the helper only ever prints the\n // single `OK` line, so cap the readiness buffer defensively and stop\n // appending once resolved (the listener stays attached for the\n // child's life but does nothing further).\n if (settled || buf.length > 256) return\n buf += c.toString(\"utf8\")\n if (buf.includes(\"OK\")) done(true)\n })\n child.stdout?.on(\"error\", () => {})\n // Early exit before OK => the assertion never took (CLM/failure).\n child.once(\"exit\", () => done(false))\n child.once(\"error\", () => done(false))\n })\n return { handle, ready }\n}\n\n/**\n * Release the assertion: close the helper's stdin (→ pipe EOF → the\n * helper clears `ES_*` and exits) then `taskkill /T /F` as a\n * belt-and-suspenders reap. Windows also releases the assertion on the\n * helper's process death regardless. Best-effort; never throws.\n */\nexport function killHelper(handle: HelperHandle): void {\n const { child } = handle\n try {\n child.stdin?.end()\n } catch {\n // stdin already closed\n }\n try {\n killManagedTree(child)\n } catch {\n // already gone\n }\n}\n","/**\n * Windows keep-awake — public entry points.\n *\n * `startKeepAwake()` is the fire-and-forget call the `start` / `claude` /\n * `codex` launchers invoke after `setupAndServe` (alongside\n * `provisionAndIndexColbert()` / `runSelfUpdate()`). On Windows, by\n * default, it spawns a persistent PowerShell helper that holds a\n * `SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED)`\n * assertion so the machine doesn't idle-sleep mid-session, and registers\n * SIGINT/SIGTERM/exit handlers to release it.\n *\n * Best-effort and model-agnostic: non-win32 is a total no-op; any\n * failure (no powershell, Constrained Language Mode blocking `Add-Type`)\n * degrades to a clean debug-logged no-op. We NEVER install, enable, or\n * bypass language-mode/WDAC policy, and never block or crash launch.\n *\n * Crash safety: the helper blocks on stdin, so if the proxy is hard-\n * killed the pipe closes, the helper hits EOF and exits, and Windows\n * releases the assertion on process death — no orphan is possible, so no\n * boot-time sweep is needed.\n */\n\nimport process from \"node:process\"\n\nimport consola from \"consola\"\n\nimport { keepAwakeOptedIn, keepDisplayOn } from \"./flags\"\nimport { type HelperHandle, killHelper, spawnHelper } from \"./helper\"\n\nexport { keepAwakeOptedIn, keepDisplayOn } from \"./flags\"\n\n/**\n * True iff keep-awake should run THIS launch: win32 AND not opted out.\n * Non-win32 short-circuits before anything else (no spawn, no flags read\n * beyond the opt-out, no handler registration). `platform` is injectable\n * for tests; production callers use the default `process.platform`.\n */\nexport function keepAwakeEnabled(\n platform: NodeJS.Platform = process.platform,\n): boolean {\n return platform === \"win32\" && keepAwakeOptedIn()\n}\n\nlet _handle: HelperHandle | null = null\nlet _started = false\n\n/** Synchronously release the assertion + drop the handle. Idempotent.\n * Also clears the `_started` latch so a transient failure never\n * permanently disables a later start. */\nfunction releaseSync(): void {\n const h = _handle\n _handle = null\n _started = false\n if (h) {\n try {\n killHelper(h)\n } catch {\n // best-effort\n }\n }\n}\n\n// ---------------------------------------------------------------------\n// Signal handlers (mirror colbert/worker-agent re-raise pattern)\n// ---------------------------------------------------------------------\n\nlet _registered = false\nlet _exitHandler: (() => void) | null = null\nlet _sigintHandler: (() => void) | null = null\nlet _sigtermHandler: (() => void) | null = null\n\n/**\n * Wire SIGINT/SIGTERM/exit handlers that release the assertion.\n * Idempotent. The signal handlers re-raise after releasing (remove self\n * + `process.kill(self)`) so Node's default terminate-on-signal is\n * restored — otherwise merely attaching a listener cancels the default\n * and Ctrl-C would clean but not exit. This is load-bearing for the\n * `start` subcommand, which has no `launchChild`/`onShutdown` of its own.\n */\nfunction registerExitHandlers(): void {\n if (_registered) return\n _registered = true\n // On `exit` the event loop is dead, so killHelper's async `taskkill`\n // can't run — but that's fine: when the proxy process dies the OS closes\n // the helper's stdin pipe, the helper hits EOF and exits, and Windows\n // releases the assertion on its death. The signal handlers (event loop\n // still alive) DO run the taskkill belt-and-suspenders. Matches the\n // colbert lifecycle's established pattern.\n _exitHandler = () => releaseSync()\n _sigintHandler = () => {\n releaseSync()\n if (_sigintHandler) process.off(\"SIGINT\", _sigintHandler)\n process.kill(process.pid, \"SIGINT\")\n }\n _sigtermHandler = () => {\n releaseSync()\n if (_sigtermHandler) process.off(\"SIGTERM\", _sigtermHandler)\n process.kill(process.pid, \"SIGTERM\")\n }\n process.on(\"SIGINT\", _sigintHandler)\n process.on(\"SIGTERM\", _sigtermHandler)\n process.on(\"exit\", _exitHandler)\n}\n\n/**\n * Start keeping the machine awake. Synchronous, fire-and-forget,\n * idempotent within a run. No-op off win32 or when opted out. Never\n * throws.\n */\nexport function startKeepAwake(): void {\n if (!keepAwakeEnabled()) return\n if (_started) return\n _started = true\n try {\n const { handle, ready } = spawnHelper({ displayRequired: keepDisplayOn() })\n if (!handle) {\n _started = false // nothing spawned — allow a later retry\n consola.debug(\"keep-awake: inactive (powershell.exe not resolvable)\")\n return\n }\n _handle = handle\n // Keep `_handle` honest if the helper dies on its own (e.g. CLM made\n // Add-Type throw): drop the reference so a later stop/check is accurate.\n handle.child.once(\"exit\", () => {\n if (_handle === handle) _handle = null\n })\n registerExitHandlers()\n void ready.then((ok) => {\n consola.debug(\n ok\n ? \"keep-awake: holding SetThreadExecutionState assertion (system sleep prevented)\"\n : \"keep-awake: inactive (helper did not confirm — Constrained Language Mode or PowerShell unavailable)\",\n )\n })\n } catch (err) {\n _started = false\n _handle = null\n consola.debug(\"keep-awake: failed to start (continuing):\", err)\n }\n}\n\n/**\n * Release the assertion / reap the helper. Idempotent; safe to `await`\n * from a subcommand's `onShutdown` chain. Never throws.\n */\nexport async function stopKeepAwake(): Promise<void> {\n releaseSync()\n}\n\n/** Test-only: the current helper child PID, or undefined if no helper is\n * active. Lets tests assert \"started once\" (same pid) and \"stop released\"\n * (undefined) instead of only \"did not throw\". */\nexport function __keepAwakeChildPidForTests(): number | undefined {\n return _handle?.child.pid\n}\n\n/** Test-only: reset module state + unregister handlers. */\nexport function __resetKeepAwakeForTests(): void {\n releaseSync()\n _started = false\n if (_sigintHandler) {\n process.off(\"SIGINT\", _sigintHandler)\n _sigintHandler = null\n }\n if (_sigtermHandler) {\n process.off(\"SIGTERM\", _sigtermHandler)\n _sigtermHandler = null\n }\n if (_exitHandler) {\n process.off(\"exit\", _exitHandler)\n _exitHandler = null\n }\n _registered = false\n}\n","import { spawn as spawnChild } from \"node:child_process\"\nimport { existsSync } from \"node:fs\"\nimport path from \"node:path\"\n\nimport consola from \"consola\"\n\n/**\n * Opt-in auto-spawn of the first-mate scheduler daemon as a SEPARATE process\n * (a hung tick must not starve the proxy event loop).\n *\n * DEFAULT OFF — gated by GH_ROUTER_FM_DAEMON === \"1\" (explicit opt-in). The\n * durable [fm-heartbeat] cron is the DEFAULT driver and the proven path; the\n * daemon is experimental and NOT yet safe as the default because two hardening\n * items remain (a verifier-stall wall-clock escalation, and an atomic-claim\n * lock in durable-store) — flip the default only once those land.\n *\n * Requirements + honest boundaries:\n * - The daemon entry is `scripts/first-mate-daemon.ts` (a TS source file run via\n * `bun`); it is NOT in the published dist tarball, so auto-spawn only fires\n * from a source checkout with `bun` available. If the script is absent we\n * no-op (never a false \"spawned\" log).\n * - Spawn failures NEVER crash the proxy: an async ENOENT (`bun` not on PATH)\n * arrives as an `'error'` EVENT, not a sync throw, so we attach an `'error'`\n * listener (without it the emitter re-throws → uncaughtException → exit(1)).\n * - The returned handle MUST be killed by the caller on shutdown (no `detached`);\n * an orphaned drive-primary daemon would keep merging PRs after the proxy is\n * gone. The parent ALSO holds the child's stdin write end (`stdio[0]===\"pipe\"`)\n * so it can EOF the child for a GRACEFUL stop (lease + pidfile released\n * immediately, not by expiry) — the cross-platform teardown trigger, since an\n * external SIGTERM on Windows is a hard kill the child can't observe. `kill()`\n * stays the hard backstop so a wedged child is never orphaned (see\n * `wireDaemonTeardown`).\n * - It owns the deterministic drive loop only; live judgments still wake the\n * lead via the heartbeat (no server->lead push).\n */\n\nexport function shouldAutoSpawnDaemon(\n env: NodeJS.ProcessEnv,\n agentsEnabled: boolean,\n): boolean {\n if (!agentsEnabled) return false // nothing to drive without missions/agents\n return env.GH_ROUTER_FM_DAEMON === \"1\" // OPT-IN; default OFF (heartbeat drives)\n}\n\nexport interface DaemonHandle {\n pid: number | undefined\n kill: () => void\n /**\n * Close the child's stdin write end (EOF). The daemon observes this as a\n * cross-platform graceful-shutdown trigger and releases its lease/pidfile\n * cleanly. Best-effort + non-throwing (a missing/closed stdin is a no-op).\n */\n endStdin: () => void\n}\n\n/** Options an injected spawner receives (so tests can assert the stdio shape). */\nexport interface DaemonSpawnOptions {\n env: NodeJS.ProcessEnv\n /** stdin MUST be \"pipe\" so the parent can EOF the child; 1/2 stay \"ignore\". */\n stdio: Array<\"pipe\" | \"ignore\" | \"inherit\">\n}\n\n/** What a spawner returns; `endStdin` is optional (defaulted to a no-op). */\nexport interface SpawnedChild {\n pid?: number\n kill: () => void\n endStdin?: () => void\n}\n\n/**\n * The minimal `child_process.spawn` surface {@link nodeDaemonSpawn} needs. A\n * narrow interface (not `typeof spawnChild`) so a test can inject a fake child\n * whose `kill` records the signal — the only way to assert the SIGKILL backstop,\n * since the injected `spawn` in {@link maybeSpawnDaemon} replaces `kill` wholesale.\n */\nexport type LowLevelSpawn = (\n command: string,\n args: string[],\n options: { env: NodeJS.ProcessEnv; stdio: Array<\"pipe\" | \"ignore\" | \"inherit\"> },\n) => {\n pid?: number\n on(event: \"error\", listener: (err: Error) => void): unknown\n kill(signal?: NodeJS.Signals | number): boolean\n stdin?: { end(): void } | null\n}\n\n/**\n * The real (non-injected) spawner: node:child_process (not the Bun runtime's spawn) so the\n * bundled dist/main.js stays node-loadable. No `detached` — the caller kills\n * this on shutdown. stdin is \"pipe\" (parent holds the write end for a graceful\n * EOF stop); stdout/stderr stay \"ignore\".\n */\nexport function nodeDaemonSpawn(\n cmd: string[],\n spawnOpts: DaemonSpawnOptions,\n spawnImpl: LowLevelSpawn = spawnChild,\n): SpawnedChild {\n const proc = spawnImpl(cmd[0]!, cmd.slice(1), {\n env: spawnOpts.env,\n stdio: spawnOpts.stdio,\n })\n // Finding 1: ENOENT (e.g. `bun` not on PATH) is delivered ASYNC as an\n // 'error' event. Without a listener the emitter re-throws on a later tick →\n // uncaughtException → the proxy exits(1). Swallow it.\n proc.on(\"error\", (err) =>\n consola.debug(\"first-mate daemon spawn error (ignored):\", err),\n )\n return {\n pid: proc.pid,\n // Finding 3: SIGKILL, not the default SIGTERM. This is the HARD backstop\n // that only runs AFTER endStdin()'s graceful EOF already fired the child's\n // shutdown trigger — and the child's graceful-shutdown handler TRAPS SIGTERM\n // and no-ops it. So a catchable SIGTERM here could NOT force-kill a wedged\n // child on POSIX → an orphaned drive-primary daemon that keeps merging PRs.\n // SIGKILL is uncatchable, restoring the \"wedged child is never orphaned\"\n // guarantee cross-platform. (On Windows any signal maps to an unconditional\n // TerminateProcess, so it was already safe there.)\n kill: () => void proc.kill(\"SIGKILL\"),\n // EOF the child's stdin → graceful shutdown. Best-effort: a closed or\n // never-opened stdin must not throw during teardown.\n endStdin: () => {\n try {\n proc.stdin?.end()\n } catch {\n /* best-effort */\n }\n },\n }\n}\n\n/**\n * Spawn the daemon child if the opt-in gate passes AND the daemon script is\n * present; else return undefined. Never throws, and never lets an async spawn\n * error crash bootstrap.\n */\nexport function maybeSpawnDaemon(opts: {\n env?: NodeJS.ProcessEnv\n agentsEnabled: boolean\n repoRoot?: string\n spawn?: (cmd: string[], spawnOpts: DaemonSpawnOptions) => SpawnedChild\n}): DaemonHandle | undefined {\n const env = opts.env ?? process.env\n if (!shouldAutoSpawnDaemon(env, opts.agentsEnabled)) return undefined\n const script = path.join(opts.repoRoot ?? process.cwd(), \"scripts/first-mate-daemon.ts\")\n // Finding 6: in a dist/global install the .ts entry isn't present — no-op\n // rather than spawn a doomed `bun <missing.ts>` and log a false success.\n if (opts.spawn === undefined && !existsSync(script)) {\n consola.debug(`first-mate daemon entry not found (${script}); auto-spawn skipped.`)\n return undefined\n }\n try {\n const spawn = opts.spawn ?? ((cmd, spawnOpts): SpawnedChild => nodeDaemonSpawn(cmd, spawnOpts))\n const child = spawn([\"bun\", script], {\n env,\n stdio: [\"pipe\", \"ignore\", \"ignore\"],\n })\n return {\n pid: child.pid,\n kill: child.kill,\n endStdin: child.endStdin ?? (() => {}),\n }\n } catch {\n return undefined // never let a spawn failure crash bootstrap\n }\n}\n\n/**\n * Wire the proxy's teardown to shut the daemon child down GRACEFULLY, then hard\n * kill as a backstop. Ordering (per teardown path):\n * 1. `endStdin()` — EOF the child so it releases its lease/pidfile cleanly (the\n * cross-platform trigger; on Windows an external SIGTERM would never run the\n * child's handler, so this EOF is the ONLY graceful path there).\n * 2. `kill()` — hard backstop so a wedged child is never orphaned (a prior\n * review blocker: an orphaned drive-primary daemon keeps merging PRs).\n *\n * On SIGINT/SIGTERM the kill is deferred by a short, NON-BLOCKING, unref'd grace\n * window (proxy exit is never delayed for it). On `'exit'` — where timers cannot\n * run — we EOF then kill synchronously as a last resort. All steps are\n * once-guarded and non-throwing.\n */\nexport function wireDaemonTeardown(\n handle: DaemonHandle,\n opts: {\n proc?: Pick<NodeJS.Process, \"once\">\n graceMs?: number\n setTimer?: (fn: () => void, ms: number) => { unref?: () => void }\n } = {},\n): void {\n const proc = opts.proc ?? process\n const graceMs = opts.graceMs ?? 300\n const setTimer = opts.setTimer ?? ((fn, ms) => setTimeout(fn, ms))\n\n let killed = false\n const kill = (): void => {\n if (killed) return\n killed = true\n try {\n handle.kill()\n } catch {\n /* best-effort */\n }\n }\n let ended = false\n const endStdin = (): void => {\n if (ended) return\n ended = true\n try {\n handle.endStdin()\n } catch {\n /* best-effort: a missing/closed stdin must not throw during teardown */\n }\n }\n\n const onSignal = (): void => {\n endStdin() // 1) graceful EOF first\n const t = setTimer(kill, graceMs) // 2) hard backstop, non-blocking\n if (t && typeof t.unref === \"function\") t.unref()\n }\n proc.once(\"SIGINT\", onSignal)\n proc.once(\"SIGTERM\", onSignal)\n // 'exit' handlers cannot schedule timers — EOF then kill synchronously.\n proc.once(\"exit\", () => {\n endStdin()\n kill()\n })\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 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 by user\",\n Response.json({ message: \"Request rejected by user\" }, { 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\n// Cap on how long a single request will wait in the rate-limit serialization\n// queue. Prevents an unbounded backlog from holding the proxy if the head of\n// the queue is in a long sleep. 5s is generous enough that normal queueing\n// (microseconds) never trips it.\nconst RATE_LIMIT_QUEUE_TIMEOUT_MS = 5000\n\n// Single-flight chain that serializes all rate-limit checks across the\n// proxy. Without this, two concurrent requests can both read the timestamp\n// before either writes — both proceed when only one should wait. The chain\n// adds microseconds of latency per request in the no-rate-limit case and\n// correctly serializes the wait when the limit fires.\nlet rateLimitChain: Promise<void> = Promise.resolve()\n\nexport async function checkRateLimit(state: State) {\n if (state.rateLimitSeconds === undefined) return\n\n // Ticket carried by `myTurn` so a queue-timeout can flag it as cancelled\n // before doCheck() ever gets to sleep or write to state.lastRequestTimestamp.\n // Without this, a request that already returned 429 to the caller would\n // STILL run later inside the chain — sleep, then bump the shared timestamp\n // — penalising subsequent legitimate requests for a request that was\n // never actually serviced.\n const ticket = { aborted: false }\n\n const myTurn = rateLimitChain.then(() => doCheck(state, ticket))\n rateLimitChain = myTurn.catch(() => {\n // Errors don't break the chain — the next caller starts fresh.\n })\n\n return Promise.race([\n myTurn,\n sleep(RATE_LIMIT_QUEUE_TIMEOUT_MS).then(() => {\n ticket.aborted = true\n throw new HTTPError(\n \"Rate limit queue wait exceeded\",\n Response.json(\n {\n type: \"error\",\n error: {\n type: \"rate_limit_error\",\n message: `Rate limit queue exceeded ${RATE_LIMIT_QUEUE_TIMEOUT_MS}ms; try again`,\n },\n },\n { status: 429 },\n ),\n )\n }),\n ])\n}\n\nasync function doCheck(\n state: State,\n ticket: { aborted: boolean },\n): Promise<void> {\n if (state.rateLimitSeconds === undefined) return\n if (ticket.aborted) 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 // Re-check after the sleep — if the caller queue-timed-out while we were\n // sleeping, do NOT bump the shared timestamp (that would penalise the next\n // legitimate request for one that was already 429'd).\n if (ticket.aborted) return\n state.lastRequestTimestamp = Date.now()\n consola.info(\"Rate limit wait completed, proceeding with request\")\n}\n","import consola from \"consola\"\n\nimport type { Model } from \"~/services/copilot/get-models\"\n\nexport interface RequestLogInfo {\n method: string\n path: string\n model?: string\n resolvedModel?: string\n inputTokens?: number\n outputTokens?: number\n status?: number\n streaming?: boolean\n errorBody?: string\n}\n\n/**\n * Format a number with K/M suffix for compact display.\n */\nfunction formatTokens(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`\n return String(n)\n}\n\n/**\n * Build a context window summary: \"in:1.2K out:50 ctx:1.2K/1M (0.1%)\"\n */\nfunction formatTokenInfo(\n inputTokens: number | undefined,\n outputTokens: number | undefined,\n model: Model | undefined,\n): string | undefined {\n if (inputTokens === undefined) return undefined\n\n const parts: Array<string> = []\n const maxPrompt = model?.capabilities?.limits?.max_prompt_tokens\n\n if (maxPrompt) {\n const pct = ((inputTokens / maxPrompt) * 100).toFixed(1)\n parts.push(`in:${formatTokens(inputTokens)}/${formatTokens(maxPrompt)} (${pct}%)`)\n } else {\n parts.push(`in:${formatTokens(inputTokens)}`)\n }\n\n if (outputTokens !== undefined) {\n parts.push(`out:${formatTokens(outputTokens)}`)\n }\n\n return parts.join(\" \")\n}\n\n/**\n * Print a single summary line for a completed request.\n *\n * Examples:\n * POST /v1/messages claude-opus-4.6-1m in:1.2K/1M (0.1%) out:50 200 2.3s\n * POST /v1/messages claude-opus-4-6→claude-opus-4.6-1m in:743/1M (0.1%) 200 198ms\n * POST /v1/chat/completions claude-sonnet-4 in:15 out:16 200 2.1s stream\n */\nexport function logRequest(\n info: RequestLogInfo,\n model: Model | undefined,\n startTime: number,\n): void {\n const parts: Array<string> = []\n\n parts.push(`${info.method} ${info.path}`)\n\n // Model (show resolution arrow if remapped)\n if (info.resolvedModel && info.resolvedModel !== info.model) {\n parts.push(`${info.model}→${info.resolvedModel}`)\n } else if (info.resolvedModel ?? info.model) {\n parts.push((info.resolvedModel ?? info.model)!)\n }\n\n // Token info with context window fill\n const tokenInfo = formatTokenInfo(info.inputTokens, info.outputTokens, model)\n if (tokenInfo) {\n parts.push(tokenInfo)\n }\n\n // Status\n if (info.status !== undefined) {\n parts.push(String(info.status))\n }\n\n // Duration + streaming flag\n const elapsed = Date.now() - startTime\n const duration =\n elapsed >= 1000 ? `${(elapsed / 1000).toFixed(1)}s` : `${elapsed}ms`\n parts.push(info.streaming ? `${duration} stream` : duration)\n\n const line = parts.join(\" \")\n\n if (detectCapabilityMismatch(info, model)) {\n consola.error(`[MISMATCH] ${line}`)\n } else {\n consola.info(line)\n }\n}\n\n/**\n * Detect when the API rejects a request for token/context reasons\n * that contradict what the /models endpoint reported.\n */\nfunction detectCapabilityMismatch(\n info: RequestLogInfo,\n model: Model | undefined,\n): boolean {\n if (!info.errorBody || !model) return false\n if (!info.status || info.status < 400) return false\n\n const err = info.errorBody.toLowerCase()\n return (\n err.includes(\"token\") ||\n err.includes(\"context\") ||\n err.includes(\"too long\") ||\n err.includes(\"max_tokens\") ||\n err.includes(\"prompt is too long\")\n )\n}\n\n/**\n * Opt-in instrumentation for the discovery loop (Phase 0.5 of the\n * long-horizon plan). When `GH_ROUTER_LOG_FIELDS=1` is set in the\n * environment, emits a single structured `[fields]` log line per request\n * recording the top-level body keys, per-tool field keys, and\n * anthropic-beta header values seen.\n *\n * Default-off (zero overhead). The companion\n * `scripts/discover-new-fields.sh` greps these lines, aggregates unique\n * field names per request shape, and diffs against the known-fields\n * list in `docs/copilot-compat-matrix.md` — surfacing anything new\n * that should get a probe row added.\n *\n * Format (single line, deterministic-ish key order):\n * [fields] path=<P> body_keys=<csv> tool_field_keys=<csv> beta_values=<csv> agent=<id|->\n *\n * Where:\n * - `body_keys` is the alphabetical union of top-level keys in the\n * request body\n * - `tool_field_keys` is the alphabetical union of all keys appearing\n * across every entry of `body.tools[]` (or empty)\n * - `beta_values` is the comma-split anthropic-beta header value as\n * received (NOT filtered) — captures what the client sends, not\n * what we forward\n * - `agent` is Claude Code's `x-claude-code-agent-id` header, or `-` for\n * main-loop traffic. Without it a capture cannot tell a subagent request\n * from a main-loop one, which is exactly the question you need answered\n * when reasoning about per-agent request shape (does a subagent send a\n * `thinking` block?). The header value is opaque to us and is logged\n * verbatim.\n */\nexport function logRequestFields(opts: {\n path: string\n body: unknown\n betaHeader?: string\n agentId?: string\n}): void {\n if (process.env.GH_ROUTER_LOG_FIELDS !== \"1\") return\n const bodyKeys = collectTopLevelKeys(opts.body)\n const toolFieldKeys = collectToolFieldKeys(opts.body)\n const betaValues = (opts.betaHeader ?? \"\")\n .split(\",\")\n .map((v) => v.trim())\n .filter(Boolean)\n consola.info(\n `[fields] path=${opts.path}`\n + ` body_keys=${bodyKeys.join(\",\")}`\n + ` tool_field_keys=${toolFieldKeys.join(\",\")}`\n + ` beta_values=${betaValues.join(\",\")}`\n + ` agent=${opts.agentId && opts.agentId.length > 0 ? opts.agentId : \"-\"}`,\n )\n}\n\nfunction collectTopLevelKeys(body: unknown): Array<string> {\n if (!body || typeof body !== \"object\" || Array.isArray(body)) return []\n return Object.keys(body as Record<string, unknown>).sort()\n}\n\nfunction collectToolFieldKeys(body: unknown): Array<string> {\n if (!body || typeof body !== \"object\") return []\n const tools = (body as Record<string, unknown>).tools\n if (!Array.isArray(tools)) return []\n const seen = new Set<string>()\n for (const tool of tools) {\n if (tool && typeof tool === \"object\" && !Array.isArray(tool)) {\n for (const k of Object.keys(tool as Record<string, unknown>)) {\n seen.add(k)\n }\n }\n }\n return [...seen].sort()\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { HTTPError } from \"~/lib/error\"\nimport { logEndpointMismatch } from \"~/lib/model-validation\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { logRequest } from \"~/lib/request-log\"\nimport { UPSTREAM_INACTIVITY_TIMEOUT_MS } from \"~/lib/port\"\nimport { state } from \"~/lib/state\"\nimport { buildOpenAIErrorEvent, isControllerClosedError, logStreamError, readIteratorWithTimeout } from \"~/lib/stream-relay\"\nimport { getTokenCount } from \"~/lib/tokenizer\"\nimport { isNullish, resolveModel } from \"~/lib/utils\"\nimport {\n createChatCompletions,\n type ChatCompletionResponse,\n type ChatCompletionsPayload,\n type Message,\n} from \"~/services/copilot/create-chat-completions\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\ninterface UpstreamSSEEvent {\n event?: string\n data?: string\n id?: string | number\n}\n\nconst ENCODER = new TextEncoder()\n\nfunction formatSSE(chunk: UpstreamSSEEvent): string {\n const parts: Array<string> = []\n if (chunk.event) parts.push(`event: ${chunk.event}`)\n if (chunk.data !== undefined) {\n for (const line of String(chunk.data).split(/\\r\\n|\\r|\\n/)) {\n parts.push(`data: ${line}`)\n }\n }\n if (chunk.id !== undefined) parts.push(`id: ${String(chunk.id)}`)\n return parts.join(\"\\n\") + \"\\n\\n\"\n}\n\nexport async function handleCompletion(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n let payload = await c.req.json<ChatCompletionsPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Request payload:\", JSON.stringify(payload).slice(-400))\n }\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n // Resolve model name (e.g. opus → opus-1m variant)\n const originalModel = payload.model\n const resolvedModel = resolveModel(payload.model)\n if (resolvedModel !== payload.model) {\n payload.model = resolvedModel\n }\n\n // Find the selected model\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n logEndpointMismatch(payload.model, \"/chat/completions\")\n\n // Calculate token count\n let inputTokens: number | undefined\n try {\n if (selectedModel) {\n const tokenCount = await getTokenCount(payload, selectedModel)\n inputTokens = tokenCount.input\n }\n } catch {\n // Token counting is best-effort\n }\n\n if (isNullish(payload.max_tokens)) {\n payload = {\n ...payload,\n max_tokens: selectedModel?.capabilities?.limits?.max_output_tokens,\n }\n if (debugEnabled) {\n consola.debug(\"Set max_tokens to:\", JSON.stringify(payload.max_tokens))\n }\n }\n\n // retryTransient: true — pre-first-byte retry; the body is consumed only\n // after the ok-check inside createChatCompletions, so a re-issue here\n // cannot duplicate streamed output.\n const response = await createChatCompletions(\n payload,\n selectedModel?.requestHeaders,\n undefined,\n true,\n ).catch(\n async (error: unknown) => {\n if (error instanceof HTTPError) {\n const errorBody = await error.response.clone().text().catch(() => \"\")\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: error.response.status,\n errorBody,\n },\n selectedModel,\n startTime,\n )\n }\n throw error\n },\n )\n const isStreaming = !isNonStreaming(response)\n\n // Extract output tokens from non-streaming response (no extra call)\n const outputTokens = !isStreaming\n ? (response as ChatCompletionResponse).usage?.completion_tokens\n : undefined\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n inputTokens,\n outputTokens,\n status: 200,\n streaming: isStreaming,\n },\n selectedModel,\n startTime,\n )\n\n if (!isStreaming) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n // Streaming: peek the first SSE event so pre-byte upstream errors surface\n // through the route's try/catch → forwardError as a clean JSON response,\n // and only mid-stream errors hit the manual ReadableStream's pull-error path.\n const iterator = (response as AsyncIterableIterator<UpstreamSSEEvent>)[\n Symbol.asyncIterator\n ]()\n const firstResult = await readIteratorWithTimeout(iterator, UPSTREAM_INACTIVITY_TIMEOUT_MS)\n if (firstResult.done) {\n consola.warn(\n `Upstream /chat/completions returned an empty stream at ${c.req.path}`,\n )\n }\n\n let pendingFirstChunk: UpstreamSSEEvent | undefined = firstResult.done\n ? undefined\n : firstResult.value\n let upstreamFinished = firstResult.done\n let consumerCancelled = false\n\n const safeClose = (controller: ReadableStreamDefaultController<Uint8Array>) => {\n try {\n controller.close()\n } catch {\n // already closed / errored\n }\n }\n const releaseUpstream = (reason?: unknown) => {\n if (typeof iterator.return === \"function\") {\n iterator.return(reason).catch(() => {\n // upstream may already be closed\n })\n }\n }\n const safeEnqueue = (\n controller: ReadableStreamDefaultController<Uint8Array>,\n bytes: Uint8Array,\n ): boolean => {\n try {\n controller.enqueue(bytes)\n return true\n } catch (e) {\n if (isControllerClosedError(e)) {\n consumerCancelled = true\n // The downstream cancel() callback may not fire if the controller\n // was closed by Bun's HTTP layer rather than an explicit consumer\n // .cancel() — release the upstream iterator here so the upstream\n // socket does not leak.\n releaseUpstream(e)\n return false\n }\n throw e\n }\n }\n\n return new Response(\n new ReadableStream<Uint8Array>({\n async pull(controller) {\n if (consumerCancelled || upstreamFinished) {\n safeClose(controller)\n return\n }\n if (pendingFirstChunk !== undefined) {\n const chunk = pendingFirstChunk\n pendingFirstChunk = undefined\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n safeEnqueue(controller, ENCODER.encode(formatSSE(chunk)))\n return\n }\n try {\n const result = await readIteratorWithTimeout(iterator, UPSTREAM_INACTIVITY_TIMEOUT_MS)\n if (consumerCancelled) {\n safeClose(controller)\n return\n }\n if (result.done) {\n upstreamFinished = true\n safeClose(controller)\n return\n }\n // Defensive: an upstream iterator that yields `{done:false, value:undefined}`\n // would crash formatSSE() below. Skip silently and pull again on\n // the next consumer demand. Real upstream iterators never emit\n // this shape, but a misbehaving / proxied iterator might.\n if (result.value === undefined || result.value === null) return\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(result.value))\n }\n safeEnqueue(controller, ENCODER.encode(formatSSE(result.value)))\n } catch (error) {\n upstreamFinished = true\n if (consumerCancelled) {\n // Consumer-cancelled mid-pull, not an upstream failure. Close\n // so the consumer's read settles cleanly. Also release the\n // upstream iterator — the cancel() callback may not have\n // fired if the controller was closed by Bun's HTTP layer.\n //\n // We deliberately do NOT call isControllerClosedError(error)\n // on iterator-side errors here — the helper matches substrings\n // like \"stream is closed\" which can appear in real upstream\n // errors, and treating them as consumer-cancel would silently\n // suppress the OpenAI-shape error frame the consumer needs.\n releaseUpstream(error)\n safeClose(controller)\n return\n }\n const { errName, errMessage } = logStreamError(c.req.path, error)\n safeEnqueue(\n controller,\n ENCODER.encode(buildOpenAIErrorEvent(errName, errMessage)),\n )\n // We've decided this stream is done — release the upstream\n // iterator since the cancel() callback won't fire on a\n // server-initiated close.\n releaseUpstream(error)\n safeClose(controller)\n }\n },\n cancel() {\n consumerCancelled = true\n upstreamFinished = true\n releaseUpstream()\n },\n }),\n {\n status: 200,\n headers: {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n \"transfer-encoding\": \"chunked\",\n connection: \"keep-alive\",\n },\n },\n )\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse => Object.hasOwn(response, \"choices\")\n\nasync function injectWebSearchIfNeeded(\n payload: ChatCompletionsPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some(\n (t) =>\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\",\n )\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (tool call results)\n const hasToolResult = payload.messages.some((msg) => msg.role === \"tool\")\n const query = hasToolResult ? undefined : extractUserQuery(payload.messages)\n\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n // Prepend to existing system message or inject a new one\n const systemMsg = payload.messages.find((msg) => msg.role === \"system\")\n if (systemMsg) {\n const existingContent =\n typeof systemMsg.content === \"string\" ? systemMsg.content\n : Array.isArray(systemMsg.content) ?\n systemMsg.content\n .filter((p) => p.type === \"text\")\n .map((p) => (\"text\" in p ? p.text : \"\"))\n .join(\"\\n\")\n : \"\"\n systemMsg.content = `${searchContext}\\n\\n${existingContent}`\n } else {\n payload.messages.unshift({\n role: \"system\",\n content: searchContext,\n })\n }\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Remove web_search from tools before forwarding\n payload.tools = payload.tools?.filter(\n (t) =>\n !(\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\"\n ),\n ) as typeof payload.tools\n if (payload.tools?.length === 0) {\n payload.tools = undefined\n }\n if (!payload.tools) {\n payload.tool_choice = undefined\n } else if (\n payload.tool_choice\n && typeof payload.tool_choice === \"object\"\n && \"type\" in payload.tool_choice\n && payload.tool_choice.type === \"function\"\n ) {\n const toolChoiceName = payload.tool_choice.function?.name\n if (\n toolChoiceName\n && !payload.tools.some((tool) => tool.function.name === toolChoiceName)\n ) {\n payload.tool_choice = undefined\n }\n }\n}\n\nfunction extractUserQuery(messages: Array<Message>): string | undefined {\n // Find the last user message\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") return msg.content\n if (Array.isArray(msg.content)) {\n const text = msg.content.find((p) => p.type === \"text\")\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\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 { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\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 fetch(`${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 { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleMcpDelete, handleMcpPost } from \"./handler\"\n\nexport const mcpRoutes = new Hono()\n\n// Unscoped union — full tool surface, retained for BYO `start` / `codex`\n// clients that point a single MCP server at `/mcp`.\nmcpRoutes.post(\"/\", async (c) => {\n try {\n return await handleMcpPost(c, \"all\")\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n\n// Scoped endpoints — `/mcp/<group>` serves ONLY that group's tools. The\n// `claude` subcommand registers one `mcpServers` entry per group pointing\n// here so the model sees `mcp__<group>__<tool>`. The raw `:group` is passed\n// through; `handleMcpPost` validates it AFTER auth (so an unauthenticated\n// probe can't enumerate valid groups) and returns 404 for an unknown one.\nmcpRoutes.post(\"/:group\", async (c) => {\n try {\n return await handleMcpPost(c, c.req.param(\"group\"))\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n\nmcpRoutes.delete(\"/\", (c) => {\n try {\n return handleMcpDelete(c)\n } catch {\n return c.body(null, 500)\n }\n})\n\n// `handleMcpDelete` is session-teardown only (scope-agnostic); accept the\n// `/mcp/<group>` form so a client that opened on a scoped URL can DELETE\n// the same path. Unknown group is harmless here (no-op teardown), so we\n// don't bother validating it.\nmcpRoutes.delete(\"/:group\", (c) => {\n try {\n return handleMcpDelete(c)\n } catch {\n return c.body(null, 500)\n }\n})\n","/**\n * Inbound /v1/messages body sanitizer.\n *\n * Today this only handles ADVISOR-related corruption — the\n * proxy-generated `server_tool_use{name:\"advisor\"}` and paired\n * `advisor_tool_result` blocks may travel through Claude Code's\n * persisted conversation state with a malformed `id`/`tool_use_id`\n * (e.g., a leftover `toolu_*` value from before the round-5 fix).\n * Every replay of that history through `/v1/messages` would 400 at\n * Copilot's spec validator without rewriting them on inbound. This\n * module performs the rewrite.\n *\n * **Out of scope** (deliberate, per gemini-critic round 6 — the \"ID\n * round-trip trap\"): generic `tool_use.id` and `tool_result.tool_use_id`\n * are stateful references between requests; rewriting them statelessly\n * would break Claude Code's client-side tool tracker. Only advisor\n * blocks are touched here, because both sides of an advisor pair\n * (`server_tool_use` + `advisor_tool_result`) are proxy-generated and\n * round-trip together in the same request body — so a per-request\n * deterministic transformation preserves pairing without cross-request\n * state.\n *\n * **Round-7 holistic fix**: Copilot rejects `server_tool_use{name:\n * \"advisor\"}` outright (spec validator says only `web_search`,\n * `tool_search_tool_regex`, `tool_search_tool_bm25` are allowed), so\n * fixing the id format alone isn't enough. The sanitizer also\n * **translates** historical advisor pairs to the\n * `tool_use{__anthropic_advisor}` + `tool_result` shape Copilot\n * accepts (per user direction \"Option C\"). Multi-turn split is\n * required because `tool_result` must appear in a `user` role per\n * Anthropic spec. The `__anthropic_advisor` tool definition is\n * re-injected into `tools[]` so the `tool_use.name` reference\n * resolves.\n */\nimport {\n ADVISOR_INTERNAL_TOOL_NAME,\n ADVISOR_TOOL_INSTRUCTIONS,\n} from \"~/services/advisor/advisor\"\n\ntype AnyRecord = Record<string, unknown>\n\n/**\n * Convert a `srvtoolu_*` id to the matching `toolu_*` id used in the\n * Copilot-replay shape (`tool_use.id` must match `^toolu_*$`). For\n * any other input shape, fall back to a synthesized `toolu_advisor_N`\n * id.\n */\nfunction toCopilotToolUseId(srvId: string, fallbackIndex: number): string {\n if (srvId.startsWith(\"srvtoolu_\")) {\n const suffix = srvId.slice(\"srvtoolu_\".length)\n if (/^[a-zA-Z0-9_]+$/.test(suffix)) return `toolu_${suffix}`\n }\n return `toolu_advisor_${fallbackIndex}`\n}\n\n/**\n * Fast-path detector: returns true if the raw body has any chance of\n * needing sanitization. Avoids a full JSON parse for the common case\n * where the body is already spec-compliant.\n *\n * Looks for either an Anthropic-native advisor typed tool entry, or\n * any advisor-related block type that would need rewriting/\n * translating.\n */\nfunction bodyMightNeedSanitize(rawBody: string): boolean {\n return (\n rawBody.includes('\"server_tool_use\"')\n || rawBody.includes('\"advisor_tool_result\"')\n || /\"type\":\"advisor_\\d+\"/.test(rawBody)\n )\n}\n\n/**\n * Translate one assistant turn's content array, splitting at advisor\n * pairs into the multi-message structure Copilot accepts.\n *\n * Input shape (Claude Code stores everything in one assistant turn):\n * [text*, server_tool_use{advisor}, advisor_tool_result, text*, ...]\n *\n * Output: array of {role, content[]} message objects, alternating\n * assistant→user→assistant for each advisor pair encountered.\n */\nfunction splitAssistantTurnAtAdvisorPairs(\n originalContent: Array<unknown>,\n syntheticIndexRef: { value: number },\n): { messages: Array<AnyRecord>; translated: boolean } {\n const messages: Array<AnyRecord> = []\n let currentAssistantContent: Array<unknown> = []\n let translated = false\n // Walk linearly. When we see `server_tool_use{name:\"advisor\"}`,\n // expect the very next block to be `advisor_tool_result`. Translate\n // both, split into assistant→user→[continued assistant].\n let i = 0\n while (i < originalContent.length) {\n const block = originalContent[i]\n const b = (typeof block === \"object\" && block !== null) ? (block as AnyRecord) : null\n\n if (\n b\n && b.type === \"server_tool_use\"\n && b.name === ADVISOR_INTERNAL_TOOL_NAME.replace(/^__anthropic_/, \"\") // \"advisor\"\n ) {\n const stuId = typeof b.id === \"string\" ? b.id : \"\"\n // The next block should be the paired advisor_tool_result.\n const nextBlock = originalContent[i + 1]\n const next =\n typeof nextBlock === \"object\" && nextBlock !== null\n ? (nextBlock as AnyRecord)\n : null\n\n // Synthesize a Copilot-shape toolu_* id for the translated pair.\n // Prefer to derive from the existing id (preserves any\n // identifying suffix); if malformed, fall back to a synthesized\n // advisor_N id. Then both blocks of the pair get the SAME id.\n const copilotId = stuId.startsWith(\"srvtoolu_\")\n ? toCopilotToolUseId(stuId, syntheticIndexRef.value++)\n : stuId.startsWith(\"toolu_\") && /^toolu_[a-zA-Z0-9_]+$/.test(stuId)\n ? stuId\n : `toolu_advisor_${syntheticIndexRef.value++}`\n\n // Emit the assistant turn so far + the translated tool_use.\n currentAssistantContent.push({\n type: \"tool_use\",\n id: copilotId,\n name: ADVISOR_INTERNAL_TOOL_NAME,\n input: {},\n })\n messages.push({ role: \"assistant\", content: currentAssistantContent })\n translated = true\n\n // Translate the paired advisor_tool_result → tool_result in a\n // new user turn.\n let resultText = \"\"\n if (next && next.type === \"advisor_tool_result\") {\n const c = next.content\n if (typeof c === \"string\") {\n resultText = c\n } else if (typeof c === \"object\" && c !== null) {\n const txt = (c as AnyRecord).text\n if (typeof txt === \"string\") resultText = txt\n }\n i += 2 // consume both blocks\n } else {\n // No paired result block — synthesize an empty result so\n // Copilot's tool-use/tool-result pairing stays consistent.\n resultText = \"[Advisor result missing in conversation history.]\"\n i += 1\n }\n messages.push({\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: copilotId,\n content: resultText,\n },\n ],\n })\n\n // Start a fresh assistant content array for any blocks after\n // the advisor pair.\n currentAssistantContent = []\n continue\n }\n\n if (b && b.type === \"advisor_tool_result\") {\n // Stray advisor_tool_result without a preceding server_tool_use.\n // Drop it — sending it to Copilot would 400. Loss is minor:\n // this only happens if Claude Code's history is corrupt.\n translated = true\n i += 1\n continue\n }\n\n // Pass-through any other block.\n currentAssistantContent.push(block)\n i += 1\n }\n\n // Flush any trailing assistant content as a final message.\n if (currentAssistantContent.length > 0) {\n messages.push({ role: \"assistant\", content: currentAssistantContent })\n }\n // If we never split (no advisor blocks), return the original as one\n // message so the caller can detect \"no change\" and short-circuit.\n if (!translated) {\n return {\n messages: [{ role: \"assistant\", content: originalContent }],\n translated: false,\n }\n }\n return { messages, translated: true }\n}\n\nexport function sanitizeAnthropicBody(rawBody: string): string {\n if (!bodyMightNeedSanitize(rawBody)) return rawBody\n\n let parsed: AnyRecord\n try {\n parsed = JSON.parse(rawBody) as AnyRecord\n } catch {\n return rawBody\n }\n\n let mutated = false\n\n // 1. Strip Anthropic-native `advisor_*` typed tools from `tools[]`.\n // Copilot 400s on the unknown tool type. Always-strip (vs only\n // when ADVISOR is enabled per `injectAdvisorTool`) covers the case\n // where Claude Code injects the typed tool independently of the\n // beta header.\n if (Array.isArray(parsed.tools)) {\n const tools = parsed.tools as Array<unknown>\n const before = tools.length\n const filtered = tools.filter((t) => {\n if (typeof t !== \"object\" || t === null) return true\n const type = (t as AnyRecord).type\n return typeof type !== \"string\" || !type.startsWith(\"advisor_\")\n })\n if (filtered.length !== before) {\n parsed.tools = filtered\n mutated = true\n }\n }\n\n // 2. Walk messages[] and translate any assistant turns that contain\n // advisor blocks (server_tool_use{name:\"advisor\"} +\n // advisor_tool_result). Per user direction round-7 \"Option C\":\n // rewrite to the tool_use{__anthropic_advisor} + tool_result\n // shape Copilot accepts, splitting into multi-turn assistant→\n // user→assistant as needed (Anthropic spec requires tool_result\n // in user role).\n if (Array.isArray(parsed.messages)) {\n const original = parsed.messages as Array<unknown>\n const rebuilt: Array<unknown> = []\n let anyTranslated = false\n const syntheticIndexRef = { value: 0 }\n for (const msg of original) {\n if (\n typeof msg !== \"object\"\n || msg === null\n || (msg as AnyRecord).role !== \"assistant\"\n ) {\n rebuilt.push(msg)\n continue\n }\n const content = (msg as AnyRecord).content\n if (!Array.isArray(content)) {\n rebuilt.push(msg)\n continue\n }\n // Quick check: does this assistant turn contain any advisor\n // blocks? If not, pass through unchanged.\n const hasAdvisorBlocks = content.some((b) => {\n if (typeof b !== \"object\" || b === null) return false\n const type = (b as AnyRecord).type\n const name = (b as AnyRecord).name\n return (\n (type === \"server_tool_use\" && name === \"advisor\")\n || type === \"advisor_tool_result\"\n )\n })\n if (!hasAdvisorBlocks) {\n rebuilt.push(msg)\n continue\n }\n const { messages: split, translated } = splitAssistantTurnAtAdvisorPairs(\n content as Array<unknown>,\n syntheticIndexRef,\n )\n if (translated) {\n anyTranslated = true\n for (const m of split) rebuilt.push(m)\n } else {\n rebuilt.push(msg)\n }\n }\n if (anyTranslated) {\n parsed.messages = rebuilt\n mutated = true\n // Re-inject __anthropic_advisor tool definition into tools[]\n // so the translated tool_use.name resolves at Copilot's\n // validator. Idempotent: skip if already present.\n const existingTools = Array.isArray(parsed.tools)\n ? (parsed.tools as Array<unknown>)\n : []\n const alreadyInjected = existingTools.some((t) => {\n if (typeof t !== \"object\" || t === null) return false\n return (t as AnyRecord).name === ADVISOR_INTERNAL_TOOL_NAME\n })\n if (!alreadyInjected) {\n parsed.tools = [\n ...existingTools,\n {\n name: ADVISOR_INTERNAL_TOOL_NAME,\n description: ADVISOR_TOOL_INSTRUCTIONS,\n input_schema: {\n type: \"object\",\n properties: {},\n required: [],\n },\n },\n ]\n }\n }\n }\n\n if (!mutated) return rawBody\n return JSON.stringify(parsed)\n}\n\n","/**\n * Anthropic Messages SSE egress: frame builders + a Bun-safe ReadableStream\n * adapter that serializes a generator of Anthropic stream events to wire bytes.\n *\n * The synthesizer (see `responses-egress.ts`) is source-specific and yields\n * plain event objects; these builders + adapter own the Anthropic wire shape\n * and the stream lifecycle so the synthesizer stays a pure state machine.\n *\n * Stream-lifecycle contract (repo mandate for any synthesized SSE surface):\n * the adapter is pull-based (backpressure-respecting), guards every\n * `controller.enqueue`/`close` against the consumer-cancel race\n * (`isControllerClosedError`), and on a mid-stream upstream error emits a\n * terminal Anthropic `event: error` frame before closing — mirroring\n * `relayAnthropicStream`. Verified against Bun's\n * `TypeError: Invalid state: Controller is already closed`.\n */\n\nimport { randomUUID } from \"node:crypto\"\n\nimport consola from \"consola\"\n\nimport { buildAnthropicErrorEvent, isControllerClosedError } from \"~/lib/stream-relay\"\n\nexport interface AnthropicUsage {\n input_tokens?: number\n output_tokens?: number\n cache_read_input_tokens?: number\n cache_creation_input_tokens?: number\n}\n\n/** A synthesized Anthropic SSE event (serialized verbatim to the wire). */\nexport type AnthropicStreamEvent = Record<string, unknown> & { type: string }\n\nexport type AnthropicContentBlock =\n | { type: \"text\"; text: string }\n | { type: \"thinking\"; thinking: string }\n | { type: \"tool_use\"; id: string; name: string; input: Record<string, unknown> }\n\nexport function makeMessageId(): string {\n return `msg_${randomUUID().replace(/-/g, \"\")}`\n}\n\nexport function makeMessageStart(\n id: string,\n model: string,\n usage: AnthropicUsage = {},\n): AnthropicStreamEvent {\n return {\n type: \"message_start\",\n message: {\n id,\n type: \"message\",\n role: \"assistant\",\n model,\n content: [],\n stop_reason: null,\n stop_sequence: null,\n usage: {\n input_tokens: usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? 0,\n cache_read_input_tokens: usage.cache_read_input_tokens ?? 0,\n cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,\n },\n },\n }\n}\n\nexport function makeContentBlockStart(\n index: number,\n block: AnthropicContentBlock,\n): AnthropicStreamEvent {\n return { type: \"content_block_start\", index, content_block: block }\n}\n\nexport function makeTextDelta(index: number, text: string): AnthropicStreamEvent {\n return { type: \"content_block_delta\", index, delta: { type: \"text_delta\", text } }\n}\n\nexport function makeInputJsonDelta(\n index: number,\n partialJson: string,\n): AnthropicStreamEvent {\n return {\n type: \"content_block_delta\",\n index,\n delta: { type: \"input_json_delta\", partial_json: partialJson },\n }\n}\n\nexport function makeThinkingDelta(\n index: number,\n thinking: string,\n): AnthropicStreamEvent {\n return {\n type: \"content_block_delta\",\n index,\n delta: { type: \"thinking_delta\", thinking },\n }\n}\n\nexport function makeSignatureDelta(\n index: number,\n signature: string,\n): AnthropicStreamEvent {\n return {\n type: \"content_block_delta\",\n index,\n delta: { type: \"signature_delta\", signature },\n }\n}\n\nexport function makeContentBlockStop(index: number): AnthropicStreamEvent {\n return { type: \"content_block_stop\", index }\n}\n\nexport function makeMessageDelta(\n stopReason: string,\n stopSequence: string | null,\n usage: AnthropicUsage,\n): AnthropicStreamEvent {\n return {\n type: \"message_delta\",\n delta: { stop_reason: stopReason, stop_sequence: stopSequence },\n usage: {\n input_tokens: usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? 0,\n cache_read_input_tokens: usage.cache_read_input_tokens ?? 0,\n cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,\n },\n }\n}\n\nexport function makeMessageStop(): AnthropicStreamEvent {\n return { type: \"message_stop\" }\n}\n\n/** Serialize one event to the Anthropic SSE wire form (`event:` + `data:`). */\nexport function serializeAnthropicEvent(ev: AnthropicStreamEvent): string {\n return `event: ${ev.type}\\ndata: ${JSON.stringify(ev)}\\n\\n`\n}\n\n/**\n * Wrap a generator of Anthropic stream events into a byte `ReadableStream`.\n * Pull-based; guards the consumer-cancel race on both `enqueue` and `close`;\n * converts a mid-stream generator throw into a terminal `event: error` frame.\n * On consumer cancel it invokes `onCancel` (abort the upstream fetch) and\n * `return()`s the generator so its `finally` tears down the upstream reader.\n */\nexport function anthropicSseStreamFromEvents(\n events: AsyncGenerator<AnthropicStreamEvent>,\n opts: { routePath: string; onCancel?: () => void },\n): ReadableStream<Uint8Array> {\n const enc = new TextEncoder()\n let consumerCancelled = false\n let finished = false\n\n const safeClose = (\n controller: ReadableStreamDefaultController<Uint8Array>,\n ): void => {\n try {\n controller.close()\n } catch {\n // already closed / errored — fine\n }\n }\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n if (consumerCancelled || finished) {\n safeClose(controller)\n return\n }\n\n let res: IteratorResult<AnthropicStreamEvent>\n try {\n res = await events.next()\n } catch (err) {\n finished = true\n if (consumerCancelled) {\n safeClose(controller)\n return\n }\n const name = err instanceof Error ? err.name : \"Error\"\n const message = err instanceof Error ? err.message : String(err)\n consola.error(\n `Anthropic-translate stream interrupted at ${opts.routePath}: ${name}: ${JSON.stringify(message)}`,\n )\n try {\n controller.enqueue(enc.encode(buildAnthropicErrorEvent(name, message)))\n } catch (enqueueError) {\n if (!isControllerClosedError(enqueueError)) {\n consola.warn(\n `Could not deliver error event to consumer at ${opts.routePath}: ${enqueueError instanceof Error ? enqueueError.message : String(enqueueError)}`,\n )\n }\n }\n safeClose(controller)\n return\n }\n\n // Consumer may have cancelled while we awaited the generator.\n if (consumerCancelled) {\n safeClose(controller)\n return\n }\n if (res.done) {\n finished = true\n safeClose(controller)\n return\n }\n\n try {\n controller.enqueue(enc.encode(serializeAnthropicEvent(res.value)))\n } catch (err) {\n if (isControllerClosedError(err)) {\n // Consumer raced ahead and closed the stream — stop quietly.\n consumerCancelled = true\n return\n }\n throw err\n }\n },\n cancel() {\n consumerCancelled = true\n finished = true\n opts.onCancel?.()\n // Drive the generator's finally so it tears down the upstream reader.\n void events.return?.(undefined as never)\n },\n })\n}\n","/**\n * Reasoning-effort bucketing + clamping shared by the `/v1/messages` handler\n * (adaptive-thinking translation) and the Anthropic-translation shim\n * (thinking-budget → Responses `reasoning.effort`).\n *\n * Extracted from `src/routes/messages/handler.ts` so a `~/lib/*` module can\n * depend on it without importing route code (and without forming a\n * handler → shim → handler import cycle). `handler.ts` re-exports these for\n * backward compatibility with existing imports/tests.\n */\n\n/**\n * Copilot's reasoning-effort tiers, lowest to highest.\n *\n * Both ends were added after the fact and both are load-bearing:\n *\n * `none` is advertised by every gpt-5.x entry in the live catalog. While it was\n * missing here it was treated as an UNRECOGNIZED value, so a client asking for\n * the MINIMUM on a model that does not offer it (gemini advertises only\n * low/medium/high) was anchored at the unknown-value tier and clamped to\n * `high` — the maximum. Listing it makes the clamp resolve to `low` instead,\n * which is what \"nearest supported tier\" should always have meant.\n *\n * `max` is advertised by `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`,\n * `claude-opus-5` and the 4.7/4.8 Opus lines, and Claude Code's effort picker\n * offers it for any model whose entry allows it. Listing it lets an explicit\n * selection pass through, and lets `clampEffort` land on it for a model that\n * advertises nothing lower.\n *\n * `bucketEffort` deliberately reaches neither end — see below.\n */\nexport const EFFORT_ORDER = [\"none\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"] as const\n\nexport type Effort = (typeof EFFORT_ORDER)[number]\n\n/** Anchor for an effort value that is not a recognized tier at all.\n *\n * Deliberately NOT the top of `EFFORT_ORDER`. Callers reach this only when the\n * incoming value is unrecognized, which is a guess — and resolving a guess to\n * the most expensive tier a model advertises would silently spend more than the\n * caller could have meant. Anchoring here and clamping DOWN keeps the behavior\n * identical to before `max` joined the ladder, while `max` stays reachable by\n * explicit, valid selection. */\nexport const UNKNOWN_EFFORT_ANCHOR: Effort = \"xhigh\"\n\n/**\n * Bucket a thinking budget into a Copilot reasoning-effort string.\n * `<2000`→low, `<8000`→medium, `<24000`→high, else→xhigh.\n * Defaults missing/non-numeric budgets to 8000 (\"high\").\n *\n * The ceiling stays at `xhigh` even though `max` exists: Anthropic's\n * `budget_tokens` is unbounded above, so any threshold chosen for a `max`\n * bucket would silently re-tier existing callers whose budgets already map to\n * `xhigh`. `max` is reachable only by explicit selection\n * (`output_config.effort`), which is an unambiguous request rather than an\n * inference from a token count.\n */\nexport function bucketEffort(budget: unknown): Effort {\n const n =\n typeof budget === \"number\" && Number.isFinite(budget) ? budget : 8000\n if (n < 2000) return \"low\"\n if (n < 8000) return \"medium\"\n if (n < 24000) return \"high\"\n return \"xhigh\"\n}\n\n/**\n * Clamp a bucketed effort to the closest value in `supported`. Ties resolve to\n * the lower-tier option (per EFFORT_ORDER).\n *\n * Iterates EFFORT_ORDER (canonical low→xhigh) so the first match on a given\n * distance is always the lower-tier value, regardless of input order in\n * `supported`.\n */\nexport function clampEffort(\n bucketed: Effort,\n supported: Array<string>,\n): string {\n if (supported.includes(bucketed)) return bucketed\n const targetIdx = EFFORT_ORDER.indexOf(bucketed)\n let best: Effort | undefined\n let bestDist = Infinity\n for (let i = 0; i < EFFORT_ORDER.length; i++) {\n const value = EFFORT_ORDER[i]\n if (!supported.includes(value)) continue\n const dist = Math.abs(i - targetIdx)\n // strict `<` keeps the first (lower-tier) on ties\n if (dist < bestDist) {\n bestDist = dist\n best = value\n }\n }\n return best ?? bucketed\n}\n","/**\n * Anthropic Messages request ingest.\n *\n * Parses an incoming Anthropic `/v1/messages` body into the provider-neutral\n * request shape (`NeutralMessage[]` + tools + reasoning effort + …) and builds\n * the Copilot `/responses` payload via the shared `assembleResponsesPayload`.\n *\n * Correspondence (Anthropic → Responses):\n * system (string | text blocks) → instructions\n * user text/image blocks → input[] user message (input_text/input_image)\n * user tool_result blocks → input[] function_call_output (+ follow-up user input_image for image content)\n * assistant text blocks → input[] assistant output_text\n * assistant tool_use blocks → input[] function_call items\n * assistant thinking blocks → dropped (not replayable to Responses)\n * tools[] {name, input_schema} → tools[] {type:function, name, parameters}\n * tool_choice {auto|any|tool|none} → tool_choice auto|required|{type:function,name}|none (name-less tool → unset)\n * tool_choice.disable_parallel_tool_use → parallel_tool_calls:false (only the disable; never sends true)\n * thinking absent → reasoning.effort high (clamped)\n * thinking {enabled, budget_tokens} → reasoning.effort (bucketed + clamped)\n * max_tokens → max_output_tokens\n * stop_sequences → stop (Copilot's /responses accepts it — verified live)\n */\n\nimport type { ResponsesPayload } from \"~/services/copilot/create-responses\"\nimport {\n assembleResponsesPayload,\n type NeutralContentPart,\n type NeutralMessage,\n type NeutralTool,\n} from \"~/services/copilot/responses-request\"\nimport type { Model } from \"~/services/copilot/get-models\"\nimport { shimDefaultsToXhigh } from \"~/lib/openai-frontier\"\nimport {\n EFFORT_ORDER,\n UNKNOWN_EFFORT_ANCHOR,\n bucketEffort,\n clampEffort,\n type Effort,\n} from \"~/lib/reasoning-effort\"\nimport { parseBoolEnv } from \"~/lib/exec\"\n\ntype AnyRecord = Record<string, unknown>\n\nexport interface ParsedAnthropicRequest {\n model: string\n instructions?: string\n messages: Array<NeutralMessage>\n tools?: Array<NeutralTool>\n toolChoice?: ResponsesPayload[\"tool_choice\"]\n reasoningEffort?: string\n maxOutputTokens?: number\n /**\n * Anthropic `stop_sequences`, forwarded to the wire as Responses/chat `stop`.\n * Copilot's `/responses` and `/chat/completions` both accept `stop` (verified\n * live, HTTP 200), so the sequences are honored rather than dropped.\n */\n stopSequences?: string[]\n /**\n * Signal that Anthropic's `tool_choice.disable_parallel_tool_use` was `true`.\n * Only ever `false` (the disable) — carried so the payload builders emit\n * `parallel_tool_calls: false`; absent means the field is omitted (never sent\n * as `true`).\n */\n parallelToolCalls?: false\n stream: boolean\n}\n\n/**\n * Steering appended to `instructions` for shim-routed (non-Claude) models when\n * the request carries Claude Code's native file tools. gpt-5.5 and other\n * OpenAI/Gemini-lineage models receive the Edit/Write tool definitions verbatim\n * (the shim never mangles them), but their base prior is to script file ops in\n * Python/Bash rather than call the dedicated tools. Claude models never reach\n * this code path (they fall through to the /v1/messages passthrough), so this is\n * automatically scoped to the models that need the nudge. Strong PREFERENCE, not\n * a Bash ban — running builds/tests/git still belongs in Bash.\n */\nconst FILE_TOOL_GUIDANCE = `<file_tools>\nYou have dedicated tools for files: use Read to read a file, Edit to modify an existing file, and Write to create one. Prefer them over shell for reading or editing. Do NOT shell out (cat, sed, awk, echo >, here-docs, or python/one-off scripts) to read, search, or rewrite file contents when a dedicated tool exists — the dedicated tools are safer and produce reviewable diffs. Use Grep/Glob to search rather than shell grep/find. Reserve Bash for commands that have no dedicated tool: builds, tests, git, package managers, and running programs.\n</file_tools>`\n\n/**\n * Append `FILE_TOOL_GUIDANCE` to the flattened system `instructions` iff the\n * request carries Claude Code's canonical `Edit` or `Write` tool. The exact\n * capitalized-name match is deliberately precise: it fires for a Claude Code\n * editing session but not for arbitrary MCP tools like `write_file`, and not for\n * non-editing chats (so a plain gpt-5.5 conversation is not polluted). The block\n * is appended AFTER the existing instructions (end-of-prompt recency) and the\n * original system text is preserved, never replaced. Opt out with\n * `GH_ROUTER_DISABLE_SHIM_TOOL_STEERING=1`.\n */\nfunction appendFileToolGuidance(\n instructions: string | undefined,\n tools: Array<NeutralTool> | undefined,\n): string | undefined {\n if (parseBoolEnv(process.env.GH_ROUTER_DISABLE_SHIM_TOOL_STEERING) === true) {\n return instructions\n }\n const hasFileTool = tools?.some((t) => t.name === \"Edit\" || t.name === \"Write\")\n if (!hasFileTool) return instructions\n return instructions && instructions.length > 0\n ? `${instructions}\\n\\n${FILE_TOOL_GUIDANCE}`\n : FILE_TOOL_GUIDANCE\n}\n\n/** Flatten Anthropic `system` (string | array of text blocks) into a string. */\nfunction flattenSystem(system: unknown): string | undefined {\n if (typeof system === \"string\") return system.length > 0 ? system : undefined\n if (Array.isArray(system)) {\n let s = \"\"\n for (const block of system) {\n if (block && typeof block === \"object\" && (block as AnyRecord).type === \"text\") {\n const t = (block as AnyRecord).text\n if (typeof t === \"string\") s += t\n }\n }\n return s.length > 0 ? s : undefined\n }\n return undefined\n}\n\n/**\n * Parse an Anthropic `tool_result.content` (string | block array) into the\n * plain-text `output` for the Responses `function_call_output` (a string-only\n * item) PLUS any image parts found in the content. A `function_call_output`\n * cannot carry images, so the caller emits the extracted images as a follow-up\n * user message (Claude Code browser screenshots/observations arrive this way).\n * `isError` (the tool_result `is_error` flag) is preserved by prefixing the\n * text so the model still learns the tool call failed.\n */\nfunction parseToolResultContent(\n content: unknown,\n isError: boolean,\n): { output: string; images: Array<NeutralContentPart> } {\n const images: Array<NeutralContentPart> = []\n let text = \"\"\n if (typeof content === \"string\") {\n text = content\n } else if (Array.isArray(content)) {\n for (const block of content) {\n if (!block || typeof block !== \"object\") continue\n const b = block as AnyRecord\n if (b.type === \"text\" && typeof b.text === \"string\") {\n text += b.text\n } else if (b.type === \"image\") {\n const img = anthropicImageToNeutral(b.source as AnyRecord)\n if (img) images.push(img)\n }\n }\n }\n // A function_call_output must be a meaningful string; when the tool returned\n // only image(s), point the model at the follow-up user message that carries\n // them rather than emitting an empty output.\n if (images.length > 0 && text.length === 0) {\n text = \"[image result below]\"\n }\n if (isError) {\n text = text.length > 0 ? `[tool error] ${text}` : \"[tool error]\"\n }\n return { output: text, images }\n}\n\n/** Map an Anthropic `image` block source to a neutral image part. */\nfunction anthropicImageToNeutral(source: AnyRecord | undefined): NeutralContentPart | null {\n if (!source || typeof source !== \"object\") return null\n if (source.type === \"url\" && typeof source.url === \"string\") {\n return { type: \"image\", url: source.url }\n }\n if (source.type === \"base64\" && typeof source.data === \"string\") {\n return {\n type: \"image\",\n mimeType: typeof source.media_type === \"string\" ? source.media_type : \"image/png\",\n data: source.data,\n }\n }\n return null\n}\n\n/** Concatenate the text of an Anthropic `document` `content`-source block array. */\nfunction joinDocumentContentText(content: unknown): string {\n if (!Array.isArray(content)) return \"\"\n let text = \"\"\n for (const block of content) {\n if (block && typeof block === \"object\") {\n const b = block as AnyRecord\n if (b.type === \"text\" && typeof b.text === \"string\") text += b.text\n }\n }\n return text\n}\n\n/**\n * Map an Anthropic `document` block to a neutral content part.\n * - base64 source → neutral `document` (mimeType + data) → Responses\n * `input_file` with `file_data`; on the chat path → an inline text note\n * (Copilot's `/chat/completions` rejects file parts).\n * - url source → neutral `document` (url) → Responses `input_file.file_url`.\n * - text source (a plain-text document) → the doc's text folded into a `text`\n * part, so the model sees it on BOTH paths.\n * - content source (content-block document) → its text blocks folded into a\n * `text` part.\n * Missing/invalid fields (unknown source type, `file`-id references Copilot has\n * no Files API for, empty text) yield null and are dropped.\n */\nfunction anthropicDocumentToNeutral(b: AnyRecord): NeutralContentPart | null {\n const source = b.source\n if (!source || typeof source !== \"object\") return null\n const s = source as AnyRecord\n const filename =\n typeof b.title === \"string\" && b.title.length > 0 ? b.title : \"document.pdf\"\n if (s.type === \"base64\" && typeof s.data === \"string\") {\n return {\n type: \"document\",\n mimeType: typeof s.media_type === \"string\" ? s.media_type : \"application/pdf\",\n data: s.data,\n filename,\n }\n }\n if (s.type === \"url\" && typeof s.url === \"string\") {\n return { type: \"document\", url: s.url, filename }\n }\n if (s.type === \"text\" && typeof s.data === \"string\") {\n return s.data.length > 0 ? { type: \"text\", text: s.data } : null\n }\n if (s.type === \"content\") {\n const text = joinDocumentContentText(s.content)\n return text.length > 0 ? { type: \"text\", text } : null\n }\n return null\n}\n\n/**\n * Convert one Anthropic message into zero-or-more neutral messages. A user\n * message with `tool_result` blocks fans out: text/image content becomes a\n * user message and each tool_result becomes its own `toolResult` message,\n * emitted in wire order so a function_call_output never precedes its text.\n */\nfunction anthropicMessageToNeutral(msg: AnyRecord): Array<NeutralMessage> {\n const role = msg.role\n const content = msg.content\n\n if (role === \"assistant\") {\n const parts: Array<NeutralContentPart> = []\n if (typeof content === \"string\") {\n if (content.length > 0) parts.push({ type: \"text\", text: content })\n } else if (Array.isArray(content)) {\n for (const block of content) {\n if (!block || typeof block !== \"object\") continue\n const b = block as AnyRecord\n if (b.type === \"text\" && typeof b.text === \"string\") {\n parts.push({ type: \"text\", text: b.text })\n } else if (b.type === \"tool_use\") {\n parts.push({\n type: \"toolCall\",\n id: typeof b.id === \"string\" ? b.id : \"\",\n name: typeof b.name === \"string\" ? b.name : \"\",\n arguments: b.input ?? {},\n })\n }\n // thinking / redacted_thinking blocks are dropped.\n }\n }\n return [{ role: \"assistant\", content: parts }]\n }\n\n // Treat everything else as a user turn (Anthropic only has user/assistant).\n const out: Array<NeutralMessage> = []\n let userParts: Array<NeutralContentPart> = []\n const flushUser = (): void => {\n if (userParts.length === 0) return\n out.push({ role: \"user\", content: userParts })\n userParts = []\n }\n\n if (typeof content === \"string\") {\n if (content.length > 0) out.push({ role: \"user\", content })\n return out\n }\n if (Array.isArray(content)) {\n for (const block of content) {\n if (!block || typeof block !== \"object\") continue\n const b = block as AnyRecord\n if (b.type === \"text\" && typeof b.text === \"string\") {\n userParts.push({ type: \"text\", text: b.text })\n } else if (b.type === \"image\") {\n const img = anthropicImageToNeutral(b.source as AnyRecord)\n if (img) userParts.push(img)\n } else if (b.type === \"document\") {\n // A PDF / document block. base64 & url sources ride as a neutral\n // `document` part (→ Responses input_file; chat path degrades to a text\n // note); text/content sources fold into a text part right here.\n const doc = anthropicDocumentToNeutral(b)\n if (doc) userParts.push(doc)\n } else if (b.type === \"tool_result\") {\n // A tool result closes the current user text/image run and becomes its\n // own neutral message so it lands as a Responses function_call_output\n // (a string-only item). Image blocks inside the tool_result (e.g.\n // Claude Code browser screenshots) can't ride in that item, so they're\n // emitted as a follow-up user message in wire order right after it —\n // otherwise the model never sees the pixels it asked for.\n flushUser()\n const { output, images } = parseToolResultContent(\n b.content,\n b.is_error === true,\n )\n out.push({\n role: \"toolResult\",\n toolCallId: typeof b.tool_use_id === \"string\" ? b.tool_use_id : \"\",\n output,\n })\n if (images.length > 0) {\n out.push({ role: \"user\", content: images })\n }\n }\n }\n }\n flushUser()\n return out\n}\n\nfunction parseTools(tools: unknown): Array<NeutralTool> | undefined {\n if (!Array.isArray(tools) || tools.length === 0) return undefined\n const out: Array<NeutralTool> = []\n for (const tool of tools) {\n if (!tool || typeof tool !== \"object\") continue\n const t = tool as AnyRecord\n if (typeof t.name !== \"string\" || t.name.length === 0) continue\n const schema = t.input_schema ?? t.parameters\n out.push({\n name: t.name,\n description: typeof t.description === \"string\" ? t.description : undefined,\n parameters:\n schema && typeof schema === \"object\"\n ? (schema as Record<string, unknown>)\n : { type: \"object\", properties: {} },\n })\n }\n return out.length > 0 ? out : undefined\n}\n\nfunction parseToolChoice(\n toolChoice: unknown,\n): ResponsesPayload[\"tool_choice\"] | undefined {\n if (!toolChoice || typeof toolChoice !== \"object\") return undefined\n const tc = toolChoice as AnyRecord\n switch (tc.type) {\n case \"auto\":\n return \"auto\"\n case \"any\":\n return \"required\"\n case \"none\":\n return \"none\"\n case \"tool\":\n // A forced tool call. WITH a usable `name`, force that function. WITHOUT\n // one the shape is malformed — return undefined so the caller's documented\n // default applies, rather than SILENTLY downgrading a forced call to\n // \"auto\" (model discretion), which would defeat the caller's intent to\n // force a specific tool.\n return typeof tc.name === \"string\" && tc.name.length > 0\n ? { type: \"function\", name: tc.name }\n : undefined\n default:\n return undefined\n }\n}\n\n/**\n * Anthropic carries `disable_parallel_tool_use` on the `tool_choice` object.\n * Returns `false` (the wire signal to disable parallel tool calls) only when it\n * is explicitly `true`; `undefined` otherwise, so the payload builders omit the\n * field rather than ever sending `parallel_tool_calls: true`.\n */\nfunction parseDisableParallelToolUse(toolChoice: unknown): false | undefined {\n if (!toolChoice || typeof toolChoice !== \"object\") return undefined\n return (toolChoice as AnyRecord).disable_parallel_tool_use === true\n ? false\n : undefined\n}\n\n/** Default absent Anthropic `thinking` to an effort, clamped by the model.\n * Every shim model defaults to `high`, so a client level maps to the identical\n * provider level (low→low, medium→medium, high→high, xhigh→xhigh) and `high` is\n * the only value the router injects on its own. There is deliberately NO floor:\n * an explicit client budget that buckets to `medium` yields `medium`, because a\n * one-directional max() would mean the router silently overriding the level the\n * user chose.\n *\n * Opt in to the previous behavior (xhigh for the OpenAI frontier models when no\n * thinking is sent) with `GH_ROUTER_FRONTIER_XHIGH_DEFAULT=1`. This replaces the\n * old opt-OUT `GH_ROUTER_DISABLE_FRONTIER_XHIGH_DEFAULT`, whose meaning would\n * have inverted under the new default.\n *\n * Two honest limits, both pre-existing: the level is bucketed from a token\n * budget so the mapping is lossy at the boundaries, and `clampEffort` moves a\n * level the model does not advertise (gemini has no `xhigh`). Returns undefined\n * for a model that advertises NO `reasoning_effort` allowlist, which leaves the\n * provider's own default rather than `high` — forcing an effort there could 400.\n * An explicit client `thinking` budget is handled by parseReasoningEffort and is\n * NOT affected by this default. */\nfunction defaultReasoningEffort(model?: Model): string | undefined {\n const supported = model?.capabilities?.supports?.reasoning_effort\n if (!(Array.isArray(supported) && supported.length > 0)) return undefined\n const wantXhigh =\n parseBoolEnv(process.env.GH_ROUTER_FRONTIER_XHIGH_DEFAULT) === true\n && model?.id != null\n && shimDefaultsToXhigh(model.id)\n && supported.includes(\"xhigh\")\n return clampEffort(wantXhigh ? \"xhigh\" : \"high\", supported)\n}\n\n/**\n * Map Anthropic `thinking` to a Responses reasoning effort, clamped to the\n * model's `reasoning_effort` allowlist. Returns undefined when thinking is\n * absent/disabled/non-enabled; the absent default is applied at the call site.\n */\nfunction parseReasoningEffort(\n thinking: unknown,\n model?: Model,\n): string | undefined {\n if (!thinking || typeof thinking !== \"object\") return undefined\n const t = thinking as AnyRecord\n if (t.type !== \"enabled\") return undefined\n const bucketed = bucketEffort(t.budget_tokens)\n const supported = model?.capabilities?.supports?.reasoning_effort\n return Array.isArray(supported) && supported.length > 0\n ? clampEffort(bucketed, supported)\n : bucketed\n}\n\n/**\n * Client-selected reasoning effort in Copilot shape (`output_config.effort`) —\n * what Claude Code's effort picker puts on the wire.\n *\n * This is the highest-precedence signal, matching the rule the passthrough path\n * already documents (\"client-supplied `output_config.effort` always wins\",\n * `routes/messages/handler.ts`). Before it was read here the field survived\n * every preprocessing step and was then simply dropped by the shim, which made\n * the picker a no-op on non-Claude models in three distinct ways: alone it fell\n * through to the `high` default, alongside a `thinking` budget it lost to the\n * bucketed budget, and alongside `thinking:{type:\"adaptive\"}` it produced NO\n * reasoning field at all (the adaptive shape is neither `undefined` nor\n * `enabled`, so both of the other branches decline it).\n *\n * `clampOutputConfigEffortInPlace` has normally already clamped this against the\n * model's allowlist upstream, but the clamp is repeated here so the shim is\n * correct when called directly, and so an unrecognized level (a future Copilot\n * tier) resolves the same way it does on the passthrough path: anchored at\n * `UNKNOWN_EFFORT_ANCHOR` and clamped DOWN to the highest the model actually\n * advertises, never up.\n *\n * When the model advertises NO allowlist there is nothing to validate against,\n * so only a recognized tier is honored and anything else declines to the\n * `thinking`/default chain. Passing an arbitrary string through would let a\n * typo become a synthesized `reasoning.effort` on a payload we build, which is\n * the 400 that `defaultReasoningEffort` already refuses to risk by returning\n * undefined in exactly this case.\n */\nfunction parseOutputConfigEffort(\n body: AnyRecord,\n model?: Model,\n): string | undefined {\n const oc = body.output_config\n if (!oc || typeof oc !== \"object\") return undefined\n const effort = (oc as AnyRecord).effort\n if (typeof effort !== \"string\" || effort === \"\") return undefined\n const known = (EFFORT_ORDER as ReadonlyArray<string>).includes(effort)\n const supported = model?.capabilities?.supports?.reasoning_effort\n if (!(Array.isArray(supported) && supported.length > 0)) {\n return known ? effort : undefined\n }\n if (supported.includes(effort)) return effort\n return clampEffort(known ? (effort as Effort) : UNKNOWN_EFFORT_ANCHOR, supported)\n}\n\n/**\n * Parse an already-JSON-parsed Anthropic Messages body into the neutral shape.\n * `resolvedModel` is the catalog id the request will run on; `model` its\n * catalog entry (for the reasoning-effort allowlist).\n */\nexport function parseAnthropicRequest(\n body: AnyRecord,\n resolvedModel: string,\n model?: Model,\n): ParsedAnthropicRequest {\n const messages: Array<NeutralMessage> = []\n if (Array.isArray(body.messages)) {\n for (const msg of body.messages) {\n if (msg && typeof msg === \"object\") {\n for (const n of anthropicMessageToNeutral(msg as AnyRecord)) messages.push(n)\n }\n }\n }\n\n const maxTokens =\n typeof body.max_tokens === \"number\" && body.max_tokens > 0\n ? body.max_tokens\n : undefined\n\n const stopSequences =\n Array.isArray(body.stop_sequences)\n ? body.stop_sequences.filter((s: unknown): s is string => typeof s === \"string\")\n : undefined\n\n const tools = parseTools(body.tools)\n\n return {\n model: resolvedModel,\n instructions: appendFileToolGuidance(flattenSystem(body.system), tools),\n messages,\n tools,\n toolChoice: parseToolChoice(body.tool_choice),\n parallelToolCalls: parseDisableParallelToolUse(body.tool_choice),\n reasoningEffort:\n parseOutputConfigEffort(body, model)\n ?? (body.thinking === undefined\n ? defaultReasoningEffort(model)\n : parseReasoningEffort(body.thinking, model)),\n maxOutputTokens: maxTokens,\n stopSequences: stopSequences && stopSequences.length > 0 ? stopSequences : undefined,\n stream: body.stream === true,\n }\n}\n\n/** Build the Copilot `/responses` payload from a parsed Anthropic request. */\nexport function parsedToResponsesPayload(\n parsed: ParsedAnthropicRequest,\n): ResponsesPayload {\n return assembleResponsesPayload({\n model: parsed.model,\n instructions: parsed.instructions,\n messages: parsed.messages,\n tools: parsed.tools,\n toolChoice: parsed.toolChoice,\n reasoningEffort: parsed.reasoningEffort,\n maxOutputTokens: parsed.maxOutputTokens,\n stopSequences: parsed.stopSequences,\n parallelToolCalls: parsed.parallelToolCalls,\n stream: parsed.stream,\n })\n}\n","/**\n * Anthropic Messages request → Copilot `/chat/completions` payload.\n *\n * The Gemini path (`gemini-3.5-flash`, `gemini-3.1-pro-preview`) is served by\n * Copilot only via the OpenAI-compatible `/chat/completions` endpoint. This\n * module assembles a `ChatCompletionsPayload` from the SAME provider-neutral\n * `ParsedAnthropicRequest` that feeds the Responses path — the neutral parse\n * (`parseAnthropicRequest`) is reused verbatim; only the wire assembly differs.\n *\n * Correspondence (neutral → chat/completions):\n * instructions → messages[0] {role:\"system\"}\n * user text (no image) → messages[] {role:\"user\", content:string}\n * user text + image → {role:\"user\", content:[{type:\"text\"},{type:\"image_url\"}]}\n * assistant text + tool_use → {role:\"assistant\", content, tool_calls[]}\n * toolResult → {role:\"tool\", tool_call_id, content}\n * tools[] {name,params} → tools[] {type:\"function\", function:{name,description,parameters}}\n * tool_choice {type,name} → NESTED chat form {type:\"function\", function:{name}}\n * reasoningEffort (clamped) → reasoning_effort (already clamped at parse time)\n * maxOutputTokens → max_tokens\n *\n * Structured Outputs (`response_format` / `output_config.schema`) is NOT\n * emitted: neither Gemini model advertises `structured_outputs`, and the\n * neutral parse carries no structured-output info anyway (the handler strips\n * every `output_config` member EXCEPT `effort` before the shim is reached, and\n * `effort` is consumed by `parseAnthropicRequest` as the highest-precedence\n * reasoning signal).\n */\n\nimport type {\n ChatCompletionsPayload,\n ContentPart,\n Message,\n Tool,\n ToolCall,\n} from \"~/services/copilot/create-chat-completions\"\n\nimport type { ParsedAnthropicRequest } from \"./anthropic-request\"\nimport type {\n NeutralContentPart,\n NeutralMessage,\n NeutralTool,\n} from \"~/services/copilot/responses-request\"\n\n/** Build the `data:` URI (base64) or return the verbatim URL for an image part. */\nfunction imageUrlFor(part: Extract<NeutralContentPart, { type: \"image\" }>): string {\n if (typeof part.url === \"string\" && part.url.length > 0) return part.url\n const mime = part.mimeType ?? \"image/png\"\n return `data:${mime};base64,${part.data ?? \"\"}`\n}\n\n/**\n * A brief inline note standing in for a document on the chat path. Copilot's\n * `/chat/completions` rejects file content parts (`type` must be `image_url` or\n * `text` → HTTP 400), so a document (PDF) can't be forwarded to a Gemini model;\n * the note keeps the document from being silently dropped and tells the model\n * one was provided but is unavailable, instead of 400ing the request.\n *\n * The note is wrapped in leading + trailing newlines so it is always DELIMITED\n * from adjacent user text — in the string-collapse branch it can't glue onto a\n * neighboring text run (`...[model]what is this?`), and in the content-parts\n * branch it stands as its own line. Regular text-to-text concatenation is left\n * untouched (only the note carries the delimiter), so wire order is preserved.\n */\nfunction documentNote(part: Extract<NeutralContentPart, { type: \"document\" }>): string {\n const name = part.filename ?? \"document\"\n return `\\n[document \"${name}\" attached but not supported for this model]\\n`\n}\n\n/**\n * A user turn: plain string when there are no images; otherwise OpenAI content\n * parts (`text` / `image_url`). Mirrors `neutralUserToResponses` so the two\n * shims encode a multimodal user turn the same way.\n */\nfunction neutralUserToChat(\n m: Extract<NeutralMessage, { role: \"user\" }>,\n): Message {\n if (typeof m.content === \"string\") {\n return { role: \"user\", content: m.content }\n }\n const hasImage = m.content.some((c) => c.type === \"image\")\n if (!hasImage) {\n // No images → collapse to a single string. Documents can't be forwarded to\n // Copilot's chat endpoint, so each becomes an inline text note rather than\n // being silently lost.\n let text = \"\"\n for (const c of m.content) {\n if (c.type === \"text\") text += c.text\n else if (c.type === \"document\") text += documentNote(c)\n }\n return { role: \"user\", content: text }\n }\n const parts: Array<ContentPart> = []\n for (const c of m.content) {\n if (c.type === \"text\") {\n parts.push({ type: \"text\", text: c.text })\n } else if (c.type === \"image\") {\n parts.push({ type: \"image_url\", image_url: { url: imageUrlFor(c) } })\n } else if (c.type === \"document\") {\n // Degrade to a text note — never an upstream-invalid file part.\n parts.push({ type: \"text\", text: documentNote(c) })\n }\n }\n return { role: \"user\", content: parts }\n}\n\n/**\n * An assistant turn: text parts collapse into `content`, tool_use parts become\n * OpenAI `tool_calls`. Unlike the Responses path (which flushes text before each\n * call to preserve interleaving), the chat wire shape carries all text on\n * `content` and all calls on `tool_calls`, so ordering within the turn is not\n * representable — matching how OpenAI itself echoes an assistant turn. When the\n * turn is tool-calls-only, `content` is `null` (OpenAI convention).\n */\nfunction neutralAssistantToChat(\n m: Extract<NeutralMessage, { role: \"assistant\" }>,\n): Message {\n let text = \"\"\n const toolCalls: Array<ToolCall> = []\n for (const c of m.content) {\n if (c.type === \"text\") {\n text += c.text\n } else if (c.type === \"toolCall\") {\n toolCalls.push({\n id: c.id,\n type: \"function\",\n function: {\n name: c.name,\n arguments: JSON.stringify(c.arguments ?? {}),\n },\n })\n }\n }\n const content = text.length > 0 ? text : toolCalls.length > 0 ? null : \"\"\n const msg: Message = { role: \"assistant\", content }\n if (toolCalls.length > 0) msg.tool_calls = toolCalls\n return msg\n}\n\n/** Translate one neutral message into a single chat/completions message. */\nfunction neutralMessageToChat(m: NeutralMessage): Message {\n if (m.role === \"user\") return neutralUserToChat(m)\n if (m.role === \"assistant\") return neutralAssistantToChat(m)\n return { role: \"tool\", tool_call_id: m.toolCallId, content: m.output }\n}\n\nfunction neutralToolsToChat(\n tools: ReadonlyArray<NeutralTool> | undefined,\n): Array<Tool> | undefined {\n if (!tools || tools.length === 0) return undefined\n return tools.map((t) => ({\n type: \"function\",\n function: {\n name: t.name,\n description: t.description,\n parameters: t.parameters ?? { type: \"object\", properties: {} },\n },\n }))\n}\n\n/**\n * Convert the parsed (Responses-flat) `tool_choice` to the chat NESTED form.\n * A forced tool is `{type:\"function\", function:{name}}` on chat/completions —\n * distinct from the Responses flat `{type:\"function\", name}`. `\"auto\"` /\n * `\"required\"` / `\"none\"` pass through unchanged.\n */\nfunction toolChoiceToChat(\n tc: ParsedAnthropicRequest[\"toolChoice\"],\n): ChatCompletionsPayload[\"tool_choice\"] {\n if (tc === undefined) return undefined\n if (typeof tc === \"string\") {\n return tc === \"auto\" || tc === \"none\" || tc === \"required\" ? tc : undefined\n }\n if (tc.type === \"function\" && typeof tc.name === \"string\" && tc.name.length > 0) {\n return { type: \"function\", function: { name: tc.name } }\n }\n return undefined\n}\n\n/** Assemble the `/chat/completions` payload from a parsed Anthropic request. */\nexport function parsedToChatPayload(\n parsed: ParsedAnthropicRequest,\n): ChatCompletionsPayload {\n const messages: Array<Message> = []\n if (parsed.instructions) {\n messages.push({ role: \"system\", content: parsed.instructions })\n }\n for (const m of parsed.messages) messages.push(neutralMessageToChat(m))\n\n const payload: ChatCompletionsPayload = {\n model: parsed.model,\n messages,\n stream: parsed.stream,\n }\n\n const tools = neutralToolsToChat(parsed.tools)\n if (tools && tools.length > 0) {\n payload.tools = tools\n // Default to \"auto\" when tools are present and no choice was given, so the\n // chat and Responses shims agree on the tools-present default.\n payload.tool_choice = toolChoiceToChat(parsed.toolChoice) ?? \"auto\"\n }\n\n // `parsed.reasoningEffort` was already bucketed AND clamped to the model's\n // `reasoning_effort` allowlist at parse time (so Gemini's xhigh → high), so\n // it is forwarded verbatim. \"off\"/undefined means no reasoning field.\n if (parsed.reasoningEffort && parsed.reasoningEffort !== \"off\") {\n payload.reasoning_effort = parsed.reasoningEffort\n }\n\n if (typeof parsed.maxOutputTokens === \"number\" && parsed.maxOutputTokens > 0) {\n payload.max_tokens = parsed.maxOutputTokens\n }\n\n // stop_sequences → `stop` (Copilot's /chat/completions accepts it, verified live).\n if (parsed.stopSequences && parsed.stopSequences.length > 0) {\n payload.stop = parsed.stopSequences\n }\n\n // tool_choice.disable_parallel_tool_use → parallel_tool_calls:false (honor the\n // disable only; never emit `true`).\n if (parsed.parallelToolCalls === false) {\n payload.parallel_tool_calls = false\n }\n\n return payload\n}\n","/**\n * Copilot `/chat/completions` → Anthropic Messages egress (the Gemini path).\n *\n * - `chatResponseToAnthropicMessage` maps a non-streaming chat/completions\n * object to an Anthropic Messages object (text + tool_use blocks, usage,\n * stop_reason).\n * - `synthAnthropicFromChat` is the streaming state machine: it consumes\n * Copilot's chat SSE (`choices[].delta`) and yields Anthropic stream events\n * (message_start → content_block_* → message_delta → message_stop), reusing\n * the shared `anthropic-sse.ts` frame builders.\n *\n * Chat streaming differs from the Responses path in one load-bearing way: there\n * is NO authoritative per-tool `.done` event carrying the full arguments — a\n * tool call's `id`/`name` arrive early (first delta for its array `index`) and\n * its `arguments` stream incrementally across later deltas keyed by that same\n * array `index`. So each tool is BUFFERED per OpenAI array index and its\n * Anthropic block is emitted ATOMICALLY at end-of-stream (content_block_start →\n * one input_json_delta with the full assembled args → content_block_stop). This\n * carries the Phase 1 C1 correctness lesson to the chat path: parallel/multiple\n * tools keep DISTINCT block indices and never lose their args to a clobbered\n * shared pointer. An open TEXT block is closed before any tool block opens (a\n * tool_use must not nest inside a text block on the wire). The Anthropic block\n * index is assigned at emit time so indices stay monotonic on the wire.\n */\n\nimport { randomUUID } from \"node:crypto\"\n\nimport type {\n ChatCompletionResponse,\n} from \"~/services/copilot/create-chat-completions\"\n\nimport {\n type AnthropicStreamEvent,\n type AnthropicUsage,\n makeContentBlockStart,\n makeContentBlockStop,\n makeInputJsonDelta,\n makeMessageDelta,\n makeMessageId,\n makeMessageStart,\n makeMessageStop,\n makeTextDelta,\n} from \"./anthropic-sse\"\n\ntype AnyRecord = Record<string, unknown>\n\n/** Streaming chat chunk subset we consume (`choices[].delta` + trailing usage). */\ninterface ChatSseChunk {\n choices?: Array<{\n delta?: {\n content?: string | null\n /** Model refusal text. Arrives outside `content`; see `chatStopReason`. */\n refusal?: string | null\n tool_calls?: Array<{\n /** OpenAI array index — the load-bearing correlation key. */\n index?: number\n id?: string\n function?: { name?: string; arguments?: string }\n }>\n }\n finish_reason?: string | null\n }>\n usage?: ChatUsage\n}\n\ninterface ChatUsage {\n prompt_tokens?: number\n completion_tokens?: number\n prompt_tokens_details?: { cached_tokens?: number }\n}\n\n/** Synthesize a matchable Anthropic tool_use id when the upstream id is absent. */\nfunction makeToolUseId(): string {\n return `toolu_${randomUUID().replace(/-/g, \"\")}`\n}\n\nfunction parseToolArgs(raw: unknown): Record<string, unknown> {\n if (typeof raw !== \"string\" || raw.trim().length === 0) return {}\n try {\n const parsed = JSON.parse(raw) as unknown\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>\n }\n } catch {\n // malformed — surface empty args (the model can retry)\n }\n return {}\n}\n\nfunction anthropicUsageFromChat(u: ChatUsage | undefined): AnthropicUsage {\n if (!u) return {}\n return {\n input_tokens: u.prompt_tokens ?? 0,\n output_tokens: u.completion_tokens ?? 0,\n cache_read_input_tokens: u.prompt_tokens_details?.cached_tokens ?? 0,\n cache_creation_input_tokens: 0,\n }\n}\n\n/**\n * Map a chat/completions `finish_reason` to an Anthropic stop_reason. A\n * truncated (`length`) response is `max_tokens` even when a partial tool call\n * is present — the response was cut — mirroring the Responses egress precedence.\n * `tool_calls` (or any buffered tool) → `tool_use`.\n *\n * `content_filter` maps to Anthropic's `refusal`, NOT `end_turn`. It used to\n * collapse into `end_turn`, which made an upstream safety block indistinguishable\n * from a normal completion: the client saw a successful, usually empty, message\n * and had no way to tell that content had been withheld. `refusal` is the\n * documented Anthropic stop_reason for exactly this case.\n */\nfunction chatStopReason(finishReason: string | null, sawTool: boolean): string {\n if (finishReason === \"length\") return \"max_tokens\"\n if (finishReason === \"tool_calls\" || sawTool) return \"tool_use\"\n if (finishReason === \"content_filter\") return \"refusal\"\n return \"end_turn\"\n}\n\n// ---------------------------------------------------------------------------\n// non-streaming\n// ---------------------------------------------------------------------------\n\ninterface AnthropicMessageResult {\n id: string\n type: \"message\"\n role: \"assistant\"\n model: string\n content: Array<Record<string, unknown>>\n stop_reason: string\n stop_sequence: null\n usage: {\n input_tokens: number\n output_tokens: number\n cache_read_input_tokens: number\n cache_creation_input_tokens: number\n }\n}\n\n/**\n * Map a non-streaming chat/completions object to an Anthropic Messages object.\n * The first choice's `message.content` becomes a text block (when non-empty)\n * and each `message.tool_calls[]` becomes a tool_use block.\n */\nexport function chatResponseToAnthropicMessage(\n resp: ChatCompletionResponse,\n modelId: string,\n): AnthropicMessageResult {\n const choice = resp.choices?.[0]\n const content: Array<AnyRecord> = []\n let sawTool = false\n\n const message = choice?.message\n if (message) {\n if (typeof message.content === \"string\" && message.content.length > 0) {\n content.push({ type: \"text\", text: message.content })\n }\n // A refusal is the model declining to answer. It arrives in its own field,\n // NOT in `content`, so ignoring it (as this did) produced an empty but\n // apparently-successful message — the client could not tell a refusal from\n // a model that simply said nothing. Anthropic represents a refusal as text\n // plus `stop_reason: \"refusal\"`, so surface it the same way.\n if (typeof message.refusal === \"string\" && message.refusal.length > 0) {\n content.push({ type: \"text\", text: message.refusal })\n }\n if (Array.isArray(message.tool_calls)) {\n for (const tc of message.tool_calls) {\n sawTool = true\n const rawId = typeof tc.id === \"string\" ? tc.id : \"\"\n content.push({\n type: \"tool_use\",\n id: rawId.length > 0 ? rawId : makeToolUseId(),\n name: typeof tc.function?.name === \"string\" ? tc.function.name : \"\",\n input: parseToolArgs(tc.function?.arguments),\n })\n }\n }\n }\n\n const usage = anthropicUsageFromChat(resp.usage)\n const stopReason = chatStopReason(choice?.finish_reason ?? null, sawTool)\n\n return {\n id: typeof resp.id === \"string\" && resp.id.length > 0 ? `msg_${resp.id}` : makeMessageId(),\n type: \"message\",\n role: \"assistant\",\n model: modelId,\n content,\n stop_reason: stopReason,\n stop_sequence: null,\n usage: {\n input_tokens: usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? 0,\n cache_read_input_tokens: usage.cache_read_input_tokens ?? 0,\n cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// streaming\n// ---------------------------------------------------------------------------\n\n/** Per-tool buffered state; the Anthropic block index is assigned at emit time. */\ninterface ChatToolState {\n id: string\n name: string\n /** Accumulated argument JSON fragments (chat streams args incrementally). */\n args: string\n}\n\n/**\n * Streaming synthesizer: consume a chat/completions SSE iterable, yield the\n * Anthropic event sequence. Emits `message_start` first, streams text live,\n * buffers tool calls per OpenAI array index and flushes them atomically at\n * end-of-stream (in numeric index order), then a terminal `message_delta`\n * (accumulated usage + stop_reason) and `message_stop`. The `[DONE]` sentinel\n * is the authoritative clean-end marker: a stream that ends WITHOUT it is\n * treated as truncated and throws so the stream adapter can emit a terminal\n * `event: error`. A clean `[DONE]` carrying no chunk-level `finish_reason`\n * still completes cleanly (stop_reason from any buffered tool, else `end_turn`).\n */\nexport async function* synthAnthropicFromChat(\n upstream: AsyncIterable<{ data?: string }>,\n opts: { modelId: string; messageId?: string },\n): AsyncGenerator<AnthropicStreamEvent> {\n const messageId = opts.messageId ?? makeMessageId()\n\n let nextIndex = 0\n let activeTextIndex: number | null = null\n // OpenAI array index → buffered tool state (flushed in numeric-index order).\n const toolByIndex = new Map<number, ChatToolState>()\n\n let usageIn = 0\n let usageOut = 0\n let usageCacheRead = 0\n // The last finish_reason seen — informs stop_reason ONLY (null → end_turn).\n let finishReason: string | null = null\n // The `[DONE]` sentinel is the authoritative clean-end marker. A stream that\n // ends WITHOUT it was cut mid-flight (I4) and must NOT be synthesized as a\n // clean success. finish_reason is NOT the signal: Copilot's Gemini path can\n // omit a chunk-level finish_reason on an otherwise-clean stream, so keying the\n // truncation guard off it would falsely error every such stream.\n let sawDone = false\n\n yield makeMessageStart(messageId, opts.modelId)\n\n for await (const evt of upstream) {\n const data = evt?.data\n if (data == null) continue\n if (data === \"[DONE]\") {\n sawDone = true\n break\n }\n\n let chunk: ChatSseChunk\n try {\n chunk = JSON.parse(data) as ChatSseChunk\n } catch {\n continue\n }\n\n // Usage may ride on any chunk (typically a trailing choices-empty chunk).\n // Max-accumulate so a later zeroed frame can't clobber a real count.\n if (chunk.usage) {\n usageIn = Math.max(usageIn, chunk.usage.prompt_tokens ?? 0)\n usageOut = Math.max(usageOut, chunk.usage.completion_tokens ?? 0)\n usageCacheRead = Math.max(\n usageCacheRead,\n chunk.usage.prompt_tokens_details?.cached_tokens ?? 0,\n )\n }\n\n const choice = chunk.choices?.[0]\n if (!choice) continue\n const delta = choice.delta\n\n if (delta && typeof delta.content === \"string\" && delta.content.length > 0) {\n if (activeTextIndex == null) {\n activeTextIndex = nextIndex++\n yield makeContentBlockStart(activeTextIndex, { type: \"text\", text: \"\" })\n }\n yield makeTextDelta(activeTextIndex, delta.content)\n }\n\n // Refusal deltas stream in their own field. Dropping them (as this used to)\n // meant a refused request streamed as literally nothing and terminated as a\n // clean `end_turn` — the client saw an empty successful message. Emit them\n // as text so the user reads why, with `stop_reason: \"refusal\"` on the tail.\n if (delta && typeof delta.refusal === \"string\" && delta.refusal.length > 0) {\n if (activeTextIndex == null) {\n activeTextIndex = nextIndex++\n yield makeContentBlockStart(activeTextIndex, { type: \"text\", text: \"\" })\n }\n yield makeTextDelta(activeTextIndex, delta.refusal)\n }\n\n if (delta && Array.isArray(delta.tool_calls) && delta.tool_calls.length > 0) {\n // A tool_use block must not nest inside an open text block: close the\n // active text block before recording any tool call.\n if (activeTextIndex != null) {\n yield makeContentBlockStop(activeTextIndex)\n activeTextIndex = null\n }\n for (const tcd of delta.tool_calls) {\n if (tcd == null || typeof tcd.index !== \"number\") continue\n let entry = toolByIndex.get(tcd.index)\n if (!entry) {\n entry = { id: \"\", name: \"\", args: \"\" }\n toolByIndex.set(tcd.index, entry)\n }\n if (typeof tcd.id === \"string\" && tcd.id.length > 0) entry.id = tcd.id\n const name = tcd.function?.name\n if (typeof name === \"string\" && name.length > 0) entry.name = name\n const argDelta = tcd.function?.arguments\n if (typeof argDelta === \"string\" && argDelta.length > 0) entry.args += argDelta\n }\n }\n\n if (choice.finish_reason != null) {\n finishReason = choice.finish_reason\n }\n }\n\n if (!sawDone) {\n throw new Error(\"chat stream ended without a [DONE] sentinel (truncated)\")\n }\n\n // Close a still-open text block, then flush the buffered tools atomically in\n // numeric provider-index order (so out-of-order deltas still emit as block\n // 0,1,2…) — each a distinct block index with its full assembled args,\n // sanitized via parseToolArgs so truncated/malformed JSON degrades to `{}`\n // (matching the non-streaming path) instead of shipping bytes an Anthropic\n // client can't JSON.parse at content_block_stop.\n if (activeTextIndex != null) {\n yield makeContentBlockStop(activeTextIndex)\n }\n let sawTool = false\n const orderedTools = [...toolByIndex.entries()].sort((a, b) => a[0] - b[0])\n for (const [, entry] of orderedTools) {\n sawTool = true\n const index = nextIndex++\n const id = entry.id.length > 0 ? entry.id : makeToolUseId()\n yield makeContentBlockStart(index, {\n type: \"tool_use\",\n id,\n name: entry.name,\n input: {},\n })\n yield makeInputJsonDelta(index, JSON.stringify(parseToolArgs(entry.args)))\n yield makeContentBlockStop(index)\n }\n\n const stopReason = chatStopReason(finishReason, sawTool)\n yield makeMessageDelta(stopReason, null, {\n input_tokens: usageIn,\n output_tokens: usageOut,\n cache_read_input_tokens: usageCacheRead,\n cache_creation_input_tokens: 0,\n })\n yield makeMessageStop()\n}\n","/**\n * OpenAI `/responses` → Anthropic Messages egress.\n *\n * - `responsesResponseToAnthropicMessage` maps a non-streaming Responses object\n * to an Anthropic Messages object (content blocks, tool_use, usage,\n * stop_reason).\n * - `synthAnthropicFromResponses` is the streaming state machine: it consumes\n * Copilot's `/responses` SSE and yields Anthropic stream events\n * (message_start → content_block_* → message_delta → message_stop).\n *\n * The decode follows our own empirically-verified `/responses` handling\n * (`src/lib/worker-agent/stream-fn.ts`): the tool/reasoning block key is the\n * STABLE `output_index`, never the per-event `item_id` — Copilot re-encrypts\n * `item_id` on every event, so an id key makes every delta lookup miss and the\n * tool args drop to `{}`.\n *\n * Block lifecycle (mirrors stream-fn.ts): every output item is tracked\n * independently by its `output_index` key. Parallel/interleaved tool calls\n * never force-close a sibling — Responses emits ALL `output_item.added` for\n * parallel tools BEFORE the first `function_call_arguments.delta`, so opening (and\n * emitting) a tool at `added` time would ship it with empty args and drop the\n * later deltas. Instead a tool's args are BUFFERED and its Anthropic block is\n * emitted ATOMICALLY (content_block_start → single input_json_delta with the\n * full assembled args → content_block_stop) at that tool's OWN\n * `output_item.done` (or flushed at end-of-stream if the item was left\n * dangling). Only an open TEXT or THINKING block is closed on a type switch —\n * never a sibling tool. The Anthropic block index is assigned at emit time, so\n * indices stay monotonic on the wire regardless of item interleaving.\n */\n\nimport { randomUUID } from \"node:crypto\"\n\nimport type { ResponsesApiResponse } from \"~/services/copilot/create-responses\"\n\nimport {\n type AnthropicStreamEvent,\n type AnthropicUsage,\n makeContentBlockStart,\n makeContentBlockStop,\n makeInputJsonDelta,\n makeMessageDelta,\n makeMessageId,\n makeMessageStart,\n makeMessageStop,\n makeSignatureDelta,\n makeTextDelta,\n makeThinkingDelta,\n} from \"./anthropic-sse\"\n\ntype AnyRecord = Record<string, unknown>\n\n/** Shape of the `/responses` streaming SSE events we consume (subset). */\ninterface ResponsesSseEvent {\n type?: string\n /** STABLE per-output-item index — the load-bearing correlation key. */\n output_index?: number\n delta?: string\n text?: string\n arguments?: string\n item_id?: string\n item?: {\n type?: string\n id?: string\n call_id?: string\n name?: string\n arguments?: string\n encrypted_content?: string\n summary?: Array<Record<string, unknown>>\n }\n response?: {\n status?: string\n usage?: ResponsesUsage\n incomplete_details?: { reason?: string }\n error?: { message?: string }\n }\n}\n\ninterface ResponsesUsage {\n input_tokens?: number\n output_tokens?: number\n total_tokens?: number\n input_tokens_details?: { cached_tokens?: number }\n}\n\n/**\n * Stable map key for a `/responses` output item: prefer `output_index`\n * (constant per item), fall back to the opaque id only when absent. Namespaced\n * so a numeric index and a string id can never collide.\n */\nfunction responsesKey(\n outputIndex: number | undefined,\n fallbackId: string | undefined,\n): string | undefined {\n if (typeof outputIndex === \"number\") return `oi:${outputIndex}`\n if (typeof fallbackId === \"string\" && fallbackId.length > 0) return `id:${fallbackId}`\n return undefined\n}\n\n/** Synthesize a matchable Anthropic tool_use id when the upstream id is absent. */\nfunction makeToolUseId(): string {\n return `toolu_${randomUUID().replace(/-/g, \"\")}`\n}\n\n/** First non-empty string among the candidates, or \"\" when none qualifies. */\nfunction firstNonEmpty(...vals: Array<string | undefined>): string {\n for (const v of vals) {\n if (typeof v === \"string\" && v.length > 0) return v\n }\n return \"\"\n}\n\nfunction anthropicUsageFromResponses(u: ResponsesUsage | undefined): AnthropicUsage {\n if (!u) return {}\n return {\n input_tokens: u.input_tokens ?? 0,\n output_tokens: u.output_tokens ?? 0,\n cache_read_input_tokens: u.input_tokens_details?.cached_tokens ?? 0,\n cache_creation_input_tokens: 0,\n }\n}\n\nfunction parseToolArgs(raw: unknown): Record<string, unknown> {\n if (typeof raw !== \"string\" || raw.trim().length === 0) return {}\n try {\n const parsed = JSON.parse(raw) as unknown\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>\n }\n } catch {\n // malformed — surface empty args (the model can retry)\n }\n return {}\n}\n\n// ---------------------------------------------------------------------------\n// non-streaming\n// ---------------------------------------------------------------------------\n\n/**\n * The Anthropic Messages object produced from a non-streaming Responses object.\n * Content blocks stay loosely typed (`Record<string, unknown>`) because the\n * block shape is a discriminated union built inline; the top-level envelope and\n * usage are pinned so callers read them without a cast.\n */\ninterface AnthropicMessageResult {\n id: string\n type: \"message\"\n role: \"assistant\"\n model: string\n content: Array<Record<string, unknown>>\n stop_reason: string\n stop_sequence: null\n usage: {\n input_tokens: number\n output_tokens: number\n cache_read_input_tokens: number\n cache_creation_input_tokens: number\n }\n}\n\n/**\n * Map a non-streaming Responses object to an Anthropic Messages object.\n *\n * stop_reason precedence for a completed non-streaming response:\n * an incomplete/max-output response is `max_tokens` even if a partial tool call\n * is present (the response was truncated), else a function_call → `tool_use`,\n * else `end_turn`.\n */\nexport function responsesResponseToAnthropicMessage(\n resp: ResponsesApiResponse,\n modelId: string,\n): AnthropicMessageResult {\n const output = Array.isArray(resp.output) ? resp.output : []\n const content: Array<AnyRecord> = []\n let sawToolUse = false\n\n for (const rawItem of output) {\n if (!rawItem || typeof rawItem !== \"object\") continue\n const item = rawItem as AnyRecord\n\n if (item.type === \"message\") {\n let text = \"\"\n if (Array.isArray(item.content)) {\n for (const part of item.content) {\n if (part && typeof part === \"object\" && part.type === \"output_text\" && typeof part.text === \"string\") {\n text += part.text\n }\n }\n }\n if (text.length > 0) content.push({ type: \"text\", text })\n } else if (item.type === \"function_call\") {\n sawToolUse = true\n // S12: a missing/empty upstream id would leave `tool_use.id` as \"\"\n // (unmatchable by the paired tool_result); synthesize a `toolu_` id.\n const rawId =\n typeof item.call_id === \"string\" && item.call_id.length > 0 ? item.call_id\n : typeof item.id === \"string\" && item.id.length > 0 ? item.id\n : \"\"\n content.push({\n type: \"tool_use\",\n id: rawId.length > 0 ? rawId : makeToolUseId(),\n name: typeof item.name === \"string\" ? item.name : \"\",\n input: parseToolArgs(item.arguments),\n })\n } else if (item.type === \"reasoning\") {\n let thinking = \"\"\n if (Array.isArray(item.summary)) {\n for (const part of item.summary) {\n if (part && typeof part === \"object\" && typeof part.text === \"string\") thinking += part.text\n }\n }\n if (thinking.length > 0) {\n content.push({\n type: \"thinking\",\n thinking,\n signature: typeof item.encrypted_content === \"string\" ? item.encrypted_content : \"\",\n })\n }\n }\n }\n\n const usage = anthropicUsageFromResponses((resp as AnyRecord).usage as ResponsesUsage)\n const incompleteMax =\n resp.status === \"incomplete\"\n && (resp.incomplete_details as { reason?: string } | undefined)?.reason\n === \"max_output_tokens\"\n const stopReason = incompleteMax ? \"max_tokens\" : sawToolUse ? \"tool_use\" : \"end_turn\"\n\n return {\n id: typeof resp.id === \"string\" && resp.id.length > 0 ? `msg_${resp.id}` : makeMessageId(),\n type: \"message\",\n role: \"assistant\",\n model: modelId,\n content,\n stop_reason: stopReason,\n stop_sequence: null,\n usage: {\n input_tokens: usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? 0,\n cache_read_input_tokens: usage.cache_read_input_tokens ?? 0,\n cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// streaming\n// ---------------------------------------------------------------------------\n\ntype OpenBlockKind = \"text\" | \"thinking\"\n\n/** Per-tool buffered state; the Anthropic block index is assigned at emit time. */\ninterface ToolState {\n id: string\n name: string\n /** Accumulated argument JSON (deltas appended; `.done` overwrites). */\n argsBuffer: string\n /** Whether the atomic tool block has been emitted. */\n emitted: boolean\n}\n\n/** Per-text-block state, keyed by `output_index`, tracking what was emitted. */\ninterface TextState {\n index: number\n /** Text already sent as `text_delta` for this block (for suffix-only `.done`). */\n emitted: string\n}\n\n/**\n * Streaming synthesizer: consume a `/responses` SSE iterable, yield the\n * Anthropic event sequence. Emits `message_start` first, then content blocks in\n * item order, then a terminal `message_delta` (accumulated usage + stop_reason)\n * and `message_stop`. A `response.failed` throws so the stream adapter can emit\n * a terminal `event: error`; a stream that ends WITHOUT a terminal event\n * (`completed`/`incomplete`/`failed`) is treated as truncated and throws too.\n */\nexport async function* synthAnthropicFromResponses(\n upstream: AsyncIterable<{ data?: string }>,\n opts: { modelId: string; messageId?: string },\n): AsyncGenerator<AnthropicStreamEvent> {\n const messageId = opts.messageId ?? makeMessageId()\n const q: Array<AnthropicStreamEvent> = []\n\n let nextIndex = 0\n // The single OPEN text/thinking block (tools never occupy `current` — they\n // are emitted atomically and never stay open). At most one open at a time.\n let current: { index: number; kind: OpenBlockKind } | null = null\n // output-index key → buffered tool state.\n const toolByKey = new Map<string, ToolState>()\n // output-index key → thinking block index (reuse across reasoning deltas +\n // signature lookup at the reasoning item's `output_item.done`).\n const thinkingByKey = new Map<string, number>()\n // output-index key → text block state (index + emitted text, for I5).\n const textByKey = new Map<string, TextState>()\n\n let usageIn = 0\n let usageOut = 0\n let usageCacheRead = 0\n let sawTool = false\n let hitMaxTokens = false\n // I4: a terminal event (`completed`/`incomplete`/`failed`) was seen. If the\n // upstream iterable ends without one, the stream was truncated mid-flight and\n // must NOT be synthesized as a clean, successful message.\n let sawTerminal = false\n\n const closeCurrent = (): void => {\n if (!current) return\n q.push(makeContentBlockStop(current.index))\n current = null\n }\n // Accessors read `current` inside a closure so it keeps its declared type at\n // the loop-body call sites (a bare `let` assigned only inside closures reads\n // as `null` under TS linear control-flow, which would make `.kind`/`.index`\n // resolve to `never`).\n const currentKind = (): OpenBlockKind | null => (current ? current.kind : null)\n const currentIndex = (): number | null => (current ? current.index : null)\n\n const ensureTextState = (key: string): TextState => {\n const existing = textByKey.get(key)\n if (existing != null && current?.kind === \"text\" && current.index === existing.index) {\n return existing\n }\n // A closed (or never-opened) block cannot be reopened at the same index —\n // a type switch already closed it. Open a fresh block with a new index.\n closeCurrent()\n const index = nextIndex++\n const state: TextState = { index, emitted: \"\" }\n textByKey.set(key, state)\n current = { index, kind: \"text\" }\n q.push(makeContentBlockStart(index, { type: \"text\", text: \"\" }))\n return state\n }\n const ensureThinking = (key: string): number => {\n if (current?.kind === \"thinking\" && thinkingByKey.get(key) === current.index) {\n return current.index\n }\n closeCurrent()\n const index = nextIndex++\n current = { index, kind: \"thinking\" }\n thinkingByKey.set(key, index)\n q.push(makeContentBlockStart(index, { type: \"thinking\", thinking: \"\" }))\n return index\n }\n // Tool arguments are BUFFERED, not forwarded live: `function_call_arguments.done`\n // / `output_item.done` carry the AUTHORITATIVE full args and overwrite the\n // accumulated deltas (Copilot can send a corrupted/partial delta stream). The\n // whole tool block is emitted atomically here so a parallel sibling tool can\n // never truncate it. A streamed protocol can't retract an already-emitted\n // `input_json_delta`, so the authoritative args go out as one delta at emit.\n const emitTool = (t: ToolState): void => {\n if (t.emitted) return\n // Close the open text/thinking block first — a tool_use block must not be\n // nested inside another open block on the wire.\n closeCurrent()\n const index = nextIndex++\n q.push(makeContentBlockStart(index, { type: \"tool_use\", id: t.id, name: t.name, input: {} }))\n const args = t.argsBuffer.length > 0 ? t.argsBuffer : \"{}\"\n q.push(makeInputJsonDelta(index, args))\n q.push(makeContentBlockStop(index))\n t.emitted = true\n sawTool = true\n }\n\n // message_start is emitted eagerly (real input_tokens aren't known until the\n // terminal usage event; they're reported in the final message_delta).\n q.push(makeMessageStart(messageId, opts.modelId))\n for (const e of q) yield e\n q.length = 0\n\n for await (const evt of upstream) {\n const data = evt?.data\n if (data == null) continue\n if (data === \"[DONE]\") break\n\n let ev: ResponsesSseEvent\n try {\n ev = JSON.parse(data) as ResponsesSseEvent\n } catch {\n continue\n }\n\n switch (ev.type) {\n case \"response.output_text.delta\": {\n const d = ev.delta\n if (typeof d !== \"string\" || d.length === 0) break\n const key = responsesKey(ev.output_index, ev.item_id) ?? \"text\"\n const state = ensureTextState(key)\n state.emitted += d\n q.push(makeTextDelta(state.index, d))\n break\n }\n\n case \"response.output_text.done\": {\n const key = responsesKey(ev.output_index, ev.item_id) ?? \"text\"\n const fullText = typeof ev.text === \"string\" ? ev.text : \"\"\n const existing = textByKey.get(key)\n if (existing == null) {\n // No deltas were emitted for this key — emit the full text as its own\n // block (this is the only carrier of the text).\n if (fullText.length > 0) {\n const state = ensureTextState(key)\n state.emitted = fullText\n q.push(makeTextDelta(state.index, fullText))\n closeCurrent()\n }\n } else if (currentKind() === \"text\" && currentIndex() === existing.index) {\n // I5: deltas already streamed this text; emit ONLY the un-emitted\n // suffix (never the full text again), then close. If `.done` merely\n // repeats what the deltas already sent, the suffix is empty.\n if (fullText.length > existing.emitted.length && fullText.startsWith(existing.emitted)) {\n q.push(makeTextDelta(existing.index, fullText.slice(existing.emitted.length)))\n existing.emitted = fullText\n }\n closeCurrent()\n }\n // else: this key's block was already closed by a type switch — the\n // deltas already conveyed the text, so re-emitting would duplicate (I5).\n break\n }\n\n case \"response.reasoning_summary_text.delta\":\n case \"response.reasoning_text.delta\": {\n const d = ev.delta\n if (typeof d !== \"string\" || d.length === 0) break\n const key = responsesKey(ev.output_index, ev.item_id) ?? \"reasoning\"\n q.push(makeThinkingDelta(ensureThinking(key), d))\n break\n }\n\n case \"response.reasoning_summary_text.done\":\n case \"response.reasoning_text.done\": {\n // C2: do NOT close the thinking block here. The block stays open so its\n // `signature_delta` (from `output_item.done{reasoning, encrypted_content}`)\n // can still be emitted into the open block. It is closed by the next\n // block's type switch, the reasoning `output_item.done`, or end-of-stream.\n break\n }\n\n case \"response.output_item.added\": {\n const item = ev.item\n if (item?.type === \"function_call\") {\n const key = responsesKey(ev.output_index, item.id)\n if (key == null || toolByKey.has(key)) break\n // C1: DO NOT open/emit the tool block here. Responses emits every\n // parallel tool's `added` before the first args delta; opening now would\n // force-close the sibling and ship empty args. Just record the tool;\n // its block is emitted atomically at its own `output_item.done`.\n // S12: an empty/missing upstream id must not become `tool_use.id: \"\"`\n // (unmatchable by the paired tool_result) — synthesize a `toolu_` id.\n const toolId = firstNonEmpty(item.call_id, item.id)\n toolByKey.set(key, {\n id: toolId.length > 0 ? toolId : makeToolUseId(),\n name: item.name ?? \"\",\n argsBuffer: \"\",\n emitted: false,\n })\n sawTool = true\n }\n // message / reasoning items open lazily on their first delta.\n break\n }\n\n case \"response.function_call_arguments.delta\": {\n const key = responsesKey(ev.output_index, ev.item_id)\n if (key == null) break\n const t = toolByKey.get(key)\n if (!t || t.emitted) break\n const d = ev.delta\n if (typeof d !== \"string\" || d.length === 0) break\n // Accumulate into the buffer; emission is deferred to the tool's done.\n t.argsBuffer += d\n break\n }\n\n case \"response.function_call_arguments.done\": {\n // Authoritative full args — overwrite the accumulated deltas (they may\n // have been corrupted/partial). Emission still happens at done.\n const key = responsesKey(ev.output_index, ev.item_id)\n if (key == null) break\n const t = toolByKey.get(key)\n if (!t || t.emitted) break\n if (typeof ev.arguments === \"string\") t.argsBuffer = ev.arguments\n break\n }\n\n case \"response.output_item.done\": {\n const item = ev.item\n if (item?.type === \"function_call\") {\n const key = responsesKey(ev.output_index, item.id)\n if (key == null) break\n const t = toolByKey.get(key)\n if (!t || t.emitted) break\n // Authoritative final view of the item overwrites the buffer and\n // backfills id/name, then the tool block is emitted atomically. Only a\n // non-empty id overwrites, so a synthesized `toolu_` id survives a\n // `.done` that still lacks a real id (S12).\n const doneId = firstNonEmpty(item.call_id, item.id)\n if (doneId.length > 0) t.id = doneId\n if (typeof item.name === \"string\" && item.name.length > 0) t.name = item.name\n if (typeof item.arguments === \"string\") t.argsBuffer = item.arguments\n emitTool(t)\n } else if (item?.type === \"reasoning\") {\n // If the reasoning item carries an encrypted signature and its\n // thinking block is still open, emit a signature_delta before closing.\n const key = responsesKey(ev.output_index, item.id)\n const idx = key != null ? thinkingByKey.get(key) : undefined\n if (\n idx != null\n && currentKind() === \"thinking\"\n && currentIndex() === idx\n ) {\n if (typeof item.encrypted_content === \"string\" && item.encrypted_content.length > 0) {\n q.push(makeSignatureDelta(idx, item.encrypted_content))\n }\n closeCurrent()\n }\n }\n break\n }\n\n case \"response.completed\":\n case \"response.incomplete\": {\n sawTerminal = true\n const u = ev.response?.usage\n if (u) {\n usageIn = Math.max(usageIn, u.input_tokens ?? 0)\n usageOut = Math.max(usageOut, u.output_tokens ?? 0)\n usageCacheRead = Math.max(usageCacheRead, u.input_tokens_details?.cached_tokens ?? 0)\n }\n if (\n ev.type === \"response.incomplete\"\n && ev.response?.incomplete_details?.reason === \"max_output_tokens\"\n ) {\n hitMaxTokens = true\n }\n break\n }\n\n case \"response.failed\": {\n // A terminal failure — the stream adapter turns this throw into a\n // terminal `event: error`. (sawTerminal is moot: we exit via throw.)\n throw new Error(ev.response?.error?.message ?? \"response.failed\")\n }\n\n default:\n break\n }\n\n for (const e of q) yield e\n q.length = 0\n }\n\n // I4: the loop ended. If NO terminal event was seen the upstream was\n // truncated mid-stream (`fetch-event-stream`'s `events()` returns-done on a\n // clean-but-premature EOF rather than throwing). Surface it as a terminal\n // error instead of a clean, successful message_stop — the stream adapter\n // converts this throw into a terminal `event: error`.\n if (!sawTerminal) {\n throw new Error(\"responses stream ended without a terminal event (truncated)\")\n }\n\n // Close the current text/thinking block, then flush the tool blocks the\n // stream left dangling (no `output_item.done`) so their buffered args aren't\n // lost. emitTool closes `current` first, so ordering stays correct.\n closeCurrent()\n for (const t of toolByKey.values()) {\n if (!t.emitted) emitTool(t)\n }\n // stop_reason precedence: a truncated (max-output) response is `max_tokens`\n // even with a partial tool call; else a tool call → `tool_use`; else end_turn.\n const stopReason = hitMaxTokens ? \"max_tokens\" : sawTool ? \"tool_use\" : \"end_turn\"\n q.push(\n makeMessageDelta(stopReason, null, {\n input_tokens: usageIn,\n output_tokens: usageOut,\n cache_read_input_tokens: usageCacheRead,\n cache_creation_input_tokens: 0,\n }),\n )\n q.push(makeMessageStop())\n for (const e of q) yield e\n q.length = 0\n}\n","/**\n * Routing classifier for `POST /v1/messages`.\n *\n * Claude Code speaks the Anthropic Messages wire format. Copilot only serves\n * Claude models on its native `/v1/messages` endpoint; a gpt/gemini request\n * sent there 400s. This classifier decides, from the RESOLVED model id and its\n * catalog metadata, whether a request stays on the native passthrough\n * (`createMessages`) or is diverted to the translation shim.\n *\n * Non-regression is the whole point — every Claude model (opus / sonnet / haiku /\n * any `claude-*` or Anthropic-vendored id) MUST return \"claude-passthrough\" so\n * its bytes reach `createMessages` unchanged — even if future catalog metadata\n * were to (wrongly) advertise a `/responses` endpoint for it. The Claude check\n * is therefore keyed off identity (id / vendor / family), NOT the endpoint.\n *\n * Non-Claude models are diverted to the translation shim by the endpoint the\n * catalog says they serve: `/responses` models (gpt-5.5, gpt-5.3-codex, …) take\n * the Responses path (`responses-shim`), `/chat/completions` models (gemini,\n * and any chat-default model) take the chat path (`chat-shim`). The decision is\n * derived from `pickEndpoint` (catalog `supported_endpoints`), never a\n * hardcoded slug list, so it generalizes. Copilot only serves Claude models on\n * its native `/v1/messages`, so diverting every non-Claude model to a shim is\n * correct — a non-Claude request sent to `/v1/messages` would 400.\n */\n\nimport { pickEndpoint } from \"~/services/copilot/endpoint\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\nexport type MessagesRoute = \"claude-passthrough\" | \"responses-shim\" | \"chat-shim\"\n\n/**\n * Match \"claude\"/\"anthropic\" as a delimiter-bounded segment anywhere in a model\n * id: at the start, or after a `/ _ . : -` path/version delimiter, and followed\n * by end-of-string, another such delimiter, or a digit. This catches catalog\n * aliases like `github/claude-3-7-sonnet` or `anthropic/…` whose vendor is\n * \"github\" and whose family is empty — where the token only surfaces mid-id —\n * while NOT firing on incidental substrings like `notclaude`. Deliberately\n * over-inclusive at the boundaries: we fail CLOSED toward Claude (→ passthrough)\n * so a real Claude model can never be diverted to the non-Claude shim.\n */\nconst CLAUDE_ID_RE = /(^|[/_.:-])(claude|anthropic)(?=$|[/_.:-]|\\d)/i\n\n/**\n * True when the target is a Claude / Anthropic model. Matches on any of:\n * catalog vendor containing \"anthropic\", capability family containing \"claude\",\n * or a Claude/anthropic path-segment (see `CLAUDE_ID_RE`) in ANY id we hold —\n * the resolved id (`modelId`), the pre-resolution request id (`originalModelId`),\n * or the catalog entry's own id (`model.id`). Conservative by design: when in\n * doubt it returns true so a Claude request can never be diverted to the shim.\n */\nexport function isClaudeModel(\n modelId: string | undefined,\n model?: Model,\n originalModelId?: string,\n): boolean {\n if (model) {\n const vendor = model.vendor?.toLowerCase() ?? \"\"\n if (vendor.includes(\"anthropic\")) return true\n const family = model.capabilities?.family?.toLowerCase() ?? \"\"\n if (family.includes(\"claude\")) return true\n }\n return [modelId, originalModelId, model?.id].some(\n (id) => typeof id === \"string\" && CLAUDE_ID_RE.test(id),\n )\n}\n\n/**\n * Decide the route for a resolved model id + its catalog entry.\n *\n * - No model id, or a Claude model → \"claude-passthrough\" (existing behaviour).\n * - A non-Claude model whose catalog endpoint is `/responses` → \"responses-shim\".\n * - A non-Claude model whose catalog endpoint is `/chat/completions` (gemini and\n * any chat-default model) → \"chat-shim\".\n * - A non-Claude model absent from the catalog (so we can't confirm an endpoint)\n * → \"claude-passthrough\" (unchanged; we don't divert what we can't classify).\n * - A non-Claude model that IS in the catalog and serves NEITHER of the two shim\n * endpoints (`pickEndpoint` → undefined) → \"claude-passthrough\" as well.\n *\n * Those last two land on the same route but are NOT the same answer, and the\n * coincidence is deliberate rather than a collapsed default (contrast\n * `resolveEndpointForModelId`, whose callers must tell them apart because\n * guessing there produces an opaque upstream 400). Here neither shim is even a\n * candidate: a shim can only speak `/responses` or `/chat/completions`, so\n * diverting a model that serves neither would 400 just as surely. Passthrough\n * is the better default because it is sometimes RIGHT — a non-Claude catalog\n * model advertising `/v1/messages` is served by exactly the endpoint\n * passthrough uses. It also preserves this module's fail-CLOSED-toward-Claude\n * invariant: an unclassifiable model is never diverted.\n *\n * KNOWN GAP (audited, deliberately not fixed here): a non-Claude model serving\n * only something we cannot speak at all (say `/embeddings`) also lands on\n * passthrough and will still 400 upstream — `logEndpointMismatch(modelId,\n * \"/v1/messages\")` logs it at the passthrough seam, but no local error is\n * raised. Closing that needs a change in `src/routes/messages/handler.ts`,\n * which this seam does not own. It is strictly narrower than the defect fixed\n * in `resolveEndpointForModelId`: no such model is reachable as a Claude Code\n * `/v1/messages` target today, whereas the plan worker's `claude-opus-5`\n * default is.\n *\n * `originalModelId` is the optional pre-resolution request id; when supplied it\n * is checked for Claude-likeness alongside the resolved id so an alias that\n * resolves to a non-Claude-looking id can't slip past.\n */\nexport function classifyMessagesRoute(\n modelId: string | undefined,\n model?: Model,\n originalModelId?: string,\n): MessagesRoute {\n if (!modelId) return \"claude-passthrough\"\n if (isClaudeModel(modelId, model, originalModelId)) return \"claude-passthrough\"\n if (!model) return \"claude-passthrough\"\n const endpoint = pickEndpoint(model)\n if (endpoint === \"responses\") return \"responses-shim\"\n if (endpoint === \"chat\") return \"chat-shim\"\n return \"claude-passthrough\"\n}\n","/**\n * Entry point for the non-Claude Anthropic-translation shim.\n *\n * `handleNonClaudeResponses` is the diversion `POST /v1/messages` takes when the\n * resolved model is a non-Claude `/responses` model (gpt-5.5, gpt-5.3-codex);\n * `handleNonClaudeChat` is the twin for a non-Claude `/chat/completions` model\n * (gemini). Each translates the Anthropic Messages request into the matching\n * Copilot request, calls the existing streaming-capable client, and translates\n * the response back to the Anthropic wire shape — streaming (synthesized SSE) or\n * non-streaming (a single Anthropic Messages object), per the request's\n * `stream` flag.\n *\n * The Claude passthrough (`createMessages`) is untouched: this module is only\n * reached via `classifyMessagesRoute(...)` returning `responses-shim` /\n * `chat-shim`.\n */\n\nimport type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { logRequest } from \"~/lib/request-log\"\nimport { createChatCompletions } from \"~/services/copilot/create-chat-completions\"\nimport type { ChatCompletionResponse } from \"~/services/copilot/create-chat-completions\"\nimport { createResponses } from \"~/services/copilot/create-responses\"\nimport type { ResponsesApiResponse } from \"~/services/copilot/create-responses\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\nimport { anthropicSseStreamFromEvents } from \"./anthropic-sse\"\nimport {\n parseAnthropicRequest,\n parsedToResponsesPayload,\n} from \"./anthropic-request\"\nimport { parsedToChatPayload } from \"./chat-request\"\nimport {\n chatResponseToAnthropicMessage,\n synthAnthropicFromChat,\n} from \"./chat-egress\"\nimport {\n responsesResponseToAnthropicMessage,\n synthAnthropicFromResponses,\n} from \"./responses-egress\"\n\ntype AnyRecord = Record<string, unknown>\n\nexport { classifyMessagesRoute, isClaudeModel } from \"./classifier\"\nexport type { MessagesRoute } from \"./classifier\"\n\n/** Shared options for both non-Claude shim entry points. */\nexport interface NonClaudeShimOptions {\n /** The resolved request body (post model-resolution), as a JSON string. */\n rawBody: string\n /** The resolved Copilot catalog model id the request runs on. */\n modelId: string\n /** The catalog entry (for request headers + reasoning-effort allowlist). */\n model?: Model\n /** The model id the client originally sent (for logging). */\n originalModel?: string\n startTime: number\n}\n\n/** Back-compat alias (the Responses handler predates the shared name). */\nexport type NonClaudeResponsesOptions = NonClaudeShimOptions\n\nconst STREAM_HEADERS: Record<string, string> = {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n \"transfer-encoding\": \"chunked\",\n connection: \"keep-alive\",\n}\n\nfunction isAsyncIterable(x: unknown): x is AsyncIterable<{ data?: string }> {\n return (\n x != null\n && typeof (x as AsyncIterable<unknown>)[Symbol.asyncIterator] === \"function\"\n )\n}\n\n/**\n * Handle a `/v1/messages` request targeting a non-Claude `/responses` model.\n * Returns a streaming or non-streaming Anthropic-format Response. Upstream\n * non-2xx / abort errors are thrown (as HTTPError) and handled by the route's\n * `forwardError`, exactly like the passthrough path.\n */\nexport async function handleNonClaudeResponses(\n c: Context,\n opts: NonClaudeResponsesOptions,\n): Promise<Response> {\n const routePath = c.req.path\n\n let body: AnyRecord\n try {\n body = JSON.parse(opts.rawBody) as AnyRecord\n } catch {\n return c.json(\n {\n type: \"error\",\n error: { type: \"invalid_request_error\", message: \"Request body is not valid JSON\" },\n },\n 400,\n )\n }\n\n const parsed = parseAnthropicRequest(body, opts.modelId, opts.model)\n const payload = parsedToResponsesPayload(parsed)\n\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\n `Anthropic-translate → /responses model=${opts.modelId} stream=${parsed.stream} `\n + `tools=${parsed.tools?.length ?? 0} effort=${parsed.reasoningEffort ?? \"none\"}`,\n )\n }\n\n if (parsed.stream) {\n // Compose a caller-controlled aborter so consumer-cancel tears down the\n // upstream fetch. Do NOT use c.req.raw.signal (Bun aborts it after body\n // consumption — see CLAUDE.md \"Bun request-signal quirk\").\n const aborter = new AbortController()\n // retryTransient: true — pre-first-byte transient retry. The SSE body is\n // iterated by the synthesizer below, not inside createResponses, so a\n // re-issue cannot duplicate already-streamed output.\n const result = await createResponses(\n payload,\n opts.model?.requestHeaders,\n aborter.signal,\n true,\n )\n if (!isAsyncIterable(result)) {\n throw new Error(\"Upstream /responses did not return an SSE stream (stream: true expected)\")\n }\n\n logRequest(\n {\n method: \"POST\",\n path: routePath,\n model: opts.originalModel,\n resolvedModel: opts.modelId,\n status: 200,\n streaming: true,\n },\n opts.model,\n opts.startTime,\n )\n\n const events = synthAnthropicFromResponses(result, { modelId: opts.modelId })\n const stream = anthropicSseStreamFromEvents(events, {\n routePath,\n onCancel: () => aborter.abort(),\n })\n return new Response(stream, { status: 200, headers: STREAM_HEADERS })\n }\n\n // Non-streaming. The upstream fetch is NOT consumer-abortable here and\n // completes regardless — matching the repo's documented pattern (streaming\n // tears down via ReadableStream.cancel(); non-streaming is a no-op on\n // consumer cancel). c.req.raw.signal is unusable (Bun aborts it once the\n // request body is consumed — already done in handleCompletion via\n // c.req.text(); see CLAUDE.md \"Bun request-signal quirk\"), and a bare\n // AbortController would never fire (no cancel hook for a buffered response),\n // so we pass no signal rather than an inert one that implies cancellation.\n const result = await createResponses(\n payload,\n opts.model?.requestHeaders,\n undefined,\n true,\n )\n const anthropic = responsesResponseToAnthropicMessage(\n result as ResponsesApiResponse,\n opts.modelId,\n )\n\n logRequest(\n {\n method: \"POST\",\n path: routePath,\n model: opts.originalModel,\n resolvedModel: opts.modelId,\n inputTokens: anthropic.usage.input_tokens,\n outputTokens: anthropic.usage.output_tokens,\n status: 200,\n },\n opts.model,\n opts.startTime,\n )\n\n return c.json(anthropic, 200)\n}\n\n/**\n * Handle a `/v1/messages` request targeting a non-Claude `/chat/completions`\n * model (gemini). Twin of `handleNonClaudeResponses` — same lifecycle, abort,\n * and logging contract, but assembles a chat/completions payload and translates\n * the chat response (object or SSE) back to the Anthropic wire shape.\n */\nexport async function handleNonClaudeChat(\n c: Context,\n opts: NonClaudeShimOptions,\n): Promise<Response> {\n const routePath = c.req.path\n\n let body: AnyRecord\n try {\n body = JSON.parse(opts.rawBody) as AnyRecord\n } catch {\n return c.json(\n {\n type: \"error\",\n error: { type: \"invalid_request_error\", message: \"Request body is not valid JSON\" },\n },\n 400,\n )\n }\n\n const parsed = parseAnthropicRequest(body, opts.modelId, opts.model)\n const payload = parsedToChatPayload(parsed)\n\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\n `Anthropic-translate → /chat/completions model=${opts.modelId} stream=${parsed.stream} `\n + `tools=${parsed.tools?.length ?? 0} effort=${parsed.reasoningEffort ?? \"none\"}`,\n )\n }\n\n if (parsed.stream) {\n // Caller-controlled aborter so consumer-cancel tears down the upstream\n // fetch. Do NOT use c.req.raw.signal (Bun aborts it after body consumption\n // — see CLAUDE.md \"Bun request-signal quirk\"). retryTransient: true — the\n // SSE body is iterated by the synthesizer below, not inside\n // createChatCompletions, so a pre-first-byte re-issue can't duplicate output.\n const aborter = new AbortController()\n const result = await createChatCompletions(\n payload,\n opts.model?.requestHeaders,\n aborter.signal,\n true,\n )\n if (!isAsyncIterable(result)) {\n throw new Error(\n \"Upstream /chat/completions did not return an SSE stream (stream: true expected)\",\n )\n }\n\n logRequest(\n {\n method: \"POST\",\n path: routePath,\n model: opts.originalModel,\n resolvedModel: opts.modelId,\n status: 200,\n streaming: true,\n },\n opts.model,\n opts.startTime,\n )\n\n const events = synthAnthropicFromChat(result, { modelId: opts.modelId })\n const stream = anthropicSseStreamFromEvents(events, {\n routePath,\n onCancel: () => aborter.abort(),\n })\n return new Response(stream, { status: 200, headers: STREAM_HEADERS })\n }\n\n // Non-streaming: not consumer-abortable (see the Responses twin above and\n // CLAUDE.md \"Bun request-signal quirk\"); the upstream fetch completes\n // regardless. Pass no signal rather than an inert AbortController.\n const result = await createChatCompletions(\n payload,\n opts.model?.requestHeaders,\n undefined,\n true,\n )\n const anthropic = chatResponseToAnthropicMessage(\n result as ChatCompletionResponse,\n opts.modelId,\n )\n\n logRequest(\n {\n method: \"POST\",\n path: routePath,\n model: opts.originalModel,\n resolvedModel: opts.modelId,\n inputTokens: anthropic.usage.input_tokens,\n outputTokens: anthropic.usage.output_tokens,\n status: 200,\n },\n opts.model,\n opts.startTime,\n )\n\n return c.json(anthropic, 200)\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport {\n classifyMessagesRoute,\n handleNonClaudeChat,\n handleNonClaudeResponses,\n} from \"~/lib/anthropic-translate\"\nimport { HTTPError } from \"~/lib/error\"\nimport { logEndpointMismatch } from \"~/lib/model-validation\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { EFFORT_ORDER, UNKNOWN_EFFORT_ANCHOR, bucketEffort, clampEffort } from \"~/lib/reasoning-effort\"\nimport { logRequest, logRequestFields } from \"~/lib/request-log\"\nimport { MAX_RESPONSE_BODY_BYTES, readResponseBodyCapped } from \"~/lib/response-cap\"\nimport { sanitizeAnthropicBody } from \"~/lib/sanitize-anthropic-body\"\nimport { state } from \"~/lib/state\"\nimport { relayAnthropicStream } from \"~/lib/stream-relay\"\nimport { filterBetaHeader, resolveModel } from \"~/lib/utils\"\nimport {\n ADVISOR_INTERNAL_TOOL_NAME,\n buildAdvisorStream,\n injectAdvisorTool,\n isAdvisorRequested,\n} from \"~/services/advisor/advisor\"\nimport { createMessages } from \"~/services/copilot/create-messages\"\nimport type { Model } from \"~/services/copilot/get-models\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\ntype AnyRecord = Record<string, unknown>\n\nconst isWebSearchTool = (tool: AnyRecord): boolean =>\n !!tool\n && typeof tool === \"object\"\n && ((typeof tool.type === \"string\" && tool.type.startsWith(\"web_search\"))\n || tool.name === \"web_search\")\n\n/**\n * Extract whitelisted beta headers from the incoming request to forward\n * to the Copilot API. VS Code sends these to enable extended features\n * like thinking, context management, and advanced tool use.\n */\nfunction extractBetaHeaders(c: Context): Record<string, string> {\n const headers: Record<string, string> = {}\n const anthropicBeta = c.req.header(\"anthropic-beta\")\n if (anthropicBeta) {\n const filtered = filterBetaHeader(anthropicBeta)\n if (filtered) headers[\"anthropic-beta\"] = filtered\n }\n return headers\n}\n\n/**\n * Extract the text content from the last user message for web search.\n * Handles both string content and content block arrays (multimodal).\n */\nfunction extractUserQuery(\n messages: Array<AnyRecord>,\n): string | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") return msg.content\n if (Array.isArray(msg.content)) {\n const textBlock = msg.content.find(\n (block: AnyRecord) => block.type === \"text\",\n )\n if (textBlock?.text) return textBlock.text as string\n }\n }\n }\n return undefined\n}\n\n/**\n * Check if any user message contains tool_result content blocks,\n * indicating a follow-up turn where we should skip web search.\n * In Anthropic format, tool results are content blocks inside user messages,\n * NOT separate role: \"tool\" messages like in OpenAI format.\n */\nfunction hasToolResultContent(messages: Array<AnyRecord>): boolean {\n return messages.some(\n (msg) =>\n Array.isArray(msg.content) &&\n msg.content.some(\n (block: AnyRecord) => block.type === \"tool_result\",\n ),\n )\n}\n\n/**\n * Inject web search results into the Anthropic system field.\n * Handles three cases: absent, string, or array of content blocks.\n * When array, prepends without cache_control to preserve existing directives.\n */\nfunction injectSearchResults(\n body: AnyRecord,\n searchContext: string,\n): void {\n if (body.system === undefined || body.system === null) {\n body.system = searchContext\n } else if (typeof body.system === \"string\") {\n body.system = `${searchContext}\\n\\n${body.system}`\n } else if (Array.isArray(body.system)) {\n body.system = [\n { type: \"text\", text: searchContext },\n ...body.system,\n ]\n }\n}\n\n/**\n * Strip web_search tools from the request and clean up tool_choice.\n * Returns the modified body object.\n */\nfunction stripWebSearchTool(body: AnyRecord): void {\n if (!body.tools) return\n\n const tools = (body.tools as Array<AnyRecord>).filter(\n (tool: AnyRecord) => !isWebSearchTool(tool),\n )\n body.tools = tools\n\n if (tools.length === 0) {\n body.tools = undefined\n body.tool_choice = undefined\n } else if (\n body.tool_choice &&\n typeof body.tool_choice === \"object\" &&\n (body.tool_choice as AnyRecord).type === \"tool\"\n ) {\n // If tool_choice forced the removed web_search tool, fall back to auto\n const choiceName = (body.tool_choice as AnyRecord).name\n if (\n choiceName &&\n !tools.some(\n (tool: AnyRecord) =>\n tool && typeof tool === \"object\" && tool.name === choiceName,\n )\n ) {\n body.tool_choice = { type: \"auto\" }\n }\n }\n}\n\n/**\n * Strip the injected `__anthropic_advisor` tool (and any Anthropic-native\n * `advisor_*` typed tool) from a request body. Used ONLY on the non-Claude\n * shim path: ADVISOR's server-side translate-loop (buildAdvisorStream) lives\n * on the native /v1/messages route, so a non-Claude model has no handler for\n * the tool and it must be removed before forwarding — otherwise the model\n * could emit a tool_use that nothing fulfils. Mirrors stripWebSearchTool's\n * tool_choice cleanup. Returns the original string (same reference) when\n * nothing was removed.\n */\nfunction stripAdvisorTool(rawBody: string): string {\n let body: AnyRecord\n try {\n body = JSON.parse(rawBody)\n } catch {\n return rawBody\n }\n if (!Array.isArray(body.tools)) return rawBody\n const original = body.tools as Array<AnyRecord>\n const tools = original.filter((tool: AnyRecord) => {\n if (typeof tool !== \"object\" || tool === null) return true\n if (tool.name === ADVISOR_INTERNAL_TOOL_NAME) return false\n const type = tool.type\n return typeof type !== \"string\" || !type.startsWith(\"advisor_\")\n })\n if (tools.length === original.length) return rawBody\n\n if (tools.length === 0) {\n body.tools = undefined\n body.tool_choice = undefined\n } else {\n body.tools = tools\n if (\n body.tool_choice\n && typeof body.tool_choice === \"object\"\n && (body.tool_choice as AnyRecord).type === \"tool\"\n ) {\n const choiceName = (body.tool_choice as AnyRecord).name\n if (\n choiceName\n && !tools.some(\n (tool: AnyRecord) =>\n tool && typeof tool === \"object\" && tool.name === choiceName,\n )\n ) {\n body.tool_choice = { type: \"auto\" }\n }\n }\n }\n return JSON.stringify(body)\n}\n\n/**\n * Process web search if the request contains a web_search tool.\n * Performs the search, injects results into system, and strips the tool.\n * Returns the (possibly modified) body string to forward.\n */\nasync function processWebSearch(rawBody: string): Promise<string> {\n // Fast path: skip parsing if no web_search tool present\n if (!rawBody.includes(\"web_search\")) return rawBody\n\n let body: AnyRecord\n try {\n body = JSON.parse(rawBody)\n } catch {\n return rawBody\n }\n\n const hasWebSearch = (body.tools as Array<AnyRecord> | undefined)?.some(\n (tool: AnyRecord) => isWebSearchTool(tool),\n )\n if (!hasWebSearch) return rawBody\n\n // Skip search on follow-up messages (tool call results)\n const messages = (body.messages ?? []) as Array<AnyRecord>\n const hasToolResult = hasToolResultContent(messages)\n const query = hasToolResult ? undefined : extractUserQuery(messages)\n\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n injectSearchResults(body, searchContext)\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Always strip web_search tool regardless of whether search succeeded\n stripWebSearchTool(body)\n\n return JSON.stringify(body)\n}\n\nexport async function handleCompletion(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n const rawBody = await c.req.text()\n\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Anthropic request body:\", rawBody.slice(0, 2000))\n }\n\n // Opt-in field-key discovery (Phase 0.5 of the long-horizon plan).\n // No-op unless GH_ROUTER_LOG_FIELDS=1 is set. Feeds\n // scripts/discover-new-fields.sh.\n if (process.env.GH_ROUTER_LOG_FIELDS === \"1\") {\n let parsedForLog: unknown = undefined\n try {\n parsedForLog = JSON.parse(rawBody) as unknown\n } catch {\n // Body parse failures are surfaced downstream; don't double-warn here.\n }\n logRequestFields({\n path: c.req.path,\n body: parsedForLog,\n betaHeader: c.req.header(\"anthropic-beta\"),\n agentId: c.req.header(\"x-claude-code-agent-id\"),\n })\n }\n\n if (state.manualApprove) {\n await awaitApproval()\n }\n\n const betaHeaders = extractBetaHeaders(c)\n\n // Phase I: detect ADVISOR request BEFORE filterBetaHeader strips\n // the advisor-tool- prefix from the outgoing header. We need the raw\n // incoming header to know whether the user asked for ADVISOR.\n const incomingBeta = c.req.header(\"anthropic-beta\")\n const advisorEnabled = isAdvisorRequested(incomingBeta)\n\n let finalBody = await processWebSearch(rawBody)\n // Inbound advisor-history sanitization: rewrite malformed\n // server_tool_use ids in Claude Code's replayed conversation history\n // (left over from before the round-5 fix or any non-spec-compliant\n // source). Without this, Copilot 400s on\n // `messages.N.content.M.server_tool_use.id: String should match\n // pattern '^srvtoolu_[a-zA-Z0-9_]+$'`\n // when the conversation grows long enough to echo a malformed block.\n // Scoped narrowly to advisor pairs to avoid the ID round-trip trap\n // (see src/lib/sanitize-anthropic-body.ts header comment).\n finalBody = sanitizeAnthropicBody(finalBody)\n if (advisorEnabled) {\n // Inject __anthropic_advisor tool definition (with cc-backup's\n // ADVISOR_TOOL_INSTRUCTIONS as description) so the model knows\n // when to call it. Tool name uses double-underscore prefix to\n // avoid collision with any user MCP server's `advisor`.\n finalBody = injectAdvisorTool(finalBody)\n consola.info(\n \"ADVISOR enabled for this request — injecting __anthropic_advisor tool; will translate tool_use → server_tool_use{advisor} on the SSE stream\",\n )\n }\n\n // Phase G fail-fast (deferred translate path per codex-critic): if the\n // request includes inline `mcp_servers`, refuse with a clear Anthropic-\n // format error before forwarding. The original plan was to translate\n // (instantiate MCP clients server-side and inline tools) but the design\n // has structural holes — continuation after pool TTL isn't implementable\n // from the request alone, and streaming correctness during the multi-turn\n // tool loop is fragile. Local stdio MCP (~/.claude/mcp.json) covers the\n // common Claude usage; remote-managed MCP is the rare path. Fail-fast\n // with a clear pointer is the better Pareto choice (codex-critic 2/2/3\n // verdict on the translate-path design).\n if (finalBody.includes('\"mcp_servers\"')) {\n try {\n const probe = JSON.parse(finalBody) as AnyRecord\n if (Array.isArray(probe.mcp_servers) && probe.mcp_servers.length > 0) {\n return c.json(\n {\n type: \"error\",\n error: {\n type: \"invalid_request_error\",\n message:\n \"Inline `mcp_servers` body field is not supported by github-router. \"\n + \"Configure remote MCP servers as local stdio entries in `~/.claude/mcp.json` instead — \"\n + \"Claude Code will spawn them locally and the proxy passes their tool calls through transparently. \"\n + \"(https://docs.claude.com/en/docs/claude-code/mcp)\",\n },\n },\n 400,\n )\n }\n } catch {\n // Body wasn't valid JSON — fall through, downstream handlers will\n // surface the parse error in their own way.\n }\n }\n\n // Resolve model name (e.g. opus → opus-1m variant) and translate\n // thinking-mode shape for adaptive-thinking models.\n const {\n body: resolvedBody,\n originalModel,\n resolvedModel,\n selectedModel,\n } = resolveModelInBody(finalBody)\n\n const modelId = resolvedModel ?? originalModel\n\n // Non-Claude models are diverted to the Anthropic-translation shim: those\n // Copilot serves via `/responses` (gpt-5.5, gpt-5.3-codex) take the Responses\n // path, those it serves via `/chat/completions` (gemini) take the chat path.\n // Claude models fall through to the native `createMessages` passthrough below,\n // byte-for-byte unchanged. The decision is keyed off the resolved model's\n // identity + catalog endpoint (see classifyMessagesRoute), never a hardcoded\n // slug list. The ORIGINAL (pre-resolution) request model id is passed as the\n // 3rd arg so a Claude alias that resolveModel maps onto a non-Claude-looking\n // id can never be diverted to either shim (fail-closed to Claude).\n const messagesRoute = classifyMessagesRoute(modelId, selectedModel, originalModel)\n if (messagesRoute !== \"claude-passthrough\") {\n // ADVISOR is a Claude-only feature: the server-side advisor translate-loop\n // (buildAdvisorStream) exists only on the native /v1/messages path, not on\n // either shim. When a request carrying the advisor beta/tool routes to a\n // non-Claude model — whether picked via `-m <model>` or switched at runtime\n // via the /model picker — gracefully DEGRADE instead of 400ing every\n // request (which would break `github-router claude -m gpt-5.5` entirely,\n // since the claude launcher auto-enables the advisor beta). Strip the\n // injected `__anthropic_advisor` tool (which would otherwise reach the\n // model with no server-side handler) and ignore the advisor beta, then\n // forward to the shim so the request succeeds. Advisor is simply\n // unavailable on non-Claude models. The Claude passthrough path (below) is\n // unchanged — the advisor loop still runs there.\n // Strip the internal advisor tool UNCONDITIONALLY on every shim path\n // (defense-in-depth): the reserved `__anthropic_advisor` / `advisor_*` tool\n // is a proxy-internal contract with no server-side handler off the Claude\n // path, so it must never reach gpt/gemini regardless of whether the advisor\n // beta was present — a hand-crafted client could decouple the tool from the\n // beta. stripAdvisorTool returns the same string when nothing matched.\n const shimBody = stripAdvisorTool(resolvedBody)\n if (advisorEnabled) {\n consola.info(\n \"ADVISOR requested with a non-Claude model — stripping the injected \"\n + \"__anthropic_advisor tool and proceeding without advisor (Claude-only \"\n + \"feature; gracefully degraded).\",\n )\n }\n const shimOpts = {\n rawBody: shimBody,\n modelId: modelId!,\n model: selectedModel,\n originalModel,\n startTime,\n }\n return messagesRoute === \"chat-shim\"\n ? handleNonClaudeChat(c, shimOpts)\n : handleNonClaudeResponses(c, shimOpts)\n }\n\n if (modelId) logEndpointMismatch(modelId, \"/v1/messages\")\n\n // Apply default anthropic-beta for Claude models when client sends none\n const effectiveBetas = applyDefaultBetas(betaHeaders, resolvedModel ?? originalModel)\n\n // When ADVISOR is enabled, create a shared AbortController BEFORE the\n // initial createMessages call so consumer-cancel propagates to the\n // initial response body (not just continuation/runAdvisor calls). Pre-\n // fix the initial createMessages had no callerSignal, so the response\n // body survived cancellation for up to UPSTREAM_FETCH_TIMEOUT_MS (0 disables),\n // burning tokens and holding a socket.\n // NOTE: do NOT use c.req.raw.signal here — Bun aborts it after request-\n // body consumption (see CLAUDE.md \"Bun request-signal quirk\").\n const advisorAborter = advisorEnabled ? new AbortController() : undefined\n\n let response: Response\n try {\n // retryTransient: true — pre-first-byte retry on a 429/5xx/network blip.\n // The response body is not consumed until the streaming/non-streaming\n // branch below, so re-issuing here cannot duplicate streamed output.\n response = await createMessages(resolvedBody, {\n ...selectedModel?.requestHeaders,\n ...effectiveBetas,\n }, advisorAborter?.signal, true)\n } catch (error) {\n if (error instanceof HTTPError) {\n const errorBody = await error.response.clone().text().catch(() => \"\")\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: error.response.status,\n errorBody,\n },\n selectedModel,\n startTime,\n )\n }\n throw error\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\"\n // Trust the upstream content-type when it's explicit. Two anomalies need\n // a fallback: (a) header missing entirely, (b) header is\n // `application/octet-stream` (some proxies normalize SSE this way). In\n // those cases, treat as streaming if the client asked for it via the\n // Accept header — Anthropic SDKs send `Accept: text/event-stream` for\n // streaming requests. We do NOT fall back when content-type is\n // explicitly `application/json` — that's almost always an upstream\n // error response that should be parsed via parseJsonOrDiagnose.\n const clientAcceptsSSE = (c.req.header(\"accept\") ?? \"\").includes(\n \"text/event-stream\",\n )\n let isStreaming = contentType.includes(\"text/event-stream\")\n if (!isStreaming && clientAcceptsSSE) {\n if (contentType === \"\" || contentType === \"application/octet-stream\") {\n consola.warn(\n `Upstream /v1/messages returned status=${response.status} content-type=${JSON.stringify(contentType)} but client requested streaming; treating response body as SSE`,\n )\n isStreaming = true\n }\n }\n\n if (debugEnabled) {\n consola.debug(\n `Upstream /v1/messages: status=${response.status} content-type=\"${contentType}\" isStreaming=${isStreaming}`,\n )\n }\n\n // Streaming: pipe the upstream SSE response body directly (or wrap\n // with the ADVISOR translate-loop if advisor was requested).\n if (isStreaming) {\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: response.status,\n streaming: true,\n },\n selectedModel,\n startTime,\n )\n\n if (debugEnabled) {\n consola.debug(\"Streaming response from Copilot /v1/messages\")\n }\n const streamHeaders: Record<string, string> = {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n \"transfer-encoding\": \"chunked\",\n connection: \"keep-alive\",\n }\n const requestId = response.headers.get(\"x-request-id\")\n if (requestId) streamHeaders[\"x-request-id\"] = requestId\n const reqId = response.headers.get(\"request-id\")\n if (reqId) streamHeaders[\"request-id\"] = reqId\n\n // Phase I: branch into the advisor translate-loop if the user\n // requested ADVISOR. The loop intercepts tool_use{__anthropic_advisor}\n // blocks, translates to server_tool_use{advisor}, runs the advisor\n // model server-side, emits advisor_tool_result, and continues the\n // Copilot conversation on the SAME SSE connection (no intermediate\n // message_stop). See src/services/advisor/advisor.ts for the design\n // (gemini-critic streaming-during-loop pattern).\n if (advisorEnabled && response.body) {\n // Parse the resolved body once to extract the conversation +\n // base body for continuation calls. The translate-loop needs\n // these to extend the conversation across advisor turns.\n let parsedBase: AnyRecord = {}\n try {\n parsedBase = JSON.parse(resolvedBody) as AnyRecord\n } catch {\n // Should not happen since resolveModelInBody just re-serialized\n // it. Fallback: pass empty conversation; translate-loop will\n // skip advisor calls if it can't construct continuations.\n }\n const initialConversation = Array.isArray(parsedBase.messages)\n ? (parsedBase.messages as Array<AnyRecord>)\n : []\n return new Response(\n buildAdvisorStream({\n firstResponse: response,\n initialConversation,\n baseBody: parsedBase,\n requestHeaders: {\n ...selectedModel?.requestHeaders,\n ...effectiveBetas,\n },\n externalAborter: advisorAborter,\n }),\n {\n status: response.status,\n headers: streamHeaders,\n },\n )\n }\n\n return new Response(\n response.body\n ? relayAnthropicStream(response.body, { routePath: c.req.path })\n : null,\n {\n status: response.status,\n headers: streamHeaders,\n },\n )\n }\n\n // Non-streaming: read response body with a 10 MiB size cap to prevent OOM\n // from a misbehaving upstream that sends a multi-GB application/json body.\n // The streaming branch is safe by construction (chunk-by-chunk processing).\n const cappedResult = await readResponseBodyCapped<AnyRecord>(\n response,\n c.req.path,\n MAX_RESPONSE_BODY_BYTES,\n )\n\n if (!cappedResult.ok) {\n return c.json(cappedResult.errorResponse, cappedResult.status as 502)\n }\n\n const responseBody = cappedResult.value\n\n const usage = responseBody.usage as\n | { input_tokens?: number; output_tokens?: number }\n | undefined\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n inputTokens: usage?.input_tokens,\n outputTokens: usage?.output_tokens,\n status: response.status,\n },\n selectedModel,\n startTime,\n )\n\n if (debugEnabled) {\n consola.debug(\n \"Non-streaming response from Copilot /v1/messages:\",\n JSON.stringify(responseBody).slice(0, 2000),\n )\n }\n const xRequestId = response.headers.get(\"x-request-id\")\n if (xRequestId) c.header(\"x-request-id\", xRequestId)\n const requestIdHeader = response.headers.get(\"request-id\")\n if (requestIdHeader) c.header(\"request-id\", requestIdHeader)\n return c.json(responseBody, response.status as 200)\n}\n\n/**\n * Parse the JSON body, resolve the model name, sanitize cache_control\n * fields, translate thinking-mode shape for adaptive-thinking models,\n * and re-serialize. Returns the body string, original/resolved model\n * names, and the matching model metadata (if any).\n *\n * Re-serialization is skipped when no modifications are needed.\n */\nfunction resolveModelInBody(rawBody: string): {\n body: string\n originalModel?: string\n resolvedModel?: string\n selectedModel?: Model\n} {\n let parsed: AnyRecord\n try {\n parsed = JSON.parse(rawBody)\n } catch {\n return { body: rawBody }\n }\n\n const originalModel =\n typeof parsed.model === \"string\" ? parsed.model : undefined\n\n let modified = false\n if (originalModel) {\n const resolved = resolveModel(originalModel)\n if (resolved !== originalModel) {\n parsed.model = resolved\n modified = true\n }\n }\n\n const resolvedModel =\n typeof parsed.model === \"string\" ? parsed.model : originalModel\n\n const selectedModel = resolvedModel\n ? state.models?.data.find((m) => m.id === resolvedModel)\n : undefined\n\n // Translate thinking-mode shape for adaptive-thinking models — Copilot\n // wants {type:\"adaptive\"} + output_config.effort, not Anthropic's\n // {type:\"enabled\", budget_tokens}.\n if (translateThinking(parsed, selectedModel)) {\n modified = true\n }\n\n // Unconditionally clamp output_config.effort to the model's\n // reasoning_effort allowlist. Runs even when translateThinking did\n // not fire — catches requests that arrive ALREADY in Copilot shape\n // (e.g. Claude Code agent-teams teammates that send xhigh to opus-4.8,\n // which Copilot rejects with \"output_config.effort 'xhigh' is not\n // supported by model claude-opus-4.8; supported values: [medium]\").\n // Policy: the proxy does not forward a value upstream rejects.\n if (clampOutputConfigEffortInPlace(parsed, selectedModel)) {\n modified = true\n }\n\n // Strip cache_control.scope — fast path skips when \"scope\" absent\n const needsSanitize = rawBody.includes('\"scope\"')\n if (needsSanitize && sanitizeCacheControl(parsed)) {\n modified = true\n }\n\n // Strip Anthropic-only top-level body fields Copilot 400s on. Empirical\n // verification (2026-05-11 / 2026-05-13 against api.enterprise.githubcopilot.com):\n // - `budget: {total_tokens}` (Task Budgets) → 400 \"budget: Extra inputs not permitted\"\n // - `output_config: {schema}` (Structured Outputs) → 400 \"output_config.schema: Extra...\"\n // - `betas: [...]` (top-level array, distinct from anthropic-beta header) → 400 \"betas: Extra...\"\n // - `tools[i].eager_input_streaming` (Fine-Grained Tool Streaming) → 400\n // \"tools.0.custom.eager_input_streaming: Extra inputs are not permitted\"\n // (the `.custom.` infix is Copilot's error-format; the actual emit\n // location from Claude Code is the top of each tool object per\n // https://platform.claude.com/docs/en/agents-and-tools/tool-use/fine-grained-tool-streaming).\n // Stripping disables only the streaming-chunk-size optimization;\n // correctness is unaffected — `input_json_delta` events still flow,\n // just with `partial_json:\"\"` instead of populated chunks.\n // Probes: `eager_input_streaming_strips` / `eager_input_streaming_passthrough`\n // in scripts/probe-copilot-compat.sh.\n // Fast-path skip when none of the field names appear in the raw body.\n // NOT stripped:\n // - `mcp_servers` — Phase G builds the translate path; silent strip\n // here would cause LLM to hallucinate tools (gemini-critic finding).\n // - `metadata: {user_id}` — Copilot 200s, ignores harmlessly. Strip\n // would be cosmetic (codex-critic: \"preserve unknown fields unless\n // documented reason\"); ~0.1ms re-serialize cost per request adds up.\n const needsAnthropicOnlyStrip =\n rawBody.includes('\"budget\"')\n || rawBody.includes('\"output_config\"')\n || rawBody.includes('\"betas\"')\n || rawBody.includes('\"eager_input_streaming\"')\n if (needsAnthropicOnlyStrip && stripAnthropicOnlyFields(parsed)) {\n modified = true\n }\n\n return {\n body: modified ? JSON.stringify(parsed) : rawBody,\n originalModel,\n resolvedModel,\n selectedModel,\n }\n}\n\n// Re-exported for backward compatibility — the definitions moved to\n// `~/lib/reasoning-effort` (shared with the Anthropic-translation shim).\nexport { EFFORT_ORDER, bucketEffort, clampEffort }\n\n/**\n * Clamp `body.output_config.effort` to the model's\n * `capabilities.supports.reasoning_effort` allowlist. Mutates `body`\n * in place. Returns true iff a clamp was applied.\n *\n * Sibling to `translateThinking`'s internal clamp — that one only fires\n * when the request arrives in the Anthropic `thinking:{type:\"enabled\"}`\n * shape (which the translator converts into `output_config.effort`).\n * Requests that arrive ALREADY in Copilot shape (`output_config.effort`\n * set by the client) would otherwise pass through unclamped and 400 at\n * upstream — the failure mode is exactly the one Claude Code agent-teams\n * teammates hit on opus-4.8 with `xhigh` effort (Copilot rejects with\n * \"output_config.effort 'xhigh' is not supported by model\n * claude-opus-4.8; supported values: [medium]\").\n *\n * Generic policy: the proxy does not forward a value upstream rejects.\n * If the model declares a `reasoning_effort` allowlist and the\n * client-supplied `output_config.effort` is not in it, clamp via\n * `clampEffort` (using `EFFORT_ORDER` bucketing). Unknown effort\n * values fall through to `clampEffort`'s \"no closer tier\" branch\n * (returns the original); the model would then 400 at upstream, which\n * is the right behaviour for genuinely invalid input.\n *\n * No-ops when:\n * - The model has no `reasoning_effort` allowlist (some models\n * accept arbitrary efforts; treat absent allowlist as \"any\n * accepted\")\n * - `body.output_config` is missing or not a plain object\n * - `body.output_config.effort` is missing or not a string\n * - The current effort is already in the allowlist (no-op clamp)\n */\nexport function clampOutputConfigEffortInPlace(\n body: AnyRecord,\n model?: Model,\n): boolean {\n if (!model?.capabilities?.supports?.reasoning_effort) return false\n const supported = model.capabilities.supports.reasoning_effort\n if (!Array.isArray(supported) || supported.length === 0) return false\n if (!body.output_config || typeof body.output_config !== \"object\") return false\n const oc = body.output_config as AnyRecord\n const current = oc.effort\n if (typeof current !== \"string\") return false\n if (supported.includes(current)) return false\n // Pass the current effort through `clampEffort` if it is a known\n // EFFORT_ORDER bucket; otherwise fall back to picking the nearest\n // supported tier by treating unknown values as the TOP tier (so we always\n // clamp DOWN to the highest supported, never up).\n const bucketed = (EFFORT_ORDER as ReadonlyArray<string>).includes(current)\n ? (current as (typeof EFFORT_ORDER)[number])\n : UNKNOWN_EFFORT_ANCHOR\n const clamped = clampEffort(bucketed, supported)\n if (clamped === current) return false\n oc.effort = clamped\n return true\n}\n\n/**\n * Translate Anthropic-shape `thinking:{type:\"enabled\", budget_tokens}` to\n * Copilot-shape `thinking:{type:\"adaptive\"}` + `output_config.effort`\n * when the resolved model declares `adaptive_thinking: true`.\n *\n * Returns true if the body was modified. No-op when the model doesn't\n * support adaptive thinking, when thinking is missing/disabled/already\n * adaptive, or when `body` isn't a plain object. Client-supplied\n * `output_config.effort` always wins over the bucketed value.\n */\nfunction translateThinking(body: AnyRecord, model?: Model): boolean {\n if (!model?.capabilities?.supports?.adaptive_thinking) return false\n const thinking = body.thinking\n if (!thinking || typeof thinking !== \"object\") return false\n const t = thinking as AnyRecord\n if (t.type !== \"enabled\") return false\n\n const bucketed = bucketEffort(t.budget_tokens)\n const supported = model.capabilities.supports.reasoning_effort\n const effort =\n Array.isArray(supported) && supported.length > 0\n ? clampEffort(bucketed, supported)\n : bucketed\n\n body.thinking = { type: \"adaptive\" }\n\n const existing =\n body.output_config && typeof body.output_config === \"object\"\n ? (body.output_config as AnyRecord)\n : {}\n body.output_config = {\n ...existing,\n // client-supplied effort wins\n effort: existing.effort ?? effort,\n }\n\n return true\n}\n\n/**\n * Strip the `scope` field from all `cache_control` objects in the body.\n * Claude CLI 2.1.88+ sends {\"type\":\"ephemeral\",\"scope\":\"global\"} which\n * Copilot rejects. Mutates the parsed object in place.\n *\n * Covers: system blocks, message content blocks (including nested\n * tool_result content), and tool definitions.\n */\nfunction sanitizeCacheControl(body: AnyRecord): boolean {\n let stripped = false\n function stripScope(block: AnyRecord): void {\n const cc = block.cache_control as AnyRecord | undefined\n if (cc?.scope !== undefined) {\n delete cc.scope\n if (Object.keys(cc).length === 0) {\n delete block.cache_control\n }\n stripped = true\n }\n }\n\n if (Array.isArray(body.system)) {\n for (const block of body.system) stripScope(block)\n }\n\n if (Array.isArray(body.messages)) {\n for (const msg of body.messages) {\n if (Array.isArray(msg.content)) {\n for (const block of msg.content) {\n stripScope(block)\n if (Array.isArray(block.content)) {\n for (const nested of block.content) stripScope(nested)\n }\n }\n }\n }\n }\n\n if (Array.isArray(body.tools)) {\n for (const tool of body.tools) stripScope(tool)\n }\n\n return stripped\n}\n\n/**\n * Apply default anthropic-beta values for Claude models when the client\n * (e.g. curl) sends no beta headers. Claude CLI sends its own betas,\n * so this only fires as a safety net for bare clients.\n */\nfunction applyDefaultBetas(\n betaHeaders: Record<string, string>,\n modelId?: string,\n): Record<string, string> {\n if (betaHeaders[\"anthropic-beta\"]) return betaHeaders\n if (!modelId || !modelId.startsWith(\"claude-\")) return betaHeaders\n\n return {\n ...betaHeaders,\n \"anthropic-beta\": [\n \"interleaved-thinking-2025-05-14\",\n \"context-management-2025-06-27\",\n ].join(\",\"),\n }\n}\n\n/**\n * Strip top-level body fields that Anthropic's Messages API accepts but\n * Copilot rejects with HTTP 400 \"Extra inputs are not permitted\". Mutates\n * `body` in place; returns true if anything was stripped.\n *\n * Empirical verification (2026-05-11):\n * POST /v1/messages?beta=true { ..., budget: {total_tokens: 10000} } → 400\n * POST /v1/messages?beta=true { ..., output_config: {schema: {...}} } → 400\n * POST /v1/messages?beta=true { ..., betas: [\"...\"] } → 400\n *\n * Each strip emits a one-line consola.warn so users running with these\n * features (e.g. `claude --max-budget-usd`, `--json-schema`) understand\n * the request succeeds with the *body field* dropped — semantics may\n * differ from upstream Anthropic. The corresponding `anthropic-beta`\n * header is preserved (Phase A allowlist) so the *intent* still flows\n * to Copilot, even if the per-request enforcement field is gone.\n *\n * NOT stripped here:\n * - `mcp_servers` (Phase G translate path — silent strip causes LLM\n * to hallucinate tools per gemini-critic finding)\n * - `metadata` (Copilot 200s, ignores harmlessly)\n */\nfunction stripAnthropicOnlyFields(body: AnyRecord): boolean {\n let stripped = false\n if (body.budget !== undefined) {\n consola.warn(\n \"Stripping body-level `budget` field (Copilot 400s; the `task-budgets-` beta header is preserved but cost ceiling is not enforced server-side)\",\n )\n delete body.budget\n stripped = true\n }\n if (body.output_config !== undefined) {\n // output_config has multiple known shapes:\n // - `{schema:{...}}` (Structured Outputs full form) — Copilot 400s\n // - `{type:\"json_object\"}` (Structured Outputs short form, used\n // by Claude Code's hook evaluator + the Anthropic SDK's\n // structured-output API) — Copilot 400s with the same\n // `output_config: Extra inputs are not permitted` message,\n // just at the top-level field rather than the nested .schema.\n // - `{effort:\"high\"}` (proxy-set during adaptive-thinking\n // translation) — Copilot 200s, required by translateThinking.\n //\n // Strategy: strip every Structured-Outputs field (`schema`,\n // `type`, `response_format`, anything else we don't recognize as\n // proxy-internal). Keep `effort` if present. If the object ends\n // up empty, drop the whole field.\n //\n // **Schema preservation via prompt injection**: stripping\n // `output_config.schema` removes server-side enforcement, which\n // makes the model's output non-deterministic. Claude Code's\n // hook evaluator then fails with \"JSON validation failed\" because\n // it tries to `JSON.parse(response)` and gets natural-language\n // text. To preserve the structured-output INTENT through Copilot,\n // append a system-prompt instruction telling the model to produce\n // JSON conforming to the schema. This isn't as strong as\n // server-side enforcement (the model may occasionally deviate),\n // but it's much better than no constraint at all.\n if (body.output_config && typeof body.output_config === \"object\") {\n const oc = body.output_config as AnyRecord\n const PROXY_OWNED_FIELDS = new Set([\"effort\"])\n // Capture the schema BEFORE stripping so we can inject it.\n const schema = oc.schema\n const ocType = oc.type\n let strippedAny = false\n for (const key of Object.keys(oc)) {\n if (!PROXY_OWNED_FIELDS.has(key)) {\n delete oc[key]\n strippedAny = true\n }\n }\n if (strippedAny) {\n consola.warn(\n \"Stripping client-set `output_config` Structured-Outputs fields\"\n + \" (Copilot 400s on `output_config.*` other than `effort`;\"\n + \" injecting schema as system-prompt instruction so the\"\n + \" model still produces JSON conforming to the structured-\"\n + \"outputs schema, since server-side enforcement is gone)\",\n )\n if (Object.keys(oc).length === 0) {\n delete body.output_config\n }\n if (schema !== undefined || ocType === \"json_object\") {\n appendStructuredOutputInstruction(body, schema, ocType)\n }\n stripped = true\n }\n }\n }\n if (Array.isArray(body.betas)) {\n consola.warn(\n \"Stripping body-level `betas` array (Copilot 400s; the betas are conveyed via the `anthropic-beta` header instead)\",\n )\n delete body.betas\n stripped = true\n }\n // Per-tool field strip: `eager_input_streaming` (Fine-Grained Tool Streaming).\n // Auto-enabled by getClaudeCodeEnvVars setting CLAUDE_CODE_ENABLE_FINE_GRAINED_TOOL_STREAMING=1\n // (see src/lib/server-setup.ts), which causes the Claude Code SDK to emit\n // `eager_input_streaming: true` on each custom tool definition. Copilot rejects.\n // JSON-AST traversal — never regex on the raw body (gemini-critic: would\n // corrupt prompt text containing the same string).\n if (Array.isArray(body.tools)) {\n let warnedFGTS = false\n for (const tool of body.tools) {\n if (typeof tool === \"object\" && tool !== null) {\n const t = tool as AnyRecord\n if (t.eager_input_streaming !== undefined) {\n delete t.eager_input_streaming\n stripped = true\n if (!warnedFGTS) {\n consola.warn(\n \"Stripping per-tool `eager_input_streaming` field (Copilot 400s on `tools.*.custom.eager_input_streaming`; FGTS chunk-size optimization disabled, but streaming correctness is unaffected — `input_json_delta` events still flow normally)\",\n )\n warnedFGTS = true\n }\n }\n }\n }\n }\n return stripped\n}\n\n/**\n * Append a system-prompt instruction telling the model to produce JSON\n * conforming to a Structured Outputs schema. Used after the proxy\n * strips `output_config` to preserve the schema enforcement intent\n * via prompt engineering instead of server-side validation.\n *\n * Mutates `body.system` in place. Handles both string and array shapes\n * (Anthropic spec allows either).\n */\nfunction appendStructuredOutputInstruction(\n body: AnyRecord,\n schema: unknown,\n ocType: unknown,\n): void {\n let instruction =\n \"\\n\\nIMPORTANT: Your response MUST be a single valid JSON object.\"\n + \" Do not wrap it in markdown code fences. Do not include any text\"\n + \" before or after the JSON object.\"\n if (schema !== undefined) {\n instruction +=\n ` The JSON object MUST conform to this JSON Schema:\\n${JSON.stringify(schema)}`\n } else if (typeof ocType === \"string\") {\n instruction +=\n ` Output type requested: ${ocType}.`\n }\n if (typeof body.system === \"string\") {\n body.system = body.system + instruction\n } else if (Array.isArray(body.system)) {\n body.system = [\n ...body.system,\n { type: \"text\", text: instruction.trimStart() },\n ]\n } else {\n body.system = instruction.trimStart()\n }\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { logRequest } from \"~/lib/request-log\"\nimport { sanitizeAnthropicBody } from \"~/lib/sanitize-anthropic-body\"\nimport { filterBetaHeader, resolveModel } from \"~/lib/utils\"\nimport { state } from \"~/lib/state\"\nimport { countTokens } from \"~/services/copilot/create-messages\"\nimport { parseJsonOrDiagnose } from \"~/lib/diagnose-response\"\nimport { clampOutputConfigEffortInPlace } from \"./handler\"\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyRecord = Record<string, any>\n\nconst isWebSearchTool = (tool: AnyRecord): boolean =>\n (typeof tool.type === \"string\" && tool.type.startsWith(\"web_search\")) ||\n tool.name === \"web_search\"\n\n/**\n * Strip web_search tools from the request body before forwarding\n * to Copilot's count_tokens endpoint, which rejects unknown tool types.\n * Returns the original raw body if no web_search tools are present.\n */\nfunction stripWebSearchFromBody(rawBody: string): string {\n if (!rawBody.includes(\"web_search\")) return rawBody\n\n let body: AnyRecord\n try {\n body = JSON.parse(rawBody)\n } catch {\n return rawBody\n }\n\n const hasWebSearch = body.tools?.some(\n (tool: AnyRecord) => isWebSearchTool(tool),\n )\n if (!hasWebSearch) return rawBody\n\n body.tools = body.tools.filter(\n (tool: AnyRecord) => !isWebSearchTool(tool),\n )\n\n if (body.tools.length === 0) {\n body.tools = undefined\n body.tool_choice = undefined\n } else if (\n body.tool_choice &&\n typeof body.tool_choice === \"object\" &&\n body.tool_choice.type === \"tool\"\n ) {\n const choiceName = body.tool_choice.name\n if (\n choiceName &&\n !body.tools.some((tool: AnyRecord) => tool.name === choiceName)\n ) {\n body.tool_choice = { type: \"auto\" }\n }\n }\n\n return JSON.stringify(body)\n}\n\n/**\n * Passthrough handler for Anthropic token counting.\n * Strips web_search tools and forwards beta headers to Copilot's\n * native /v1/messages/count_tokens endpoint.\n */\nexport async function handleCountTokens(c: Context) {\n const startTime = Date.now()\n const rawBody = await c.req.text()\n // Inbound advisor-history sanitization (mirrors handler.ts) — count\n // tokens uses the same Copilot validator, so a malformed\n // server_tool_use block in the conversation history would 400 here\n // too. Scoped narrowly to advisor pairs.\n const sanitizedBody = sanitizeAnthropicBody(rawBody)\n const strippedBody = stripWebSearchFromBody(sanitizedBody)\n\n // Phase G fail-fast: same rationale as handler.ts. count_tokens uses\n // the same Copilot schema validator, so mcp_servers in the body\n // produces the same 400 — surface clearly here too.\n if (strippedBody.includes('\"mcp_servers\"')) {\n try {\n const probe = JSON.parse(strippedBody) as AnyRecord\n if (Array.isArray(probe.mcp_servers) && probe.mcp_servers.length > 0) {\n return c.json(\n {\n type: \"error\",\n error: {\n type: \"invalid_request_error\",\n message:\n \"Inline `mcp_servers` body field is not supported by github-router. \"\n + \"Configure remote MCP servers as local stdio entries in `~/.claude/mcp.json` instead.\",\n },\n },\n 400,\n )\n }\n } catch {\n // Not valid JSON — fall through to downstream parse-error path.\n }\n }\n\n const { body: finalBody, originalModel, resolvedModel } = resolveModelInBody(strippedBody)\n\n const extraHeaders: Record<string, string> = {}\n const anthropicBeta = c.req.header(\"anthropic-beta\")\n if (anthropicBeta) {\n const filtered = filterBetaHeader(anthropicBeta)\n if (filtered) extraHeaders[\"anthropic-beta\"] = filtered\n }\n\n const modelId = resolvedModel ?? originalModel\n const selectedModel = state.models?.data.find((m) => m.id === modelId)\n\n // retryTransient: true — count_tokens is non-streaming, so the whole call\n // is pre-first-byte and a transient retry is safe.\n const response = await countTokens(finalBody, {\n ...selectedModel?.requestHeaders,\n ...extraHeaders,\n }, undefined, true)\n const responseBody = await parseJsonOrDiagnose<{ input_tokens?: number }>(\n response,\n c.req.path,\n )\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n inputTokens: responseBody.input_tokens,\n status: response.status,\n },\n selectedModel,\n startTime,\n )\n\n return c.json(responseBody)\n}\n\n/**\n * Parse the JSON body, resolve the model name, sanitize cache_control, and re-serialize.\n */\nfunction resolveModelInBody(rawBody: string): {\n body: string\n originalModel?: string\n resolvedModel?: string\n} {\n let parsed: AnyRecord\n try {\n parsed = JSON.parse(rawBody)\n } catch {\n return { body: rawBody }\n }\n\n const originalModel =\n typeof parsed.model === \"string\" ? parsed.model : undefined\n\n let modified = false\n if (originalModel) {\n const resolved = resolveModel(originalModel)\n if (resolved !== originalModel) {\n parsed.model = resolved\n modified = true\n }\n }\n\n const needsSanitize = rawBody.includes('\"scope\"')\n if (needsSanitize && sanitizeCacheControl(parsed)) {\n modified = true\n }\n\n // Strip Anthropic-only body fields Copilot 400s on. See\n // `stripAnthropicOnlyFields` in handler.ts for full rationale + empirical\n // evidence (2026-05-11 / 2026-05-13 verification). count_tokens uses the same\n // Copilot schema validator as /v1/messages so the same fields are rejected.\n const needsAnthropicOnlyStrip =\n rawBody.includes('\"budget\"')\n || rawBody.includes('\"output_config\"')\n || rawBody.includes('\"betas\"')\n || rawBody.includes('\"eager_input_streaming\"')\n if (needsAnthropicOnlyStrip && stripAnthropicOnlyFields(parsed)) {\n modified = true\n }\n\n const resolvedModel =\n typeof parsed.model === \"string\" ? parsed.model : originalModel\n\n // Unconditionally clamp output_config.effort to the resolved\n // model's reasoning_effort allowlist. Mirrors the same step in\n // /v1/messages handler so count_tokens never forwards a value\n // upstream rejects. Selected model is looked up off state.models\n // so the clamp uses the live catalog (matches handler.ts's lookup\n // pattern).\n const selectedModel = resolvedModel\n ? state.models?.data.find((m) => m.id === resolvedModel)\n : undefined\n if (selectedModel && clampOutputConfigEffortInPlace(parsed, selectedModel)) {\n modified = true\n }\n\n return {\n body: modified ? JSON.stringify(parsed) : rawBody,\n originalModel,\n resolvedModel,\n }\n}\n\nfunction sanitizeCacheControl(body: AnyRecord): boolean {\n let stripped = false\n function stripScope(block: AnyRecord): void {\n if (block.cache_control?.scope !== undefined) {\n delete block.cache_control.scope\n if (Object.keys(block.cache_control).length === 0) {\n delete block.cache_control\n }\n stripped = true\n }\n }\n\n if (Array.isArray(body.system)) {\n for (const block of body.system) stripScope(block)\n }\n\n if (Array.isArray(body.messages)) {\n for (const msg of body.messages) {\n if (Array.isArray(msg.content)) {\n for (const block of msg.content) {\n stripScope(block)\n if (Array.isArray(block.content)) {\n for (const nested of block.content) stripScope(nested)\n }\n }\n }\n }\n }\n\n if (Array.isArray(body.tools)) {\n for (const tool of body.tools) stripScope(tool)\n }\n\n return stripped\n}\n\n/**\n * Strip top-level body fields Copilot 400s on (budget, output_config.schema,\n * betas). Duplicated structurally from handler.ts because count_tokens uses\n * its own JSON-pass; the bodies are independent. Behavior must stay in lock-\n * step with handler.ts's stripAnthropicOnlyFields — covered by integration\n * tests (Phase F P2.4).\n */\nfunction stripAnthropicOnlyFields(body: AnyRecord): boolean {\n let stripped = false\n if (body.budget !== undefined) {\n consola.warn(\n \"[count_tokens] Stripping body-level `budget` field (Copilot 400s)\",\n )\n delete body.budget\n stripped = true\n }\n if (body.output_config !== undefined) {\n if (body.output_config && typeof body.output_config === \"object\") {\n const oc = body.output_config as AnyRecord\n const PROXY_OWNED_FIELDS = new Set([\"effort\"])\n let strippedAny = false\n for (const key of Object.keys(oc)) {\n if (!PROXY_OWNED_FIELDS.has(key)) {\n delete oc[key]\n strippedAny = true\n }\n }\n if (strippedAny) {\n consola.warn(\n \"[count_tokens] Stripping client-set `output_config` Structured-Outputs fields (Copilot 400s on `output_config.*` other than `effort`)\",\n )\n if (Object.keys(oc).length === 0) {\n delete body.output_config\n }\n stripped = true\n }\n }\n }\n if (Array.isArray(body.betas)) {\n consola.warn(\n \"[count_tokens] Stripping body-level `betas` array (Copilot 400s; conveyed via header)\",\n )\n delete body.betas\n stripped = true\n }\n // Per-tool field strip: `eager_input_streaming` (FGTS). Mirrors handler.ts.\n if (Array.isArray(body.tools)) {\n let warnedFGTS = false\n for (const tool of body.tools) {\n if (typeof tool === \"object\" && tool !== null) {\n const t = tool as AnyRecord\n if (t.eager_input_streaming !== undefined) {\n delete t.eager_input_streaming\n stripped = true\n if (!warnedFGTS) {\n consola.warn(\n \"[count_tokens] Stripping per-tool `eager_input_streaming` (Copilot 400s on `tools.*.custom.eager_input_streaming`)\",\n )\n warnedFGTS = true\n }\n }\n }\n }\n }\n return stripped\n}\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 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 // Pass through every upstream field (billing, is_chat_default,\n // info_messages, model_picker_category, etc.) and overlay the\n // OpenAI-compat aliases. requestHeaders is router-internal — drop it.\n const { requestHeaders, ...rest } = model\n void requestHeaders\n return {\n ...rest,\n object: \"model\",\n type: model.capabilities?.type ?? \"model\",\n created: 0,\n created_at: new Date(0).toISOString(),\n owned_by: model.vendor,\n display_name: model.name,\n }\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","import { randomUUID } from \"node:crypto\"\nimport type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { awaitApproval } from \"~/lib/approval\"\nimport { HTTPError } from \"~/lib/error\"\nimport { logEndpointMismatch } from \"~/lib/model-validation\"\nimport { UPSTREAM_FETCH_TIMEOUT_MS } from \"~/lib/port\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { logRequest } from \"~/lib/request-log\"\nimport { UPSTREAM_INACTIVITY_TIMEOUT_MS } from \"~/lib/port\"\nimport { state } from \"~/lib/state\"\nimport { buildOpenAIErrorEvent, isControllerClosedError, logStreamError, readIteratorWithTimeout } from \"~/lib/stream-relay\"\nimport { tryRefreshAndRetry } from \"~/lib/token\"\nimport { fetchWithTransientRetry } from \"~/lib/upstream-retry\"\nimport { resolveModel } from \"~/lib/utils\"\nimport {\n createResponses,\n type ResponsesApiResponse,\n type ResponsesInputItem,\n type ResponsesPayload,\n} from \"~/services/copilot/create-responses\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\ninterface UpstreamSSEEvent {\n event?: string\n data?: string\n id?: string | number\n}\n\nconst ENCODER = new TextEncoder()\n\nfunction formatSSE(chunk: UpstreamSSEEvent): string {\n const parts: Array<string> = []\n if (chunk.event) parts.push(`event: ${chunk.event}`)\n if (chunk.data !== undefined) {\n for (const line of String(chunk.data).split(/\\r\\n|\\r|\\n/)) {\n parts.push(`data: ${line}`)\n }\n }\n if (chunk.id !== undefined) parts.push(`id: ${String(chunk.id)}`)\n return parts.join(\"\\n\") + \"\\n\\n\"\n}\n\nexport async function handleResponses(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n const payload = await c.req.json<ResponsesPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\n \"Responses request payload:\",\n JSON.stringify(payload).slice(-400),\n )\n }\n\n // Resolve model name (e.g. opus → opus-1m variant)\n const originalModel = payload.model\n const resolvedModel = resolveModel(payload.model)\n if (resolvedModel !== payload.model) {\n payload.model = resolvedModel\n }\n\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n logEndpointMismatch(payload.model, \"/responses\")\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n // retryTransient: true — pre-first-byte retry; the body is consumed only\n // after the ok-check inside createResponses, so a re-issue here cannot\n // duplicate streamed output.\n const response = await createResponses(\n payload,\n selectedModel?.requestHeaders,\n undefined,\n true,\n ).catch(\n async (error: unknown) => {\n if (error instanceof HTTPError) {\n const errorBody = await error.response.clone().text().catch(() => \"\")\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: error.response.status,\n errorBody,\n },\n selectedModel,\n startTime,\n )\n }\n throw error\n },\n )\n const isStreaming = !isNonStreaming(response)\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: 200,\n streaming: isStreaming,\n },\n selectedModel,\n startTime,\n )\n\n if (!isStreaming) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n // Streaming: peek the first SSE event so pre-byte upstream errors surface\n // through the route's try/catch → forwardError as a clean JSON response,\n // and only mid-stream errors hit the manual ReadableStream's pull-error path.\n // The /responses iterator emits a final `[DONE]` sentinel which we drop.\n const iterator = (response as AsyncIterableIterator<UpstreamSSEEvent>)[\n Symbol.asyncIterator\n ]()\n\n // Skip leading empty / [DONE] sentinels until we get a real event.\n let firstChunk: UpstreamSSEEvent | undefined\n let upstreamFinished = false\n while (true) {\n const r = await readIteratorWithTimeout(iterator, UPSTREAM_INACTIVITY_TIMEOUT_MS)\n if (r.done) {\n upstreamFinished = true\n break\n }\n // Defensive guard against an iterator that yields {done:false, value:undefined}\n // before we dereference r.value.data below.\n if (r.value === undefined || r.value === null) continue\n if (r.value.data === \"[DONE]\") {\n upstreamFinished = true\n break\n }\n if (!r.value.data) continue\n firstChunk = r.value\n break\n }\n if (firstChunk === undefined) {\n consola.warn(\n `Upstream /responses returned no payload events at ${c.req.path}`,\n )\n }\n\n let pendingFirstChunk: UpstreamSSEEvent | undefined = firstChunk\n let consumerCancelled = false\n\n const safeClose = (controller: ReadableStreamDefaultController<Uint8Array>) => {\n try {\n controller.close()\n } catch {\n // already closed / errored\n }\n }\n const releaseUpstream = (reason?: unknown) => {\n if (typeof iterator.return === \"function\") {\n iterator.return(reason).catch(() => {\n // upstream may already be closed\n })\n }\n }\n const safeEnqueue = (\n controller: ReadableStreamDefaultController<Uint8Array>,\n bytes: Uint8Array,\n ): boolean => {\n try {\n controller.enqueue(bytes)\n return true\n } catch (e) {\n if (isControllerClosedError(e)) {\n consumerCancelled = true\n // The downstream cancel() callback may not fire if the controller\n // was closed by Bun's HTTP layer rather than an explicit consumer\n // .cancel() — release the upstream iterator here so the upstream\n // socket does not leak.\n releaseUpstream(e)\n return false\n }\n throw e\n }\n }\n\n return new Response(\n new ReadableStream<Uint8Array>({\n async pull(controller) {\n if (consumerCancelled || upstreamFinished) {\n safeClose(controller)\n return\n }\n if (pendingFirstChunk !== undefined) {\n const chunk = pendingFirstChunk\n pendingFirstChunk = undefined\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n safeEnqueue(controller, ENCODER.encode(formatSSE(chunk)))\n return\n }\n try {\n const result = await readIteratorWithTimeout(iterator, UPSTREAM_INACTIVITY_TIMEOUT_MS)\n if (consumerCancelled) {\n safeClose(controller)\n return\n }\n if (result.done) {\n upstreamFinished = true\n safeClose(controller)\n return\n }\n // Defensive: an upstream iterator that yields `{done:false, value:undefined}`\n // would crash on `result.value.data` below. Skip silently and\n // pull again on the next consumer demand. Real upstream iterators\n // never emit this shape, but a misbehaving / proxied iterator might.\n if (result.value === undefined || result.value === null) return\n if (result.value.data === \"[DONE]\") {\n upstreamFinished = true\n safeClose(controller)\n return\n }\n if (!result.value.data) return\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(result.value))\n }\n safeEnqueue(controller, ENCODER.encode(formatSSE(result.value)))\n } catch (error) {\n upstreamFinished = true\n if (consumerCancelled) {\n // Consumer-cancelled mid-pull. Release the upstream iterator\n // — the cancel() callback may not have fired if the controller\n // was closed by Bun's HTTP layer.\n //\n // We deliberately do NOT call isControllerClosedError(error)\n // on iterator-side errors here — the helper matches substrings\n // like \"stream is closed\" which can appear in real upstream\n // errors, and treating them as consumer-cancel would silently\n // suppress the OpenAI-shape error frame the consumer needs.\n releaseUpstream(error)\n safeClose(controller)\n return\n }\n const { errName, errMessage } = logStreamError(c.req.path, error)\n safeEnqueue(\n controller,\n ENCODER.encode(buildOpenAIErrorEvent(errName, errMessage)),\n )\n // Server-initiated close — release the upstream iterator since\n // our cancel() callback won't fire.\n releaseUpstream(error)\n safeClose(controller)\n }\n },\n cancel() {\n consumerCancelled = true\n upstreamFinished = true\n releaseUpstream()\n },\n }),\n {\n status: 200,\n headers: {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n \"transfer-encoding\": \"chunked\",\n connection: \"keep-alive\",\n },\n },\n )\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createResponses>>,\n): response is ResponsesApiResponse => Object.hasOwn(response, \"output\")\n\nasync function injectWebSearchIfNeeded(\n payload: ResponsesPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some((t) => t.type === \"web_search\")\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (function call results)\n if (Array.isArray(payload.input)) {\n const hasFollowUp = payload.input.some(\n (item: ResponsesInputItem) => item.type === \"function_call_output\",\n )\n if (hasFollowUp) return\n }\n\n const query = extractUserQuery(payload.input)\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n payload.instructions =\n payload.instructions ?\n `${searchContext}\\n\\n${payload.instructions}`\n : searchContext\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Strip the legacy `web_search` tool — defensive. Copilot's /responses\n // empirically accepts bare `web_search` on gpt-5.x today (2026-05-15\n // probe `web_search_responses_preview`: model invokes it natively, output\n // contains a `web_search_call` block), and also accepts the explicit\n // `web_search_preview` / `web_search_preview_2025_03_11` shapes. We strip\n // here as belt-and-suspenders against version drift across Copilot tiers\n // — the proxy's MCP fallback (`injectWebSearchIfNeeded`) substitutes a\n // pre-fetched result so the user-facing path always works regardless of\n // upstream support. Lift this strip if/when we trust bare `web_search`\n // across all served gpt-5.x variants. Other tool types pass through\n // unchanged.\n payload.tools = payload.tools?.filter((t) => t.type !== \"web_search\")\n if (payload.tools && payload.tools.length === 0) {\n payload.tools = undefined\n }\n if (!payload.tools) {\n payload.tool_choice = undefined\n } else if (\n payload.tool_choice\n && typeof payload.tool_choice === \"object\"\n ) {\n const choice = payload.tool_choice as {\n name?: string\n function?: { name?: string }\n }\n const choiceName = choice.function?.name ?? choice.name\n if (choiceName === \"web_search\") {\n payload.tool_choice = undefined\n }\n }\n}\n\nfunction extractUserQuery(\n input: ResponsesPayload[\"input\"],\n): string | undefined {\n if (typeof input === \"string\") return input\n if (!Array.isArray(input)) return undefined\n\n // Find the last user message\n for (let i = input.length - 1; i >= 0; i--) {\n const item = input[i]\n if (\"role\" in item && item.role === \"user\") {\n if (typeof item.content === \"string\") return item.content\n if (Array.isArray(item.content)) {\n const text = item.content.find(\n (p: Record<string, unknown>) => p.type === \"input_text\",\n )\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\n\n/**\n * Compaction prompt used when GitHub Copilot API does not support\n * /responses/compact natively. Matches the prompt Codex CLI uses for\n * local (non-OpenAI) compaction.\n */\nconst COMPACTION_PROMPT = `You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.\n\nInclude:\n- Current progress and key decisions made\n- Important context, constraints, or user preferences\n- What remains to be done (clear next steps)\n- Any critical data, examples, or references needed to continue\n\nBe concise, structured, and focused on helping the next LLM seamlessly continue the work.`\n\ninterface CompactRequestPayload {\n model: string\n input: Array<Record<string, unknown>>\n instructions?: string\n [key: string]: unknown\n}\n\nexport async function handleResponsesCompact(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n if (state.manualApprove) await awaitApproval()\n\n const body = await c.req.json<CompactRequestPayload>()\n\n // Try Copilot's native compact endpoint first (future-proofs for when they add support)\n const compactUrl = `${copilotBaseUrl(state)}/responses/compact`\n // DELIBERATELY DIFFERENT from the streaming services, which honor\n // `UPSTREAM_FETCH_TIMEOUT_MS === 0` as \"no fetch-phase timeout\". That opt-out\n // exists so a legitimately long STREAMING completion is never truncated\n // mid-flight. Compact is a short, NON-streaming request/response, so that\n // rationale doesn't apply — and a hung compact with no signal was a real bug\n // (regression E1; `tests/isolated/responses-compact-timeout.test.ts` asserts a\n // signal is ALWAYS passed). Hence the `|| 300_000` floor: the env var can\n // raise or lower the bound but never remove it. Do NOT \"unify\" this with the\n // streaming services for consistency — that reintroduces E1.\n const doFetch = (): Promise<Response> => fetch(compactUrl, {\n method: \"POST\",\n headers: copilotHeaders(state),\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(UPSTREAM_FETCH_TIMEOUT_MS || 300_000),\n })\n // Non-streaming native compact — retry the transient class (429/5xx/\n // network) around the 401-refresh path. A 404 (Copilot doesn't support\n // this endpoint) is NOT in the retry set, so the synthetic-compaction\n // fallback below still triggers on the first attempt.\n const response = await fetchWithTransientRetry(\n () => tryRefreshAndRetry(doFetch, \"/responses/compact\"),\n { label: \"/responses/compact\" },\n )\n\n if (response.ok) {\n logRequest(\n { method: \"POST\", path: c.req.path, status: 200 },\n undefined,\n startTime,\n )\n return c.json(await response.json())\n }\n\n // Copilot doesn't support /responses/compact — perform synthetic compaction\n // by sending a regular /responses call with a summarization prompt\n if (response.status === 404) {\n consola.debug(\"Copilot API does not support /responses/compact, using synthetic compaction\")\n // Consume the 404 response body to release the upstream TCP connection.\n await response.body?.cancel().catch(() => {})\n return await syntheticCompact(c, body, startTime)\n }\n\n // Other errors: throw as before\n logRequest(\n { method: \"POST\", path: c.req.path, status: response.status },\n undefined,\n startTime,\n )\n throw new HTTPError(\"Copilot responses/compact request failed\", response)\n}\n\n/**\n * Synthetic compaction: sends the conversation history to Copilot's\n * regular /responses endpoint with a compaction prompt appended,\n * then returns the model's summary in the compact response format.\n */\nasync function syntheticCompact(\n c: Context,\n body: CompactRequestPayload,\n startTime: number,\n) {\n const input = Array.isArray(body.input) ? [...body.input] : []\n\n // Append compaction prompt as the last user message\n input.push({\n type: \"message\",\n role: \"user\",\n content: [{ type: \"input_text\", text: COMPACTION_PROMPT }],\n })\n\n const payload: ResponsesPayload = {\n model: body.model,\n input: input as Array<ResponsesInputItem>,\n instructions: body.instructions,\n stream: false,\n store: false,\n }\n\n let result: ResponsesApiResponse\n try {\n // Non-streaming synthetic compaction — whole call is pre-first-byte, so\n // retryTransient: true is safe.\n result = (await createResponses(\n payload,\n undefined,\n undefined,\n true,\n )) as ResponsesApiResponse\n } catch (error) {\n if (error instanceof HTTPError) {\n logRequest(\n { method: \"POST\", path: c.req.path, status: error.response.status },\n undefined,\n startTime,\n )\n }\n throw error\n }\n\n logRequest(\n { method: \"POST\", path: c.req.path, status: 200 },\n undefined,\n startTime,\n )\n\n return c.json({\n id: `resp_compact_${randomUUID().replace(/-/g, \"\").slice(0, 24)}`,\n object: \"response.compaction\",\n created_at: Math.floor(Date.now() / 1000),\n output: result.output,\n usage: result.usage ?? { input_tokens: 0, output_tokens: 0, total_tokens: 0 },\n })\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleResponses, handleResponsesCompact } from \"./handler\"\n\nexport const responsesRoutes = new Hono()\n\nresponsesRoutes.post(\"/\", async (c) => {\n try {\n return await handleResponses(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n\nresponsesRoutes.post(\"/compact\", async (c) => {\n try {\n return await handleResponsesCompact(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport const searchRoutes = new Hono()\n\nsearchRoutes.post(\"/\", async (c) => {\n try {\n const { query } = await c.req.json<{ query: string }>()\n\n if (!query || typeof query !== \"string\") {\n return c.json(\n { error: { message: \"Missing required field: query\" } },\n 400,\n )\n }\n\n const results = await searchWeb(query)\n return c.json({ results })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { state } from \"~/lib/state\"\n\nexport const tokenRoute = new Hono()\n\ntokenRoute.get(\"/\", (c) => {\n if (!state.showToken) {\n return c.json(\n { error: { message: \"Token endpoint disabled\", type: \"error\" } },\n 403,\n )\n }\n\n return c.json({\n token: state.copilotToken,\n })\n})\n","import { Hono } from \"hono\"\nimport consola from \"consola\"\n\nimport { forwardError } from \"~/lib/error\"\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 await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\nimport { cors } from \"hono/cors\"\n\nimport packageJson from \"../package.json\" with { type: \"json\" }\n\nimport { completionRoutes } from \"./routes/chat-completions/route\"\nimport { embeddingRoutes } from \"./routes/embeddings/route\"\nimport { mcpRoutes } from \"./routes/mcp/route\"\nimport { messageRoutes } from \"./routes/messages/route\"\nimport { modelRoutes } from \"./routes/models/route\"\nimport { responsesRoutes } from \"./routes/responses/route\"\nimport { searchRoutes } from \"./routes/search/route\"\nimport { tokenRoute } from \"./routes/token/route\"\nimport { usageRoute } from \"./routes/usage/route\"\nimport { assertMcpToolSurfaceConsistent } from \"./lib/peer-mcp-personas\"\n\n// Fail-fast invariant (runs once at module load for every proxy-serving\n// command): MCP tool names must be unique within each group AND across the\n// unscoped `/mcp` union, since `handleToolsCall` dispatches on the bare\n// tool name. A duplicate would silently shadow — throw loudly instead.\nassertMcpToolSurfaceConsistent()\n\nexport const server = new Hono()\n\nserver.use(cors())\n\nserver.get(\"/\", (c) => c.text(\"Server running\"))\n\n// Build identity. Operators can `curl http://localhost:<port>/version` to\n// confirm which build is serving requests — useful when upgrading via\n// `npx github-router@latest` and verifying the new code actually loaded.\nserver.get(\"/version\", (c) =>\n c.json({\n name: packageJson.name,\n version: packageJson.version,\n gitSha: process.env.GITHUB_SHA ?? \"unknown\",\n }),\n)\n\n// Claude CLI sends HEAD / as health check before each request\nserver.on(\"HEAD\", [\"/\"], (c) => c.body(null, 200))\n\nserver.route(\"/chat/completions\", completionRoutes)\nserver.route(\"/responses\", responsesRoutes)\nserver.route(\"/models\", modelRoutes)\nserver.route(\"/embeddings\", embeddingRoutes)\nserver.route(\"/search\", searchRoutes)\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/responses\", responsesRoutes)\nserver.route(\"/v1/models\", modelRoutes)\nserver.route(\"/v1/embeddings\", embeddingRoutes)\nserver.route(\"/v1/search\", searchRoutes)\n\n// Anthropic compatible endpoints\nserver.route(\"/v1/messages\", messageRoutes)\n\n// Peer-MCP endpoint: hosts gpt-5.5/gpt-5.3-codex/gemini-3.1-pro\n// persona tools (codex_critic / codex_reviewer / gemini_critic) for\n// the spawned Claude Code session to consult via MCP. Auth is a\n// per-launch nonce stored in `state.peerMcpNonce`; the route\n// rejects all requests when the nonce is unset (e.g. proxy started\n// standalone via `github-router start`). See src/routes/mcp/handler.ts.\nserver.route(\"/mcp\", mcpRoutes)\n\n// Stub out Claude Code SDK telemetry so it doesn't 404-spam logs.\n// Copilot doesn't expose this endpoint; clients fire it best-effort.\nserver.post(\"/api/event_logging/batch\", (c) => c.body(null, 200))\n\n// Phase E P1.4: explicit Files-API not-supported route. Claude Code's\n// BriefTool upload + utils/teleport/gitBundle paths hit\n// GET /v1/files/{id}/content (download), GET /v1/files (list),\n// POST /v1/files (upload). Copilot has no equivalent storage backend\n// (verified via cc-backup src/services/api/filesApi.ts). Without this\n// explicit route, requests fall to the default 404 with a generic\n// \"not found\" message — fine but unhelpful.\n//\n// Why surface explicitly: the user gets a clear signal \"this feature\n// isn't supported here\" instead of inferring it from a generic 404.\n// Fail-loud-with-explanation aligns with cc-backup mentality #10\n// (errors are logged not swallowed; surface the limitation).\nserver.all(\"/v1/files/*\", (c) =>\n c.json(\n {\n type: \"error\",\n error: {\n type: \"not_found_error\",\n message:\n \"Files API is not supported by github-router (Copilot has no equivalent storage backend). \"\n + \"Use the Anthropic API directly for file uploads/downloads.\",\n },\n },\n 404,\n ),\n)\n\n// Return Anthropic-format JSON for unknown endpoints\nserver.notFound((c) =>\n c.json(\n {\n type: \"error\",\n error: {\n type: \"not_found_error\",\n message: `${c.req.method} ${c.req.path} not found`,\n },\n },\n 404,\n ),\n)\n","import * as fs from \"node:fs\"\nimport * as nodePath from \"node:path\"\n\nimport consola from \"consola\"\nimport { serve, type ServerHandler } from \"srvx\"\nimport { createBodyTooLargeError, limitRequestBody } from \"srvx/body-limit\"\n\nimport { PATHS, ensurePaths } from \"./paths\"\nimport { maybeSpawnDaemon, wireDaemonTeardown } from \"./first-mate/scheduler/autospawn\"\nimport { agentToolsEnabled } from \"./mcp-capabilities\"\nimport { withOneMSuffix } from \"./one-m-context\"\nimport { generateRandomPort } from \"./port\"\nimport { initProxyFromEnv } from \"./proxy\"\nimport { state } from \"./state\"\nimport { setupCopilotToken, setupGitHubAgentToken, setupGitHubToken } from \"./token\"\nimport { toolbeltEnabled } from \"./toolbelt\"\nimport { toolbeltPathOverride } from \"./toolbelt/path-inject\"\nimport { cacheModels, cacheCopilotVersion, cacheVSCodeVersion } from \"./utils\"\nimport { resolveMcpToolTimeoutMs } from \"./worker-agent/budget\"\nimport { server as app } from \"../server\"\n\nconst MAX_PORT_RETRIES = 10\n\n/**\n * Maximum request body the proxy will accept, in bytes.\n *\n * Pinned EXPLICITLY because the runtimes disagree by default: bun's `serve`\n * defaults `maxRequestBodySize` to 128 MB and rejects past it, while\n * `node:http` (the srvx node adapter) has no body limit at all. Left\n * unset, the same request succeeds under node and 413s under bun, with\n * nothing in the response explaining that the runtime is the variable.\n * Same class of defect as the `idleTimeout` divergence below.\n *\n * Note which side that leaves exposed: `dist/main.js` ships\n * `#!/usr/bin/env node`, so npm-installed users are on the runtime with NO\n * limit, and bun is mostly the dev/`bun run start` path. The uncapped case\n * was the shipped one.\n *\n * 128 MB — i.e. bun's default, adopted as the intended value on BOTH\n * runtimes rather than inherited on one:\n *\n * - It sits above the traffic this proxy is built for, with margin. A\n * full 1M-token Claude Code context is on the order of 4-5 MB of JSON\n * text; base64 inline images inflate 4/3 and are re-sent every turn, so\n * an image-heavy session runs to tens of MB. That is an estimate, not a\n * measurement, which is part of why the cap is set well clear of it\n * rather than snugly above it.\n * - Removing the limit to \"match node\" is not free even on loopback. The\n * app mounts permissive `cors()`, so any web page the user visits can\n * POST to 127.0.0.1:<port> (CORS gates reading the response, not sending\n * the request); so can any local process. An unbounded body lets either\n * stream the proxy to death.\n * - Raising it above 128 MB buys nothing and costs safety: the proxy\n * BUFFERS the whole body (`c.req.json()`), parses it into a JS object\n * (multiples of the text size in heap), then re-serializes it upstream.\n * Past ~512 MB V8's max string length makes `JSON.stringify` fail\n * opaquely — a cap well under that keeps the failure explainable.\n *\n * A body over this ceiling means something is wrong (runaway loop,\n * corrupted context), not a workload that needs a bigger buffer, so\n * there is deliberately no env override to raise it.\n */\nexport const MAX_REQUEST_BODY_BYTES = 128 * 1024 * 1024\n\n/**\n * Where the RUNTIME's own body check sits. Not the policy.\n *\n * The policy is `MAX_REQUEST_BODY_BYTES`, enforced by `withBodyLimit` in\n * this process, identically on every runtime. This value exists only to\n * displace the 128 MB default bun's `serve` applies, which would otherwise pre-empt\n * that gate — bun enforces its limit at header-parse time by replying and\n * closing while the client is still uploading, so a client that has not\n * finished writing never reads the reply. Measured with a real client\n * posting 64 MB over a limit: `The socket connection was closed\n * unexpectedly`, i.e. exactly the opaque failure this change removes, and\n * exactly what bun does TODAY at its default. An early response from our\n * own handler, by contrast, is delivered cleanly (413 with the JSON body,\n * ~50ms, no memory growth; draining the body first was strictly worse at\n * 155ms and +50 MB, so we do not drain).\n *\n * Set as ONE top-level srvx option, so bun and node get the same number.\n * A bun-only override would put the two runtimes back on different\n * thresholds, which is the defect being fixed, not a fix for it.\n *\n * Deliberately far above the policy so the policy always decides first:\n * everything a client can realistically send is answered by the explained\n * 413, and this is reached only by a body that is both undeclared and\n * absurd. It stays finite so \"no limit at all\" is never the state. It\n * bounds nothing the gate does not already bound — an unread body is\n * discarded by both runtimes rather than buffered — so a high value costs\n * no memory, and buys message quality across the whole realistic range.\n */\nconst TRANSPORT_BODY_CEILING_BYTES = 1024 * 1024 * 1024\n\n/**\n * The 413 the user sees when a request body is over the ceiling.\n *\n * Anthropic error envelope (`request_too_large` is Anthropic's own 413\n * category), so a client that parses our error shape on every other path\n * parses this one too, and the message says what to actually do about it.\n *\n * `declaredBytes` is present only when the request declared a length. A\n * body caught mid-stream has no known size, and saying so beats inventing\n * one. Byte counts are exact, with the MB figure only as a gloss:\n * rounding alone reads as a contradiction at the boundary, where a body\n * one byte over renders as \"128.0 MB, over the 128.0 MB limit\".\n */\nfunction bodyTooLargeResponse(declaredBytes?: number): Response {\n const mb = (n: number) => `${(n / (1024 * 1024)).toFixed(1)} MB`\n const actual =\n declaredBytes === undefined ?\n `Request body exceeds the size github-router accepts`\n : `Request body is ${declaredBytes} bytes (${mb(declaredBytes)}), over `\n + `the size github-router accepts`\n return new Response(\n JSON.stringify({\n type: \"error\",\n error: {\n type: \"request_too_large\",\n message:\n `${actual}: at most ${MAX_REQUEST_BODY_BYTES} bytes `\n + `(${mb(MAX_REQUEST_BODY_BYTES)}), the same limit under bun and node. `\n + `This is usually an accumulated conversation or inline images `\n + `(base64 attachments are re-sent every turn) rather than one large `\n + `message — start a new session or drop the attachments.`,\n },\n }),\n { status: 413, headers: { \"content-type\": \"application/json\" } },\n )\n}\n\n/** srvx's canonical over-limit error, however it reaches us. */\nfunction isBodyTooLarge(error: unknown): boolean {\n return (\n typeof error === \"object\"\n && error !== null\n && (error as { code?: unknown }).code === \"ERR_BODY_TOO_LARGE\"\n )\n}\n\n/**\n * Enforce `MAX_REQUEST_BODY_BYTES` in-process, so the limit and the\n * rejection are the same on every runtime.\n *\n * Leaving it to the runtimes is what produced the divergence in the first\n * place, and their rejections are not interchangeable:\n *\n * - bun rejects at header-parse time and closes the connection while the\n * client is still uploading, so the client sees a dead socket rather\n * than the 413 (measured; see `TRANSPORT_BODY_CEILING_BYTES`).\n * - node lets the handler run and rejects the body READ with an\n * `ERR_BODY_TOO_LARGE` error. The app installs no Hono `onError`, so\n * that becomes `500 Internal Server Error` — indistinguishable from a\n * real proxy fault.\n *\n * Two layers, one threshold, applied uniformly:\n *\n * 1. A declared `Content-Length` over the limit is answered before the\n * body is read at all. This is the path every real client takes\n * (Claude Code / undici / curl all declare a length on a JSON body).\n * 2. Anything else — chunked, or a length that understates the body — is\n * caught mid-stream by srvx's own `limitRequestBody`, the same helper\n * its node and deno adapters use. Overflow is surfaced as the SAME\n * explained 413 rather than leaking out as a 500.\n *\n * So a body that declares no length is no longer a hole in the message\n * quality OR in the bound, and neither depends on which runtime is\n * serving. Verified end to end against both adapters with a real client:\n * declared-over and chunked-over each return an identical 413.\n */\nexport function withBodyLimit(fetchHandler: ServerHandler): ServerHandler {\n return async (request) => {\n const declared = request.headers.get(\"content-length\")\n // Only a plain integer is trusted as a declared length. Anything else\n // (absent, chunked, a comma-joined duplicate) is not guessed at — it\n // just falls through to layer 2, which enforces the same threshold.\n if (declared !== null && /^\\d+$/.test(declared)) {\n const bytes = Number(declared)\n if (bytes > MAX_REQUEST_BODY_BYTES) return bodyTooLargeResponse(bytes)\n }\n\n // `overflowed` is per-request state closed over by this one call, so\n // concurrent requests cannot see each other's flag.\n let overflowed = false\n const limited = limitRequestBody(request, MAX_REQUEST_BODY_BYTES, {\n createError: (max) => {\n overflowed = true\n return createBodyTooLargeError(max)\n },\n })\n\n try {\n const response = await fetchHandler(limited)\n // The flag is only ever set by a body read that failed, so the\n // handler cannot have produced a meaningful response; replacing it\n // is what stops the overflow surfacing as Hono's generic 500. A\n // route that never reads the body never trips this. Cancel what we\n // discard so a handler that did return a stream can't dangle.\n if (overflowed) {\n void response.body?.cancel().catch(() => {})\n return bodyTooLargeResponse()\n }\n return response\n } catch (error) {\n // Belt and braces for an overflow that propagates instead of being\n // caught by the framework.\n if (overflowed || isBodyTooLarge(error)) return bodyTooLargeResponse()\n throw error\n }\n }\n}\n\nexport interface ServerSetupOptions {\n port?: number\n verbose: boolean\n accountType: string\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n showToken: boolean\n proxyEnv: boolean\n extendedBetas: boolean\n browseEnabled: boolean\n fleetEnabled: boolean\n agentsEnabled: boolean\n powerBrowseEnabled: boolean\n humanlikeEnabled: boolean\n silent: boolean\n}\n\n/**\n * Build the srvx `serve()` options shared by the explicit-port and\n * random-port paths.\n *\n * Extracted and exported so the per-runtime overrides below are\n * assertable. `setupAndServe` itself performs auth and network I/O, so the\n * only way to pin this behaviour in a test is to make the options object\n * reachable on its own — and it needs pinning, because deleting either\n * override reintroduces a failure that looks like an upstream/network\n * problem rather than a config one.\n */\nexport function buildServeOptions(\n fetchHandler: ServerHandler,\n silent: boolean,\n): {\n fetch: ServerHandler\n hostname: string\n silent: boolean\n maxRequestBodySize: number\n bun: { idleTimeout: number }\n} {\n return {\n fetch: withBodyLimit(fetchHandler),\n hostname: \"127.0.0.1\",\n silent,\n // Pin the transport ceiling instead of inheriting one runtime's\n // default. Unset, srvx forwards nothing: bun applies its own 128 MB\n // default and node applies none, so the identical request 413s or\n // succeeds purely on which runtime is serving, with no signal to the\n // user that the runtime was the variable.\n //\n // TOP-LEVEL on purpose, not in the `bun` namespace: srvx's top-level\n // option reaches every adapter, so both runtimes get the same number.\n // A bun-only override would leave the two on different thresholds,\n // which is the defect, not a fix for it.\n //\n // This is the outer bound, NOT the policy — `withBodyLimit` above\n // enforces MAX_REQUEST_BODY_BYTES in-process, identically everywhere,\n // and answers first. See TRANSPORT_BODY_CEILING_BYTES for why it sits\n // so far above, and MAX_REQUEST_BODY_BYTES for why the proxy caps at\n // all rather than matching node's absence of a limit.\n maxRequestBodySize: TRANSPORT_BODY_CEILING_BYTES,\n // Bun-only: disable `Bun.serve`'s per-connection idle reaper.\n //\n // Bun defaults `idleTimeout` to 10 seconds and applies it to a\n // STREAMING response: if no bytes reach the socket for ~10s while a\n // ReadableStream body is open, Bun kills the connection. Node's\n // `node:http` (the srvx node adapter) has no equivalent default\n // (`server.timeout === 0`), which is why this only ever bit users\n // running the proxy under bun.\n //\n // Upstream Copilot routinely goes quiet for longer than that\n // mid-stream — extended thinking and prompt processing on a large\n // accumulated context both produce >10s SSE gaps. The client (undici)\n // surfaces the kill as `UND_ERR_SOCKET other side closed`, which\n // Claude Code reports as `Unable to connect to API (ECONNRESET)`.\n // Because the retry replays the same large context, every retry\n // reproduces the same gap and the whole 10-attempt backoff burns down.\n // Reproduced end-to-end: headers + first byte at +12.7s, socket killed\n // at +24.0s (an 11.3s mid-stream gap); the identical request through\n // the node adapter completes.\n //\n // Disabled rather than raised to Bun's 255s maximum: the proxy already\n // owns upstream-stall detection via UPSTREAM_INACTIVITY_TIMEOUT_MS\n // (`relayAnthropicStream`, default 5 min), and a 255s socket reaper\n // would fire BEFORE that guard and reintroduce this same bug at a\n // longer horizon. One authority for stream liveness, and it is ours.\n //\n // Namespaced under `bun`, so the node adapter ignores it. Note that\n // the body ceiling above is deliberately NOT namespaced here — a\n // per-runtime body limit is the bug, not the fix.\n bun: { idleTimeout: 0 },\n }\n}\n\nexport async function setupAndServe(\n options: ServerSetupOptions,\n): Promise<{ server: ReturnType<typeof serve>; serverUrl: string }> {\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.extendedBetas = options.extendedBetas\n // --browse + GH_ROUTER_ENABLE_BROWSE=1 are equivalent; either enables\n // the browser-control MCP tools. The env-var path is the convenience\n // for users who don't want to retype the flag every session, mirroring\n // the GH_ROUTER_DISABLE_WORKER_TOOLS / GH_ROUTER_LOG_PEER_MCP convention.\n state.browseEnabled =\n options.browseEnabled || process.env.GH_ROUTER_ENABLE_BROWSE === \"1\"\n state.fleetEnabled =\n options.fleetEnabled || process.env.GH_ROUTER_ENABLE_FLEET === \"1\"\n // --agents + GH_ROUTER_ENABLE_AGENTS=1 enable the first-mate\n // cloud-agent orchestration surface (the write-token GitHub layer +\n // the `mcp__first-mate__*` tools). The tools additionally require the\n // write token to be present (see `agentToolsEnabled()`), so the flag\n // alone doesn't expose an unauthenticated surface.\n state.agentsEnabled =\n options.agentsEnabled || process.env.GH_ROUTER_ENABLE_AGENTS === \"1\"\n // --power-browse implies --browse: power mode exposes the FULL\n // browser tool surface (read_page, mouse, drag, scroll, keyboard,\n // type, eval_js, diagnostics, find, locate) on top of the lead\n // surface. There is no \"power without basic\" state, so enabling\n // power forces basic on too.\n state.powerBrowseEnabled =\n options.powerBrowseEnabled || process.env.GH_ROUTER_ENABLE_POWER_BROWSE === \"1\"\n if (state.powerBrowseEnabled) state.browseEnabled = true\n // Humanlike pacing override. GH_ROUTER_BROWSER_NO_HUMANLIKE=1 wins\n // over every other signal so test runs stay deterministic.\n if (process.env.GH_ROUTER_BROWSER_NO_HUMANLIKE === \"1\") {\n state.humanlikeForce = \"off\"\n } else if (options.humanlikeEnabled || process.env.GH_ROUTER_HUMANLIKE === \"1\") {\n state.humanlikeForce = \"on\"\n } else {\n state.humanlikeForce = \"auto\"\n }\n\n if (process.env.COPILOT_API_URL) {\n state.copilotApiUrl = process.env.COPILOT_API_URL\n }\n\n await ensurePaths()\n // The two editor-identity lookups are independent of each other and of the\n // token chain below, so they overlap. Both are cached with a 12h TTL\n // (`editor-version-cache.ts`), so on the common path neither touches the\n // network at all and this only bounds the cold case.\n //\n // `ensurePaths()` deliberately stays a prerequisite rather than joining the\n // batch: it is the FS init these writes land in, and folding it in would\n // let network work proceed past a filesystem failure.\n await Promise.all([cacheVSCodeVersion(), cacheCopilotVersion()])\n\n if (options.githubToken) {\n state.githubToken = options.githubToken\n consola.info(\"Using provided GitHub token\")\n } else {\n await setupGitHubToken()\n }\n\n // First-mate agent orchestration needs a second, write-capable GitHub\n // token (repo/workflow/read:org via the GitHub CLI OAuth client). Only\n // when opted in via --agents / GH_ROUTER_ENABLE_AGENTS. A failure here\n // is fatal to the opted-in surface (the tools won't work without it)\n // but must not break plain proxy operation — so it's gated on the flag.\n if (state.agentsEnabled) {\n await setupGitHubAgentToken()\n }\n\n await setupCopilotToken()\n await cacheModels()\n\n consola.debug(\n `Available models: \\n${state.models?.data.map((model) => `- ${model.id}`).join(\"\\n\")}`,\n )\n\n const serveOptions = buildServeOptions(\n app.fetch as ServerHandler,\n options.silent,\n )\n\n let srvxServer: ReturnType<typeof serve> | undefined\n\n if (options.port !== undefined) {\n // Explicit port — no retry\n srvxServer = serve({ ...serveOptions, port: options.port })\n } else {\n // Random available port with retry\n let lastError: unknown\n for (let attempt = 0; attempt < MAX_PORT_RETRIES; attempt++) {\n const candidatePort = generateRandomPort()\n try {\n srvxServer = serve({ ...serveOptions, port: candidatePort })\n break\n } catch (error) {\n lastError = error\n const isAddrInUse =\n error instanceof Error\n && (error.message.includes(\"EADDRINUSE\")\n || error.message.includes(\"address already in use\")\n || (\"code\" in error\n && (error as NodeJS.ErrnoException).code === \"EADDRINUSE\"))\n if (!isAddrInUse) throw error\n consola.debug(`Port ${candidatePort} in use, trying another...`)\n }\n }\n\n if (srvxServer === undefined) {\n throw new Error(\n `Failed to find an available port after ${MAX_PORT_RETRIES} attempts. `\n + `Specify a port with --port or free some ports. Last error: ${lastError}`,\n )\n }\n }\n\n // Wait for the server to be listening before reading the URL\n await srvxServer.ready()\n const url = srvxServer.url\n if (!url) {\n throw new Error(\"Server started but URL is not available\")\n }\n const serverUrl = url.replace(/\\/$/, \"\")\n\n // Opt-in (GH_ROUTER_FM_DAEMON=1; default OFF) auto-spawn of the first-mate\n // scheduler daemon as a SEPARATE process. The [fm-heartbeat] cron is the\n // default driver; this is experimental. Never throws. The returned handle is\n // wired to shutdown so a drive-primary daemon can never orphan and keep\n // merging PRs after the proxy exits (Windows has no process-group reaping).\n // Teardown EOFs the child's stdin first (graceful lease/pidfile release — the\n // only graceful path on Windows), then hard-kills as a non-blocking backstop.\n try {\n const handle = maybeSpawnDaemon({ agentsEnabled: agentToolsEnabled() })\n if (handle) {\n wireDaemonTeardown(handle)\n consola.debug(`first-mate daemon spawn attempted (pid ${handle.pid ?? \"?\"}).`)\n }\n } catch (err) {\n consola.debug(\"first-mate daemon auto-spawn skipped:\", err)\n }\n\n return { server: srvxServer, serverUrl }\n}\n\n/** Shared CLI arg definitions for all server commands. */\nexport const sharedServerArgs = {\n port: {\n alias: \"p\",\n type: \"string\" as const,\n description: \"Port to listen on\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\" as const,\n default: false,\n description: \"Enable verbose logging\",\n },\n \"account-type\": {\n alias: \"a\",\n type: \"string\" as const,\n default: \"enterprise\",\n description: \"Account type to use (individual, business, enterprise)\",\n },\n manual: {\n type: \"boolean\" as const,\n default: false,\n description: \"Enable manual request approval\",\n },\n \"rate-limit\": {\n alias: \"r\",\n type: \"string\" as const,\n description: \"Rate limit in seconds between requests\",\n },\n wait: {\n alias: \"w\",\n type: \"boolean\" as const,\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\" as const,\n description:\n \"Provide GitHub token directly (must be generated using the `auth` subcommand)\",\n },\n \"show-token\": {\n type: \"boolean\" as const,\n default: false,\n description: \"Show GitHub and Copilot tokens on fetch and refresh\",\n },\n \"proxy-env\": {\n type: \"boolean\" as const,\n default: false,\n description: \"Initialize proxy from environment variables\",\n },\n \"extended-betas\": {\n type: \"boolean\" as const,\n default: false,\n description:\n \"Forward extended beta headers for Claude CLI compatibility (default: VS Code-only)\",\n },\n browse: {\n type: \"boolean\" as const,\n default: false,\n description:\n \"Enable the browser-control MCP tools (browser_open_tab, browser_screenshot, browser_click, etc.) on /mcp. Requires Chrome or Edge installed; the bundled extension must be loaded on first tool call (the proxy returns install_required with a Load Unpacked path and the expected extension ID). Off by default; can also be enabled with GH_ROUTER_ENABLE_BROWSE=1.\",\n },\n fleet: {\n type: \"boolean\" as const,\n default: false,\n description:\n \"Enable the fleet session-control MCP tools (mcp__fleet__*) on /mcp for driving sessions across remote ai-or-die instances over their tunnels. Off by default; also enabled with GH_ROUTER_ENABLE_FLEET=1.\",\n },\n agents: {\n type: \"boolean\" as const,\n default: false,\n description:\n \"Enable the first-mate cloud-agent orchestration surface (mcp__first-mate__*): a durable controller that drives GitHub cloud coding agents (Copilot/Anthropic/OpenAI) across research/plan/implement/test/merge. Triggers a second GitHub device-login for a write-capable token (repo, workflow, read:org). Off by default; also enabled with GH_ROUTER_ENABLE_AGENTS=1.\",\n },\n \"power-browse\": {\n type: \"boolean\" as const,\n default: false,\n description:\n \"Expose the full ~18-tool browser MCP surface (raw read_page, mouse / drag / scroll / keyboard / type primitives, eval_js, diagnostics, find, locate). Default --browse exposes only the 6 lead-model tools (act, observe, extract, navigate, screenshot, open_tab) that hide DOM details behind intent. Implies --browse. Off by default; can also be enabled with GH_ROUTER_ENABLE_POWER_BROWSE=1.\",\n },\n humanlike: {\n type: \"boolean\" as const,\n default: false,\n description:\n \"Force humanlike pacing on ALL browser tool dispatches: Beta-distributed inter-action delays (800-4600 ms), Bezier mouse trajectories with overshoot-and-correct, per-keystroke jitter with word-end pauses, scroll chunking. Use for known anti-bot sites (Cloudflare, Datadome). Off by default (auto mode); GH_ROUTER_HUMANLIKE=1 is the env equivalent. GH_ROUTER_BROWSER_NO_HUMANLIKE=1 hard-disables (wins over --humanlike, for tests).\",\n },\n \"self-update\": {\n type: \"boolean\" as const,\n default: true,\n description:\n \"Update github-router itself to the latest npm version on launch (throttled once/hour). Best-effort and non-blocking: the proxy serves immediately and a detached updater applies the new version after this process exits (it takes effect on the NEXT launch; the running process keeps its current build). Disable with --no-self-update or GH_ROUTER_NO_SELF_UPDATE=1. Skipped silently if npm/network unavailable.\",\n },\n} as const\n\nconst allowedAccountTypes = new Set([\"individual\", \"business\", \"enterprise\"])\n\n/** Parse shared server args into ServerSetupOptions fields. */\nexport function parseSharedArgs(args: Record<string, unknown>): {\n port?: number\n verbose: boolean\n accountType: string\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n showToken: boolean\n proxyEnv: boolean\n extendedBetas: boolean\n browseEnabled: boolean\n fleetEnabled: boolean\n agentsEnabled: boolean\n powerBrowseEnabled: boolean\n humanlikeEnabled: boolean\n} {\n const portRaw = args.port as string | undefined\n let port: number | undefined\n if (portRaw !== undefined) {\n port = Number.parseInt(portRaw, 10)\n if (Number.isNaN(port) || port <= 0 || port > 65535) {\n throw new Error(\"Invalid port. Must be between 1 and 65535.\")\n }\n }\n\n const accountType = (args[\"account-type\"] as string) ?? \"enterprise\"\n if (!allowedAccountTypes.has(accountType)) {\n throw new Error(\n \"Invalid account type. Must be individual, business, or enterprise.\",\n )\n }\n\n const rateLimitRaw = args[\"rate-limit\"] as string | undefined\n let rateLimit: number | undefined\n if (rateLimitRaw !== undefined) {\n rateLimit = Number.parseInt(rateLimitRaw, 10)\n if (Number.isNaN(rateLimit) || rateLimit <= 0) {\n throw new Error(\"Invalid rate limit. Must be a positive integer.\")\n }\n }\n\n const rateLimitWait = (args.wait as boolean) && rateLimit !== undefined\n if ((args.wait as boolean) && rateLimit === undefined) {\n consola.warn(\"Rate limit wait ignored because no rate limit was set.\")\n }\n\n const githubToken =\n (args[\"github-token\"] as string | undefined) ?? process.env.GH_TOKEN\n\n return {\n port,\n verbose: args.verbose as boolean,\n accountType,\n manual: args.manual as boolean,\n rateLimit,\n rateLimitWait,\n githubToken,\n showToken: args[\"show-token\"] as boolean,\n proxyEnv: args[\"proxy-env\"] as boolean,\n extendedBetas: args[\"extended-betas\"] as boolean,\n browseEnabled: args.browse as boolean,\n fleetEnabled: args.fleet as boolean,\n agentsEnabled: args.agents as boolean,\n powerBrowseEnabled: args[\"power-browse\"] as boolean,\n humanlikeEnabled: args.humanlike as boolean,\n }\n}\n\n/**\n * Non-Claude models we surface as first-class, selectable rows in Claude\n * Code's model picker (Phase 3 of native-non-claude-models). The main\n * agent loop runs on them through the `/v1/messages` translation shim\n * (`src/lib/anthropic-translate/*`, branched in `routes/messages/handler.ts`)\n * that forwards non-Claude targets to Copilot `/responses` (gpt) or\n * `/chat/completions` (gemini). The exact gemini id is\n * `gemini-3.1-pro-preview` (preview slug — NOT `gemini-3.1-pro`).\n *\n * Display labels only: the gateway-model cache schema Claude Code reads is\n * `{id, display_name?}` per model — there is NO per-model context-window\n * field. Context accounting is instead driven off the id itself, via the\n * `[1m]` literal-bracket suffix `nativeSelectableModelsInCatalog` attaches to\n * every row the catalog says serves >=1M. See `withOneMSuffix`.\n */\nconst NATIVE_NON_CLAUDE_MODELS: ReadonlyArray<{\n id: string\n displayName: string\n}> = [\n { id: \"gpt-5.6-sol\", displayName: \"GPT-5.6 Sol\" },\n { id: \"gpt-5.5\", displayName: \"GPT-5.5\" },\n { id: \"gpt-5.3-codex\", displayName: \"GPT-5.3 Codex\" },\n { id: \"gemini-3.5-flash\", displayName: \"Gemini 3.5 Flash\" },\n { id: \"gemini-3.1-pro-preview\", displayName: \"Gemini 3.1 Pro (preview)\" },\n]\n\n/**\n * The subset of `NATIVE_NON_CLAUDE_MODELS` actually present in the live\n * Copilot catalog. License tiers differ (gpt-5.5 needs\n * pro_plus/business/enterprise/max; gemini-3.5-flash is absent on\n * edu/individual_trial), so a model missing from the catalog is silently\n * dropped — the caller then neither enables discovery nor writes a cache\n * for it, and lesser tiers see the unchanged picker. Pure (reads\n * `state.models`), so it is unit-testable without side effects.\n *\n * The projected id carries a `[1m]` suffix when the catalog advertises a\n * >=1M window for it, because Claude Code budgets a gateway-discovered row\n * at its 200K default otherwise — `gpt-5.6-sol` (1,050,000) would compact at\n * roughly a fifth of its real window. `withOneMSuffix` is catalog-gated, so\n * `gpt-5.3-codex` (400K) stays bare and keeps the conservative accounting;\n * over-budgeting it would trade premature compaction for a hard overflow.\n * The lookup below still keys off the BARE id — the decoration is applied\n * only to the value handed to Claude Code.\n */\nexport function nativeSelectableModelsInCatalog(): Array<{\n id: string\n display_name: string\n}> {\n const catalog = state.models?.data\n if (!catalog || catalog.length === 0) return []\n const present = new Set(catalog.map((m) => m.id))\n return NATIVE_NON_CLAUDE_MODELS.filter((m) => present.has(m.id)).map((m) => ({\n id: withOneMSuffix(m.id),\n display_name: m.displayName,\n }))\n}\n\n/**\n * Pre-seed Claude Code's gateway-model discovery cache so the non-Claude\n * models appear as selectable picker rows WITHOUT the network fetch.\n *\n * Verified against the installed Claude Code build (2.1.201): the picker\n * builder reads `<CLAUDE_CONFIG_DIR>/cache/gateway-models.json`\n * (schema `{baseUrl: string, fetchedAt: number, models: [{id, display_name?}]}`)\n * and — when gateway discovery is enabled (first-party auth mode +\n * `CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY` set + a non-`api.anthropic.com`\n * `ANTHROPIC_BASE_URL`, all true for the proxy) — maps each cached model to\n * a picker row `{value: id, label: display_name}`. Critically, the\n * cache-READ path applies NO id filter; the `/^(claude|anthropic)/i` filter\n * lives ONLY in the network-FETCH path. So a pre-seeded cache can carry the\n * real Copilot ids (`gpt-5.5`, `gemini-3.1-pro-preview`, …) — no `claude-*`\n * alias needed — and selecting a row sends that real id, which\n * `resolveModel()` exact-matches and the `/v1/messages` shim routes.\n *\n * The network fetch never overwrites this seed: it bails when nonessential\n * traffic is disabled, and the proxy ALWAYS sets\n * `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`, so the fetch returns before\n * it can write. The seed is therefore authoritative for the session.\n *\n * `baseUrl` MUST equal the `ANTHROPIC_BASE_URL` Claude Code sees\n * (`serverUrl`) or the cache is discarded. `configDir` defaults to\n * `PATHS.CLAUDE_CONFIG_DIR` — the same dir the proxy points\n * `CLAUDE_CONFIG_DIR` at — so the write target and Claude Code's read\n * target are identical by construction.\n *\n * Best-effort: every failure is swallowed — a missing picker row must never\n * break launch. This is coupled to Claude Code's internal cache path/schema;\n * if a future build changes them the read simply ignores the seed and the\n * rows don't appear (graceful degradation). Returns whether a file was\n * written (for tests/observability).\n *\n * The write is atomic (temp file in the same dir + rename) so a Claude Code\n * read can never observe a torn/partial JSON (which its safeParse would\n * reject, dropping the rows). Rename-over-existing is atomic on POSIX and\n * Windows (libuv MoveFileEx REPLACE_EXISTING).\n */\nexport function seedGatewayModelCache(\n serverUrl: string,\n models: ReadonlyArray<{ id: string; display_name: string }>,\n configDir: string = PATHS.CLAUDE_CONFIG_DIR,\n): boolean {\n if (models.length === 0) return false\n const cacheDir = nodePath.join(configDir, \"cache\")\n const target = nodePath.join(cacheDir, \"gateway-models.json\")\n const tmp = nodePath.join(\n cacheDir,\n `gateway-models.json.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`,\n )\n try {\n fs.mkdirSync(cacheDir, { recursive: true })\n const payload = {\n baseUrl: serverUrl,\n fetchedAt: Date.now(),\n models: models.map((m) => ({ id: m.id, display_name: m.display_name })),\n }\n fs.writeFileSync(tmp, JSON.stringify(payload), \"utf-8\")\n fs.renameSync(tmp, target)\n return true\n } catch {\n try {\n fs.rmSync(tmp, { force: true })\n } catch {\n /* best-effort cleanup */\n }\n return false\n }\n}\n\n/**\n * Remove any seeded gateway-model cache. Called when the current catalog\n * carries none of the target models, so a user who has pinned\n * `CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY` on cannot surface rows for\n * models that are no longer available. Best-effort (per-launch config dirs\n * make a stale file rare, but this closes the pinned-port + catalog-change\n * seam). Never throws.\n */\nexport function clearGatewayModelCache(\n configDir: string = PATHS.CLAUDE_CONFIG_DIR,\n): void {\n try {\n fs.rmSync(nodePath.join(configDir, \"cache\", \"gateway-models.json\"), {\n force: true,\n })\n } catch {\n /* best-effort */\n }\n}\n\n/**\n * Build environment variables for Claude Code.\n *\n * The parent env is sanitized of every key in `STRIPPED_PARENT_ENV_KEYS`\n * (see `src/lib/launch.ts`) BEFORE these overrides are merged in, so we\n * only need to provide the positive values.\n *\n * Auth precedence in Claude Code (https://code.claude.com/docs/en/iam),\n * after the github-router substrate fix:\n * 1. Cloud provider (CLAUDE_CODE_USE_BEDROCK / VERTEX / FOUNDRY) — stripped at parent.\n * 2. ANTHROPIC_AUTH_TOKEN — NOT set by the proxy. Stripped at parent\n * (no env-source auth in the spawned child at all).\n * 3. ANTHROPIC_API_KEY — stripped at parent.\n * 4. apiKeyHelper in settings.json — copied into our config dir as\n * part of the mirror; if the user defined one, it still fires\n * and may mint an `x-api-key` header. Copilot ignores `x-api-key`,\n * so behavior is unchanged from before this fix.\n * 5. CLAUDE_CODE_OAUTH_TOKEN — stripped at parent.\n * 6. Subscription OAuth (Keychain / `<CLAUDE_CONFIG_DIR>/.credentials.json`)\n * — the credentials file is OURS (synthetic blob, written by\n * `ensureClaudeConfigMirror`). Claude Code reads accessToken from\n * it and sends as `Authorization: Bearer <accessToken>`. The\n * teammate-spawn allowlist propagates `CLAUDE_CONFIG_DIR` to\n * children, so spawned teammates find the same synthetic credential\n * and authenticate (the bug this whole fix addresses).\n *\n * `CLAUDE_CONFIG_DIR` activates Claude Code's per-config-dir keychain\n * isolation (per binary-grep of v2.1.126's `iN()` function: when set,\n * the keychain service name becomes `Claude Code-<sha256(path)[0..8]>`,\n * missing the user's real `Claude Code` entry). Pointing it at our\n * snapshot-copied `PATHS.CLAUDE_CONFIG_DIR` preserves user customization\n * (mirrored settings.json, skills, MCP, hooks, CLAUDE.md, custom\n * agents) while giving teammates a credential they can find on disk.\n *\n * No-401 invariant: Claude Code's reactive refresh path (`SZ1` →\n * `D3(0,true,...)`) fires on any 401 from upstream. The synthetic\n * refreshToken would fail any real refresh attempt, so the proxy\n * MUST NOT return 401 on the Anthropic-shape boundary even when\n * upstream Copilot returns 401. See `src/routes/messages/handler.ts`.\n */\nexport function getClaudeCodeEnvVars(\n serverUrl: string,\n model?: string,\n): Record<string, string> {\n const vars: Record<string, string> = {\n // Route to the proxy\n ANTHROPIC_BASE_URL: serverUrl,\n // CLAUDE_CONFIG_DIR points at the router-owned snapshot mirror;\n // the synthetic .credentials.json inside it provides the OAuth\n // accessToken that Claude Code sends as Bearer. See\n // `ensureClaudeConfigMirror` in `src/lib/paths.ts`.\n CLAUDE_CONFIG_DIR: PATHS.CLAUDE_CONFIG_DIR,\n // Suppress non-essential telemetry/model calls. The first two are\n // Anthropic's own knobs (per cc-backup managedEnv.ts); the third\n // (`DISABLE_TELEMETRY`) suppresses Datadog/Statsig/etc. external\n // analytics that would otherwise run regardless of the proxy. None of\n // these calls reach the proxy (they hit external hosts), but they\n // consume user resources and may leak metadata. Setting all three\n // turns the spawned child into a quiet local-only session.\n DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\n DISABLE_TELEMETRY: \"1\",\n }\n if (model) vars.ANTHROPIC_MODEL = model\n\n // Extend Claude Code's MCP per-tool-call wait window. Two distinct\n // env vars are at play (per binary inspection of v2.1.141 by the\n // peer-MCP team's empirical SDK test, 2026-05-14):\n //\n // - MCP_TIMEOUT — historical/general MCP timeout, may apply to\n // server-startup or initial-handshake but NOT confirmed to reach\n // the per-tool-call HTTP wait on v2.1.138-141 (regressions\n // #50289 / #52137 documented this as silently-ignored on the\n // per-call path). Kept as belt-and-suspenders.\n //\n // - MCP_TOOL_TIMEOUT — the load-bearing one. v2.1.141's `y13()`\n // reads `parseInt(process.env.MCP_TOOL_TIMEOUT)` for the per-\n // tool-call timeout passed to MCP SDK's `.callTool({...},\n // schema, {timeout: W})`. Default `1e8` ms (~27.7 hours) when\n // the env is unset. Set to 6h15m (`resolveMcpToolTimeoutMs()`,\n // override `GH_ROUTER_MCP_TOOL_TIMEOUT_MS`): finite-but-large\n // (surfaces regressions where the SDK silently caps at 60s, AND\n // bounds runaway calls) but high enough that an autonomous worker\n // can do up to its 6h wall-clock of real work AND still return its\n // result before the harness gives up. INVARIANT: the worker\n // wall-clock (default 6h, per-call overridable) is clamped to\n // `workerWallClockCeilingMs()` = this timeout − 15 min teardown\n // headroom (`MCP_TIMEOUT_HEADROOM_MS`), so a slow/runaway worker\n // aborts gracefully (partial work + `[halted: wallclock]`) a full\n // headroom before the harness hard-kills it — 6h worker < 6h15m\n // ceiling. Both live in `worker-agent/budget.ts` (single source of\n // truth) so the two numbers can never drift apart.\n //\n // Without the SDK's `resetTimeoutOnProgress` opt-in (which Claude\n // Code does not pass), SSE notifications/progress events DO NOT\n // reset the per-call timer — they only fire UI callbacks. So\n // MCP_TOOL_TIMEOUT is the actual lever for long-running peer-MCP\n // calls, not the SSE response transport. SSE remains valuable as\n // the canonical Streamable HTTP shape and for progress UI, but the\n // ceiling-busting work is done by these env vars.\n //\n // Presence-based guard (symmetric with ANTHROPIC_SMALL_FAST_MODEL /\n // the tier-default / experimental-enables guards below): if the parent\n // env already set either key, preserve the user's value — only inject\n // our default when unset. Neither key is in `STRIPPED_PARENT_ENV_KEYS`,\n // so an unset override lets the parent value flow through naturally.\n const mcpToolTimeoutMs = String(resolveMcpToolTimeoutMs())\n if (process.env.MCP_TIMEOUT === undefined) vars.MCP_TIMEOUT = mcpToolTimeoutMs\n if (process.env.MCP_TOOL_TIMEOUT === undefined) {\n vars.MCP_TOOL_TIMEOUT = mcpToolTimeoutMs\n }\n\n // Default the small/fast tier model (used by Claude Code for status\n // text, auto-compact summaries, session titles, background ops) to\n // claude-sonnet-5. Anthropic-published dashed slug that is also the\n // Copilot catalog id verbatim (no dotted variant), so resolveModel\n // resolves it via an exact catalog match at request time.\n // We deliberately pass Sonnet rather than Haiku here: on the canonical\n // Copilot-Enterprise deployment the quality lift on background ops\n // (compaction summaries, session titles) is worth more than Haiku's\n // marginal latency/cost edge, and Copilot bills per-request by\n // multiplier rather than per-token. Sonnet 5 is both the newest Sonnet\n // and cheaper than Sonnet 4.6 per the live catalog (input/output\n // multipliers 200/1000 vs 300/1500), so it strictly dominates the\n // prior default for this tier. The /model picker's Haiku tier row\n // (ANTHROPIC_DEFAULT_HAIKU_MODEL below) is likewise seeded to\n // claude-sonnet-5 so the cheap-tier pick also lands on Sonnet 5.\n // Presence-based guard preserves any user-set value, including the\n // dated slug variant or a different family (gemini, gpt) for users\n // who have custom Copilot mappings — symmetric with the\n // ANTHROPIC_SMALL_FAST_MODEL pass-through documented in launch.ts's\n // STRIPPED_PARENT_ENV_KEYS comment.\n if (process.env.ANTHROPIC_SMALL_FAST_MODEL === undefined) {\n vars.ANTHROPIC_SMALL_FAST_MODEL = \"claude-sonnet-5\"\n }\n\n // Tier-default knobs read by Claude Code's /model picker (cc-backup\n // src/utils/model/modelOptions.ts:78,109,167) when the user invokes\n // the picker to switch model. Without these, the picker shows\n // Anthropic's catalog-baseline entries (which may be stale relative\n // to what Copilot has). Setting them seeds the three tier rows with\n // ids the proxy's resolveModel knows how to route.\n //\n // Why NO [1m] suffix on the Sonnet/Haiku tier rows: the picker-row tier\n // defaults are always the bare slug — the [1m] decoration for the\n // *active* default lives on ANTHROPIC_MODEL itself (see pickClaudeDefault\n // in src/lib/port.ts) and is cap-aware against the live catalog via the\n // dual-signal detector (sibling-slug regex OR base-slug\n // max_context_window_tokens). Seeding a bracketed slug here would bypass\n // that cap-awareness and risk a request Copilot 400s (unrecognized\n // bracket) or local over-accounting of context. Note both the Sonnet and\n // Haiku tier rows are seeded to claude-sonnet-5 (the Haiku row is NOT a\n // haiku slug) to match the ANTHROPIC_SMALL_FAST_MODEL default above — the\n // Sonnet/cheap-tier picks land on Sonnet 5, which is newer and cheaper than\n // the prior Sonnet-4.6 / Haiku-4.5 defaults.\n //\n // Presence-based guard symmetric with the SMALL_FAST_MODEL guard\n // above — preserves any value (including 0/false/off/unrecognized)\n // the user has explicitly set.\n if (process.env.ANTHROPIC_DEFAULT_SONNET_MODEL === undefined) {\n vars.ANTHROPIC_DEFAULT_SONNET_MODEL = \"claude-sonnet-5\"\n }\n if (process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL === undefined) {\n vars.ANTHROPIC_DEFAULT_HAIKU_MODEL = \"claude-sonnet-5\"\n }\n if (process.env.ANTHROPIC_DEFAULT_OPUS_MODEL === undefined) {\n vars.ANTHROPIC_DEFAULT_OPUS_MODEL = \"claude-opus-5\"\n }\n\n // Plan-mode (v2) Phase-2 \"Plan\" agent parallelism. Claude Code's\n // getPlanModeV2AgentCount() (verified verbatim in the claude v2.1.158\n // binary, minified fn `bGK`) gates this on subscription tier:\n // env override CLAUDE_CODE_PLAN_V2_AGENT_COUNT (1..10) wins, else\n // max+rateLimitTier=default_claude_max_20x -> 3, enterprise/team -> 3,\n // else 1.\n // Our synthetic credential is subscriptionType:\"max\" with\n // rateLimitTier:\"default_claude_max_20x\", so the natural tier path now\n // yields 3 — but we pin it higher here. The env override is the clean,\n // tier-independent lever (wins unconditionally, range 1..10), so the\n // count holds even if the credential tier ever changes. Presence-guarded,\n // symmetric with the tier-default guards above: any user-set value\n // (incl. \"0\"/unset intent) wins; we only inject the default when unset.\n if (process.env.CLAUDE_CODE_PLAN_V2_AGENT_COUNT === undefined) {\n vars.CLAUDE_CODE_PLAN_V2_AGENT_COUNT = \"7\"\n }\n\n // Auto-enable Anthropic's experimental \"leverage\" features for proxied\n // claude sessions. Symmetric with the leverage-policy default\n // (extended-betas ON for `claude` subcommand): users running\n // `github-router claude` opted in for the Claude Code feature surface,\n // and these experimental gates default off for non-Anthropic users\n // (gated by GrowthBook flags that don't fire outside Anthropic).\n //\n // Presence-based guard: if the parent env has set ANY value for these\n // keys (including \"0\", \"false\", \"no\", \"off\", or any unrecognized\n // value), preserve the user's intent — only inject \"1\" when the key\n // is unset. The parent env survives `buildLaunchCommand`'s sanitize\n // step because none of these keys are in `STRIPPED_PARENT_ENV_KEYS`,\n // so an unset proxy var means the parent's value (if any) wins\n // naturally.\n //\n // ADVISOR has a documented `CLAUDE_CODE_DISABLE_ADVISOR_TOOL=1` hard\n // opt-out that wins via JI()'s ordering (DISABLE checked before\n // ENABLE). FORK_SUBAGENT and AGENT_TEAMS rely on Anthropic's SH()\n // falsy semantics for opt-out (\"0\"/\"false\"/\"no\"/\"off\"/empty all opt\n // out — preserved by the presence guard). FINE_GRAINED_TOOL_STREAMING\n // is explicitly recommended by Anthropic's docs at\n // code.claude.com/docs/en/env-vars: \"Set to `1` to force on when\n // routing through a proxy via ANTHROPIC_BASE_URL\". TASKS only\n // manifests in `claude -p` headless mode.\n //\n // GATEWAY_MODEL_DISCOVERY is intentionally NOT enabled here — Claude\n // Code's hardcoded slug registry maps slugs to capabilities, not just\n // labels; Copilot's slugs (claude-opus-4.6-1m) don't match\n // Anthropic's registry (claude-opus-4-6), so dynamic discovery would\n // silently degrade advanced tool use. Enable it intentionally only\n // after building a slug-translation shim in /v1/models. See\n // CLAUDE.md \"Experimental Claude Code features auto-enabled\".\n const experimentalEnables: ReadonlyArray<string> = [\n \"CLAUDE_CODE_ENABLE_EXPERIMENTAL_ADVISOR_TOOL\",\n \"CLAUDE_CODE_FORK_SUBAGENT\",\n \"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS\",\n \"CLAUDE_CODE_ENABLE_FINE_GRAINED_TOOL_STREAMING\",\n \"CLAUDE_CODE_ENABLE_TASKS\",\n ]\n for (const key of experimentalEnables) {\n if (process.env[key] === undefined) {\n vars[key] = \"1\"\n }\n }\n\n // Native selection of the four non-Claude models (Phase 3). Surface\n // gpt-5.5, gpt-5.3-codex, gemini-3.5-flash, gemini-3.1-pro-preview as\n // selectable rows in Claude Code's model picker — ADDITIVELY, without\n // touching the opus/sonnet/haiku tier defaults (ANTHROPIC_DEFAULT_*,\n // ANTHROPIC_MODEL, ANTHROPIC_SMALL_FAST_MODEL) seeded above.\n //\n // Mechanism (verified against installed Claude Code 2.1.201): the ONLY\n // env lever that adds MORE THAN ONE selectable row is gateway model\n // discovery — ANTHROPIC_CUSTOM_MODEL_OPTION adds exactly one. Discovery's\n // NETWORK fetch is blocked here (it never reads the synthetic OAuth\n // credential, and bails on CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1),\n // but its cache-READ path is not — so we (1) enable discovery and (2)\n // pre-seed its cache with the real Copilot ids (seedGatewayModelCache).\n // The cache-read applies no id filter, so no claude-* alias / no\n // /v1/models normalization is needed, and the picker rows carry the real\n // ids the /v1/messages shim already routes.\n //\n // Non-regression is structural: the fetch that could otherwise discover\n // Copilot's dotted claude-* slugs (and degrade tier capability mapping —\n // the reason discovery is normally left off) is permanently blocked, and\n // the cache we seed contains ONLY these four non-Claude models. Tiers are\n // untouched.\n //\n // Gated on at least one target being in the live catalog (license tiers\n // differ) and presence-guarded: a user-set discovery value always wins.\n // The guard checks BOTH the parent env (consistent with every other guard\n // in this function) AND `vars` (defence against a future in-function\n // refactor that sets this key earlier). Discovery is enabled only when the\n // cache seed actually landed, so we never turn on a feature with nothing\n // to show. When no target is in the catalog we clear any prior seed so a\n // user-pinned discovery flag can't surface stale rows.\n const nativeModels = nativeSelectableModelsInCatalog()\n if (nativeModels.length > 0) {\n const seeded = seedGatewayModelCache(serverUrl, nativeModels)\n if (\n seeded\n && process.env.CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY === undefined\n && vars.CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY === undefined\n ) {\n vars.CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY = \"1\"\n }\n } else {\n clearGatewayModelCache()\n }\n\n // Prepend the toolbelt bin dir to the spawned agent's PATH so it can\n // call rg/fd/jq/sd/sg/yq directly. Uses the parent's existing PATH\n // key casing to avoid creating a duplicate `Path`/`PATH` on Windows.\n if (toolbeltEnabled()) {\n Object.assign(vars, toolbeltPathOverride(process.env, PATHS.TOOLBELT_BIN_DIR))\n }\n\n return vars\n}\n\n/**\n * Build environment variables for Codex CLI.\n *\n * Like `getClaudeCodeEnvVars`, the parent env is sanitized of\n * `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `CODEX_HOME` (see\n * `STRIPPED_PARENT_ENV_KEYS` in `src/lib/launch.ts`) before these\n * overrides are merged, so a stale shell `OPENAI_API_KEY` can't leak\n * through. Codex caches a ChatGPT subscription login under\n * `$CODEX_HOME/auth.json` which can override `OPENAI_API_KEY` per\n * openai/codex#2733; pointing `CODEX_HOME` at an isolated directory\n * masks any cached login.\n */\nexport function getCodexEnvVars(serverUrl: string): Record<string, string> {\n const vars: Record<string, string> = {\n OPENAI_BASE_URL: `${serverUrl}/v1`,\n OPENAI_API_KEY: \"dummy\",\n // Isolated CODEX_HOME — masks any cached ChatGPT login (openai/codex#2733).\n CODEX_HOME: PATHS.CODEX_HOME,\n }\n if (toolbeltEnabled()) {\n Object.assign(vars, toolbeltPathOverride(process.env, PATHS.TOOLBELT_BIN_DIR))\n }\n return vars\n}\n"],"mappings":"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"}