copilot-relay 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","names":["consolaLevelByName: Record<LogLevelName, number>","fileLevelByMethod: Record<string, number>","copilotVersion","editorPluginVersion","userAgent","copilotTokenRefreshTimer: ReturnType<typeof setTimeout> | undefined","sleep","resolve","payload: StoredCopilotToken","refreshIn","refreshIn: number","runtimeState: RuntimeState","defaultReasoningEffort: ReasoningEffort","defaultModelRouting: ModelRoutingConfig","defaultConfig: AppConfig","config: Record<string, unknown>","logRetentionDays","config: AppConfig","resolve","payload: RelayPidFile","relayPids: Array<number>","configPath","parsed: Record<string, unknown>","env: Record<string, unknown>","next: Record<string, unknown>","lastError: unknown","path","undiciFetch","state: ResponseTranslationState","chunks: Array<ResponseStreamEventMessage>","translated: Array<ResponsesInputItem>","continuePrefillPrompt","normalizeFinalAssistantPrefill","newMessages: Array<Message>","contentParts: Array<ContentPart>","allThinkingBlocks: Array<ClaudeThinkingBlock>","allTextBlocks: Array<ClaudeTextBlock>","allToolUseBlocks: Array<ClaudeToolUseBlock>","stopReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null","events: Array<ClaudeStreamEventData>","events","results: Array<WebSearchResult>","content: Array<ClaudeAssistantContentBlock>","events: Array<ClaudeStreamEventData>","events","claudeResponse: ClaudeResponse","streamState: ClaudeStreamState","chunk: ChatCompletionChunk","path","claudeConfigPath","defaultClaudeConfigPath","resolve"],"sources":["../src/lib/error.ts","../src/lib/paths.ts","../src/lib/log.ts","../src/lib/auth.ts","../src/lib/state.ts","../src/lib/models.ts","../src/lib/app-config.ts","../src/lib/config.ts","../src/auth.ts","../src/lib/lifecycle.ts","../src/lib/claude-settings.ts","../src/lib/defaults.ts","../src/copilot/client.ts","../src/copilot/responses.ts","../src/copilot/chat.ts","../src/lib/preflight.ts","../src/lib/version.ts","../src/claude/utils.ts","../src/claude/tool-names.ts","../src/claude/translate.ts","../src/claude/stream.ts","../src/claude/web-search.ts","../src/lib/tokenizer.ts","../src/routes/claude.ts","../src/server.ts","../src/start.ts","../src/restart.ts","../src/stop.ts","../src/main.ts"],"sourcesContent":["// Error wrappers used to preserve upstream HTTP status and response bodies.\nexport class ProxyNotImplementedError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"ProxyNotImplementedError\"\n }\n}\n\nexport class HTTPError extends Error {\n detail?: string\n response: Response\n\n constructor(message: string, response: Response, detail?: string) {\n super(message)\n this.name = \"HTTPError\"\n this.detail = detail\n this.response = response\n }\n}\n","// File-system layout for config, token cache, logs, and legacy migration paths.\nimport fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nconst homeDir = os.homedir()\n\nconst appDir = path.join(homeDir, \".copilot-relay\")\n\nconst legacyGithubTokenPaths = [\n path.join(homeDir, \".copilot-tennel\", \"github_token\"),\n path.join(homeDir, \"Library\", \"Application Support\", \"copilot-tennel\", \"github_token\"),\n path.join(homeDir, \".local\", \"share\", \"copilot-tennel\", \"github_token\"),\n path.join(homeDir, \"Library\", \"Application Support\", \"copilot-relay\", \"github_token\"),\n path.join(homeDir, \".local\", \"share\", \"copilot-relay\", \"github_token\"),\n path.join(homeDir, \".local\", \"share\", \"copilot-bridge\", \"github_token\"),\n]\n\nconst legacyCopilotTokenPaths = [\n path.join(homeDir, \".copilot-tennel\", \"copilot_token.json\"),\n path.join(homeDir, \"Library\", \"Application Support\", \"copilot-tennel\", \"copilot_token.json\"),\n path.join(homeDir, \".local\", \"share\", \"copilot-tennel\", \"copilot_token.json\"),\n path.join(homeDir, \"Library\", \"Application Support\", \"copilot-relay\", \"copilot_token.json\"),\n path.join(homeDir, \".local\", \"share\", \"copilot-relay\", \"copilot_token.json\"),\n]\n\nconst configPath = path.join(appDir, \"config.yaml\")\nconst copilotTokenPath = path.join(appDir, \"copilot_token.json\")\nconst githubTokenPath = path.join(appDir, \"github_token\")\nconst logsDir = path.join(appDir, \"logs\")\nconst logPath = path.join(logsDir, \"copilot-relay.log\")\nconst pidPath = path.join(appDir, \"copilot-relay.pid\")\n\nexport const paths = {\n appDir,\n configPath,\n copilotTokenPath,\n githubTokenPath,\n legacyConfigPaths: [\n path.join(homeDir, \".copilot-relay.yaml\"),\n path.join(homeDir, \".copilot-tennel\", \"config.yaml\"),\n path.join(homeDir, \".copilot-tennel.yaml\"),\n ],\n legacyCopilotTokenPaths,\n logPath,\n logsDir,\n pidPath,\n}\n\nexport async function ensurePaths(): Promise<void> {\n await fs.mkdir(paths.appDir, { recursive: true })\n // GitHub tokens are plain text and safe to migrate here. Copilot token\n // migration is handled in auth.ts because that cache has a JSON schema.\n await ensureFile(paths.githubTokenPath, {\n legacyPaths: legacyGithubTokenPaths,\n })\n}\n\nasync function ensureFile(\n filePath: string,\n options: { legacyPaths?: Array<string> } = {},\n): Promise<void> {\n try {\n await fs.access(filePath, fs.constants.W_OK)\n } catch {\n for (const legacyPath of options.legacyPaths ?? []) {\n if (legacyPath === filePath) {\n continue\n }\n\n try {\n const content = await fs.readFile(legacyPath, \"utf8\")\n if (content.trim()) {\n await fs.writeFile(filePath, content, { mode: 0o600 })\n await fs.chmod(filePath, 0o600)\n return\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error\n }\n }\n }\n\n await fs.writeFile(filePath, \"\")\n await fs.chmod(filePath, 0o600)\n }\n}","// Central logger: writes to console and ~/.copilot-relay/logs with retention cleanup.\nimport fs from \"node:fs/promises\"\nimport { inspect } from \"node:util\"\n\nimport consola from \"consola\"\n\nimport type { LogLevelName } from \"~/lib/app-config\"\nimport { paths } from \"~/lib/paths\"\n\nconst logCleanupCheckIntervalMs = 60 * 60 * 1000\nlet logRetentionDays = 3\nlet nextLogCleanupCheckAt = 0\n\nconst consolaLevelByName: Record<LogLevelName, number> = {\n error: 0,\n info: 3,\n debug: 4,\n}\n\n// Keep runtime logging intentionally small: error carries full failure context,\n// info is operational status, and debug is detailed tracing for local diagnosis.\nconst fileLevelByMethod: Record<string, number> = {\n error: consolaLevelByName.error,\n info: consolaLevelByName.info,\n debug: consolaLevelByName.debug,\n}\n\nlet currentLogLevel = consolaLevelByName.info\n\nexport const setLogLevel = (level: LogLevelName): void => {\n currentLogLevel = consolaLevelByName[level]\n consola.level = consolaLevelByName[level]\n}\n\nconst formatLogValue = (value: unknown): string =>\n typeof value === \"string\" ? value : inspect(value, { depth: null })\n\nconst writeLogFile = async (\n level: string,\n values: Array<unknown>,\n): Promise<void> => {\n await fs.mkdir(paths.logsDir, { recursive: true })\n await cleanupLogsIfDue()\n const line = [\n new Date().toISOString(),\n level,\n values.map(formatLogValue).join(\" \"),\n ].join(\" \")\n await fs.appendFile(paths.logPath, `${line}\\n`)\n}\n\nconst cleanupLogsIfDue = async (): Promise<void> => {\n const now = Date.now()\n if (now < nextLogCleanupCheckAt) {\n return\n }\n\n nextLogCleanupCheckAt = now + logCleanupCheckIntervalMs\n await cleanupLogs(logRetentionDays)\n}\n\nconst wrapFileLog = <T extends (...args: Array<unknown>) => unknown>(\n level: string,\n fn: T,\n): T =>\n ((...args: Array<unknown>) => {\n if ((fileLevelByMethod[level] ?? consolaLevelByName.info) <= currentLogLevel) {\n // File logging must never block the console path or fail a request. If\n // the disk write fails, the original consola call still runs.\n void writeLogFile(level, args).catch(() => undefined)\n }\n return fn(...args)\n }) as T\n\nconsola.error = wrapFileLog(\"error\", consola.error.bind(consola))\nconsola.info = wrapFileLog(\"info\", consola.info.bind(consola))\nconsola.debug = wrapFileLog(\"debug\", consola.debug.bind(consola))\n\nexport const cleanupLogs = async (retentionDays: number): Promise<void> => {\n logRetentionDays = retentionDays\n await fs.mkdir(paths.logsDir, { recursive: true })\n // Retention uses file mtime rather than per-line timestamps; the active log\n // naturally remains fresh while the long-running proxy keeps appending to it.\n const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1000\n const entries = await fs.readdir(paths.logsDir, { withFileTypes: true })\n await Promise.all(\n entries\n .filter((entry) => entry.isFile() && entry.name.endsWith(\".log\"))\n .map(async (entry) => {\n const filePath = `${paths.logsDir}/${entry.name}`\n const stat = await fs.stat(filePath)\n if (stat.mtimeMs < cutoff) {\n await fs.unlink(filePath)\n }\n }),\n )\n}\n\nexport const log = consola\n","// GitHub device auth plus file-backed Copilot token cache and refresh scheduling.\nimport fs from \"node:fs/promises\"\n\nimport type { ProxyConfig } from \"~/lib/config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { log } from \"~/lib/log\"\nimport { paths, ensurePaths } from \"~/lib/paths\"\n\nconst copilotVersion = \"0.26.7\"\nconst editorPluginVersion = `copilot-chat/${copilotVersion}`\nconst userAgent = `GitHubCopilotChat/${copilotVersion}`\nconst githubApiVersion = \"2022-11-28\"\n\nconst githubApiBaseUrl = \"https://api.github.com\"\nconst githubBaseUrl = \"https://github.com\"\nconst githubClientId = \"Iv1.b507a08c87ecfe98\"\nconst githubAppScopes = [\"read:user\"].join(\" \")\n\ninterface DeviceCodeResponse {\n device_code: string\n expires_in: number\n interval: number\n user_code: string\n verification_uri: string\n}\n\ninterface AccessTokenResponse {\n access_token?: string\n}\n\ninterface CopilotTokenResponse {\n refresh_in: number\n token: string\n}\n\ninterface StoredCopilotToken {\n refreshedAt: number\n refreshIn: number\n token: string\n}\n\ninterface GitHubUserResponse {\n login: string\n}\n\ninterface AuthOptions {\n force?: boolean\n}\n\nexport interface ProxyAuthSession {\n githubLogin?: string\n source: \"github-token\"\n}\n\nlet copilotTokenRefreshTimer: ReturnType<typeof setTimeout> | undefined\n\nconst standardHeaders = () => ({\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n})\n\nconst sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nconst readGitHubToken = async () => {\n await ensurePaths()\n const token = await fs.readFile(paths.githubTokenPath, \"utf8\")\n return token.trim()\n}\n\nconst writeGitHubToken = async (token: string) => {\n await ensurePaths()\n await fs.writeFile(paths.githubTokenPath, `${token.trim()}\\n`, {\n mode: 0o600,\n })\n}\n\nconst readStoredCopilotToken = async (): Promise<StoredCopilotToken | undefined> => {\n await ensurePaths()\n try {\n const payload = JSON.parse(\n await fs.readFile(paths.copilotTokenPath, \"utf8\"),\n ) as Partial<StoredCopilotToken>\n if (\n typeof payload.token === \"string\"\n && typeof payload.refreshedAt === \"number\"\n && typeof payload.refreshIn === \"number\"\n ) {\n return payload as StoredCopilotToken\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error\n }\n }\n\n // Migrate only caches that still match the current JSON shape; older files\n // are ignored so a corrupt token cache does not poison new installs.\n for (const legacyPath of paths.legacyCopilotTokenPaths) {\n try {\n const content = await fs.readFile(legacyPath, \"utf8\")\n const payload = JSON.parse(content) as Partial<StoredCopilotToken>\n if (\n typeof payload.token === \"string\"\n && typeof payload.refreshedAt === \"number\"\n && typeof payload.refreshIn === \"number\"\n ) {\n await fs.writeFile(paths.copilotTokenPath, content, { mode: 0o600 })\n await fs.chmod(paths.copilotTokenPath, 0o600)\n return payload as StoredCopilotToken\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error\n }\n }\n }\n\n return undefined\n}\n\nconst writeStoredCopilotToken = async (\n input: CopilotTokenResponse,\n): Promise<void> => {\n await ensurePaths()\n const payload: StoredCopilotToken = {\n refreshedAt: Date.now(),\n refreshIn: input.refresh_in,\n token: input.token,\n }\n await fs.writeFile(\n paths.copilotTokenPath,\n `${JSON.stringify(payload, null, 2)}\\n`,\n { mode: 0o600 },\n )\n}\n\nconst getStoredTokenRemainingSeconds = (token: StoredCopilotToken): number => {\n const ageSeconds = Math.floor((Date.now() - token.refreshedAt) / 1000)\n return token.refreshIn - ageSeconds\n}\n\nconst githubHeaders = (githubToken: string, vsCodeVersion: string) => ({\n ...standardHeaders(),\n authorization: `token ${githubToken}`,\n \"editor-plugin-version\": editorPluginVersion,\n \"editor-version\": `vscode/${vsCodeVersion}`,\n \"user-agent\": userAgent,\n \"x-github-api-version\": githubApiVersion,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n})\n\nconst getDeviceCode = async (): Promise<DeviceCodeResponse> => {\n const response = await fetch(`${githubBaseUrl}/login/device/code`, {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: githubClientId,\n scope: githubAppScopes,\n }),\n })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get device code\", response)\n }\n\n return (await response.json()) as DeviceCodeResponse\n}\n\nconst pollAccessToken = async (\n deviceCode: DeviceCodeResponse,\n): Promise<string> => {\n // GitHub asks clients to poll at `interval`; add a one-second cushion so\n // long waits do not accidentally trigger OAuth `slow_down` responses.\n const sleepDuration = (deviceCode.interval + 1) * 1000\n\n // Device auth is intentionally user-driven: keep polling until the user\n // finishes authorization in the browser instead of treating pending states\n // as fatal startup errors.\n while (true) {\n const response = await fetch(`${githubBaseUrl}/login/oauth/access_token`, {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: githubClientId,\n device_code: deviceCode.device_code,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }),\n })\n\n if (!response.ok) {\n await sleep(sleepDuration)\n continue\n }\n\n const json = (await response.json()) as AccessTokenResponse\n if (json.access_token) {\n return json.access_token\n }\n\n await sleep(sleepDuration)\n }\n}\n\nconst getGitHubUser = async (\n githubToken: string,\n vsCodeVersion: string,\n): Promise<GitHubUserResponse> => {\n const response = await fetch(`${githubApiBaseUrl}/user`, {\n headers: githubHeaders(githubToken, vsCodeVersion),\n })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get GitHub user\", response)\n }\n\n return (await response.json()) as GitHubUserResponse\n}\n\nconst getCopilotToken = async (\n githubToken: string,\n vsCodeVersion: string,\n): Promise<CopilotTokenResponse> => {\n const response = await fetch(\n `${githubApiBaseUrl}/copilot_internal/v2/token`,\n {\n headers: githubHeaders(githubToken, vsCodeVersion),\n },\n )\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get Copilot token\", response)\n }\n\n return (await response.json()) as CopilotTokenResponse\n}\n\nconst isCopilotTokenError = (error: unknown): boolean =>\n error instanceof HTTPError && error.message === \"Failed to get Copilot token\"\n\nconst ensureGitHubToken = async (options: AuthOptions = {}) => {\n const existingToken = options.force ? \"\" : await readGitHubToken()\n if (existingToken) {\n log.info(`Using cached GitHub token at ${paths.githubTokenPath}`)\n return existingToken\n }\n\n const deviceCode = await getDeviceCode()\n log.info(\n `Open ${deviceCode.verification_uri} and enter code ${deviceCode.user_code}`,\n )\n\n const githubToken = await pollAccessToken(deviceCode)\n await writeGitHubToken(githubToken)\n log.info(`GitHub token synced to ${paths.githubTokenPath}`)\n\n return githubToken\n}\n\nconst loadGitHubLogin = async (\n githubToken: string,\n vsCodeVersion: string,\n): Promise<string | undefined> => {\n try {\n const user = await getGitHubUser(githubToken, vsCodeVersion)\n return user.login\n } catch (error) {\n log.error(\"Could not load GitHub user:\", error)\n return undefined\n }\n}\n\nexport const setupProxyAuth = async (\n config: ProxyConfig,\n options: AuthOptions = {},\n): Promise<ProxyAuthSession> => {\n let githubToken = await ensureGitHubToken(options)\n const applyCopilotToken = async () => {\n const tokenResponse = await getCopilotToken(\n githubToken,\n config.vsCodeVersion,\n )\n\n config.copilotToken = tokenResponse.token\n await writeStoredCopilotToken(tokenResponse)\n return tokenResponse.refresh_in\n }\n\n const scheduleCopilotTokenRefresh = (refreshIn: number) => {\n if (copilotTokenRefreshTimer) {\n clearTimeout(copilotTokenRefreshTimer)\n }\n\n // Refresh one minute before GitHub's `refresh_in` deadline, but keep a\n // one-minute floor so failure retries do not spin in a tight loop.\n const refreshMs = Math.max(refreshIn - 60, 60) * 1000\n log.info(\n `Next Copilot token refresh in ${Math.round(refreshMs / 1000)}s`,\n )\n\n copilotTokenRefreshTimer = setTimeout(async () => {\n try {\n const nextRefreshIn = await applyCopilotToken()\n log.info(\"Refreshed Copilot token\")\n scheduleCopilotTokenRefresh(nextRefreshIn)\n } catch (error) {\n log.error(\"Failed to refresh Copilot token:\", error)\n // Keep the last token active and retry soon; in-flight requests can\n // continue until the bearer token actually expires.\n scheduleCopilotTokenRefresh(60)\n }\n }, refreshMs)\n\n if (typeof copilotTokenRefreshTimer.unref === \"function\") {\n copilotTokenRefreshTimer.unref()\n }\n }\n\n const storedToken = await readStoredCopilotToken()\n let refreshIn: number\n if (storedToken && getStoredTokenRemainingSeconds(storedToken) > 60) {\n // Avoid using tokens that are close to expiry; Claude Code requests can\n // be long-running, so keep at least one minute of freshness for new calls.\n config.copilotToken = storedToken.token\n refreshIn = getStoredTokenRemainingSeconds(storedToken)\n log.info(`Using cached Copilot token at ${paths.copilotTokenPath}`)\n } else {\n try {\n refreshIn = await applyCopilotToken()\n } catch (error) {\n if (options.force || !isCopilotTokenError(error)) {\n throw error\n }\n\n // A cached GitHub token can still become unable to mint Copilot tokens\n // after revocation or account changes; only this specific failure gets\n // a fresh device-auth attempt.\n log.error(\n \"Cached GitHub auth could not get a Copilot token; running device auth again.\",\n )\n githubToken = await ensureGitHubToken({\n ...options,\n force: true,\n })\n refreshIn = await applyCopilotToken()\n }\n }\n scheduleCopilotTokenRefresh(refreshIn)\n\n return {\n githubLogin: await loadGitHubLogin(githubToken, config.vsCodeVersion),\n source: \"github-token\",\n }\n}\n\nexport const runProxyAuth = async (\n config: ProxyConfig,\n options: AuthOptions = {},\n) => {\n const githubToken = await ensureGitHubToken({\n ...options,\n force: true,\n })\n\n const user = await getGitHubUser(githubToken, config.vsCodeVersion)\n log.info(`GitHub token written to ${paths.githubTokenPath}`)\n log.info(`Logged in as ${user.login}`)\n}","// Process-local mutable state for values that can change after config hot reload.\nimport type { ReasoningEffort } from \"~/lib/models\"\nimport type { ModelRoutingConfig } from \"~/lib/models\"\n\nexport interface RuntimeState {\n debug?: boolean\n modelRouting?: ModelRoutingConfig\n thinkEffort?: ReasoningEffort\n}\n\nexport const runtimeState: RuntimeState = {}\n","// Config-driven model routing and think-effort validation.\nimport { runtimeState } from \"~/lib/state\"\n\nexport type ReasoningEffort =\n | \"none\"\n | \"low\"\n | \"medium\"\n | \"high\"\n | \"xhigh\"\n\nexport interface ModelRoutingConfig {\n gptModel: string\n opusModel: string\n}\n\nexport const defaultReasoningEffort: ReasoningEffort = \"xhigh\"\n\nexport const defaultModelRouting: ModelRoutingConfig = {\n gptModel: \"gpt-5.5\",\n opusModel: \"claude-opus-4.8\",\n}\n\nexport const isReasoningEffort = (value: unknown): value is ReasoningEffort =>\n value === \"none\"\n || value === \"low\"\n || value === \"medium\"\n || value === \"high\"\n || value === \"xhigh\"\n\nexport const getModelRouting = (): ModelRoutingConfig =>\n runtimeState.modelRouting ?? defaultModelRouting\n\nexport const getExposedModelIds = (): Array<string> => {\n const routing = getModelRouting()\n return [routing.gptModel, routing.opusModel]\n}\n\nexport const routeModelId = (model: string): string => {\n const routing = getModelRouting()\n // Keep routing intentionally predictable for Claude Code: any alias that\n // mentions Opus gets the configured Opus upstream, all other model names use\n // the configured GPT upstream.\n return model.trim().toLowerCase().includes(\"opus\") ?\n routing.opusModel\n : routing.gptModel\n}\n","// Runtime YAML config loader/writer with hot-reload support for ~/.copilot-relay/config.yaml.\nimport fs from \"node:fs/promises\"\nimport { dirname, resolve } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nimport {\n defaultReasoningEffort,\n isReasoningEffort,\n type ReasoningEffort,\n} from \"~/lib/models\"\nimport { paths } from \"~/lib/paths\"\n\nexport const logLevels = [\"error\", \"info\", \"debug\"] as const\nexport type LogLevelName = (typeof logLevels)[number]\nexport interface AppConfig {\n claudeSetup: boolean\n copilotBaseUrl: string\n gptModel: string\n host: string\n logLevel: LogLevelName\n logRetentionDays: number\n opusModel: string\n port: number\n thinkEffort: ReasoningEffort\n upstreamTimeoutSeconds: number\n webSearchBackend?: string\n}\n\nconst defaultConfig: AppConfig = {\n claudeSetup: true,\n copilotBaseUrl: \"https://api.githubcopilot.com\",\n gptModel: \"gpt-5.5\",\n host: \"127.0.0.1\",\n logLevel: \"info\",\n logRetentionDays: 3,\n opusModel: \"claude-opus-4.8\",\n port: 4142,\n thinkEffort: defaultReasoningEffort,\n upstreamTimeoutSeconds: 180,\n webSearchBackend: undefined,\n}\n\nexport const isLogLevelName = (value: unknown): value is LogLevelName =>\n typeof value === \"string\"\n && logLevels.includes(value.toLowerCase() as LogLevelName)\n\nexport const normalizeLogLevel = (value: unknown): LogLevelName | undefined => {\n if (value === undefined) {\n return undefined\n }\n\n if (typeof value !== \"string\") {\n throw new Error(\n `Invalid logLevel: expected one of ${logLevels.join(\", \")}`,\n )\n }\n\n const normalized = value.toLowerCase()\n if (!isLogLevelName(normalized)) {\n throw new Error(\n `Invalid logLevel \"${value}\": expected one of ${logLevels.join(\", \")}`,\n )\n }\n\n return normalized\n}\n\nconst normalizeBoolean = (value: unknown): boolean | undefined => {\n if (typeof value === \"boolean\") {\n return value\n }\n if (typeof value !== \"string\") {\n return undefined\n }\n const normalized = value.toLowerCase()\n if (normalized === \"true\") return true\n if (normalized === \"false\") return false\n return undefined\n}\n\nconst normalizePort = (value: unknown): number | undefined => {\n const port =\n typeof value === \"number\" ? value\n : typeof value === \"string\" ? Number.parseInt(value, 10)\n : Number.NaN\n return Number.isInteger(port) && port > 0 && port <= 65_535 ? port : undefined\n}\n\nconst normalizePositiveInteger = (value: unknown): number | undefined => {\n const number =\n typeof value === \"number\" ? value\n : typeof value === \"string\" ? Number.parseInt(value, 10)\n : Number.NaN\n return Number.isInteger(number) && number > 0 ? number : undefined\n}\n\nconst normalizeString = (value: unknown): string | undefined =>\n typeof value === \"string\" && value.trim() ? value.trim() : undefined\n\nexport const normalizeThinkEffort = (\n value: unknown,\n): ReasoningEffort | undefined => {\n if (typeof value !== \"string\") {\n return undefined\n }\n const normalized = value.toLowerCase() === \"minimal\" ? \"low\" : value.toLowerCase()\n return isReasoningEffort(normalized) ? normalized : undefined\n}\n\nexport const normalizeUpstreamTimeoutSeconds = (\n value: unknown,\n): number | undefined => {\n if (value === undefined) {\n return undefined\n }\n\n const timeout = normalizePositiveInteger(value)\n if (timeout === undefined) {\n throw new Error(\"Invalid upstreamTimeoutSeconds: expected a positive integer\")\n }\n\n return timeout\n}\n\nconst readRawConfig = async (): Promise<Record<string, unknown>> => {\n try {\n const content = await fs.readFile(paths.configPath, \"utf8\")\n return parseConfigYaml(content)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n for (const legacyPath of paths.legacyConfigPaths) {\n try {\n const content = await fs.readFile(legacyPath, \"utf8\")\n return parseConfigYaml(content)\n } catch (legacyError) {\n if ((legacyError as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw legacyError\n }\n }\n }\n return readDefaultConfigTemplate()\n }\n throw error\n }\n}\n\nconst readDefaultConfigTemplate = async (): Promise<Record<string, unknown>> => {\n let currentDir = dirname(fileURLToPath(import.meta.url))\n\n // Bundled code may run from src/ during development or from dist/ after\n // packaging, so walk upward until the package-level config template is found.\n while (true) {\n try {\n const content = await fs.readFile(\n resolve(currentDir, \"config.default.yaml\"),\n \"utf8\",\n )\n return parseConfigYaml(content)\n } catch {\n const parentDir = dirname(currentDir)\n if (parentDir === currentDir) {\n return {}\n }\n currentDir = parentDir\n }\n }\n}\n\nconst unquoteYamlScalar = (value: string): string => {\n const trimmed = value.trim()\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"'))\n || (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n ) {\n return trimmed.slice(1, -1)\n }\n return trimmed\n}\n\nconst parseConfigYaml = (content: string): Record<string, unknown> => {\n const config: Record<string, unknown> = {}\n for (const line of content.split(/\\r?\\n/)) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith(\"#\")) {\n continue\n }\n\n const match = trimmed.match(/^([A-Za-z][A-Za-z0-9_-]*)\\s*:\\s*(.*?)\\s*$/)\n if (!match) {\n throw new Error(`Invalid config line in ${paths.configPath}: ${line}`)\n }\n\n const [, key, value] = match\n // The runtime config intentionally supports only a flat key/value YAML\n // subset. That keeps startup dependency-free and makes bad edits fail\n // predictably instead of being partially interpreted.\n switch (key) {\n case \"claudeSetup\":\n case \"claude_setup\": {\n config.claudeSetup = unquoteYamlScalar(value)\n break\n }\n case \"copilotBaseUrl\":\n case \"copilot_base_url\": {\n config.copilotBaseUrl = unquoteYamlScalar(value)\n break\n }\n case \"host\": {\n config.host = unquoteYamlScalar(value)\n break\n }\n case \"gptModel\":\n case \"gpt_model\": {\n config.gptModel = unquoteYamlScalar(value)\n break\n }\n case \"logLevel\":\n case \"log_level\": {\n config.logLevel = unquoteYamlScalar(value)\n break\n }\n case \"logRetentionDays\":\n case \"log_retention_days\": {\n config.logRetentionDays = unquoteYamlScalar(value)\n break\n }\n case \"opusModel\":\n case \"opus_model\": {\n config.opusModel = unquoteYamlScalar(value)\n break\n }\n case \"port\": {\n config.port = unquoteYamlScalar(value)\n break\n }\n case \"thinkEffort\":\n case \"think_effort\": {\n config.thinkEffort = unquoteYamlScalar(value)\n break\n }\n case \"upstreamTimeoutSeconds\":\n case \"upstream_timeout_seconds\": {\n config.upstreamTimeoutSeconds = unquoteYamlScalar(value)\n break\n }\n case \"webSearchBackend\":\n case \"web_search_backend\": {\n config.webSearchBackend = unquoteYamlScalar(value)\n break\n }\n default: {\n break\n }\n }\n }\n return config\n}\n\nconst writeConfig = async (config: AppConfig): Promise<void> => {\n await fs.mkdir(paths.appDir, { recursive: true })\n const content = serializeConfig(config)\n const existing = await fs.readFile(paths.configPath, \"utf8\").catch(() => \"\")\n if (existing === content) {\n return\n }\n await fs.writeFile(paths.configPath, content, { mode: 0o600 })\n}\n\nconst serializeConfig = (config: AppConfig): string =>\n [\n \"# copilot-relay configuration\",\n \"#\",\n \"# This file is hot-reloaded while copilot-relay is running.\",\n \"\",\n \"# Local host for the Claude Code-compatible HTTP server.\",\n `host: ${config.host}`,\n \"\",\n \"# Local port for the HTTP server.\",\n `port: ${config.port}`,\n \"\",\n \"# GitHub Copilot API base URL.\",\n `copilotBaseUrl: ${config.copilotBaseUrl}`,\n \"\",\n \"# Update ~/.claude/settings.json on start.\",\n `claudeSetup: ${config.claudeSetup}`,\n \"\",\n \"# Log verbosity:\",\n \"# error - startup/preflight/request failures only\",\n \"# info - error logs plus startup status, preflight status, and local HTTP\",\n \"# status codes\",\n \"# debug - info logs plus model routing summaries, Copilot upstream timings,\",\n \"# and request payloads\",\n `logLevel: ${config.logLevel}`,\n \"\",\n \"# Number of days to keep files in ~/.copilot-relay/logs.\",\n `logRetentionDays: ${config.logRetentionDays}`,\n \"\",\n \"# Default upstream thinking/reasoning effort: none, low, medium, high, xhigh.\",\n `thinkEffort: ${config.thinkEffort}`,\n \"\",\n \"# Max seconds to wait for a single Claude request's upstream Copilot calls.\",\n `upstreamTimeoutSeconds: ${config.upstreamTimeoutSeconds}`,\n \"\",\n \"# Copilot model used for bridge-managed Claude WebSearch. Empty uses gptModel.\",\n `webSearchBackend: ${config.webSearchBackend ?? \"\"}`,\n \"\",\n \"# Model routing: requests containing \\\"opus\\\" use opusModel; all others use gptModel.\",\n \"\",\n \"# Upstream Copilot model used for non-Opus requests.\",\n `gptModel: ${config.gptModel}`,\n \"\",\n \"# Upstream Copilot model used for requests containing \\\"opus\\\".\",\n `opusModel: ${config.opusModel}`,\n \"\",\n ].join(\"\\n\")\n\nexport async function readAppConfig(): Promise<AppConfig> {\n const raw = await readRawConfig()\n const claudeSetup = normalizeBoolean(raw.claudeSetup)\n const host = normalizeString(raw.host)\n const logLevel = normalizeLogLevel(raw.logLevel)\n const logRetentionDays = normalizePositiveInteger(raw.logRetentionDays)\n const port = normalizePort(raw.port)\n const thinkEffort = normalizeThinkEffort(raw.thinkEffort)\n const upstreamTimeoutSeconds = normalizeUpstreamTimeoutSeconds(\n raw.upstreamTimeoutSeconds,\n )\n\n const config: AppConfig = {\n claudeSetup: claudeSetup ?? defaultConfig.claudeSetup,\n copilotBaseUrl: normalizeString(raw.copilotBaseUrl) ?? defaultConfig.copilotBaseUrl,\n gptModel: normalizeString(raw.gptModel) ?? defaultConfig.gptModel,\n host: host ?? defaultConfig.host,\n logLevel: logLevel ?? defaultConfig.logLevel,\n logRetentionDays: logRetentionDays ?? defaultConfig.logRetentionDays,\n opusModel: normalizeString(raw.opusModel) ?? defaultConfig.opusModel,\n port: port ?? defaultConfig.port,\n thinkEffort: thinkEffort ?? defaultConfig.thinkEffort,\n upstreamTimeoutSeconds:\n upstreamTimeoutSeconds ?? defaultConfig.upstreamTimeoutSeconds,\n webSearchBackend: normalizeString(raw.webSearchBackend),\n }\n\n await writeConfig(config)\n return config\n}\n\nconst getConfigMtime = async (): Promise<number> => {\n try {\n return (await fs.stat(paths.configPath)).mtimeMs\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return 0\n }\n throw error\n }\n}\n\nexport const watchAppConfig = (\n onReload: (config: AppConfig) => void,\n): ReturnType<typeof setInterval> => {\n let lastMtime = 0\n\n const timer = setInterval(async () => {\n try {\n const nextMtime = await getConfigMtime()\n if (nextMtime === lastMtime) {\n return\n }\n\n lastMtime = nextMtime\n onReload(await readAppConfig())\n } catch {\n // Config editors can briefly write invalid partial files. Keep the last\n // good runtime config rather than degrading live requests mid-edit.\n }\n }, 1000)\n\n if (typeof timer.unref === \"function\") {\n timer.unref()\n }\n\n void getConfigMtime().then((mtime) => {\n lastMtime = mtime\n })\n\n return timer\n}\n","// Converts hot-loaded app config into the mutable runtime config shared with routes.\nimport type { AppConfig } from \"~/lib/app-config\"\n\nconst vscodeVersion = \"1.99.3\"\n\nexport interface ProxyConfig {\n host: string\n port: number\n copilotBaseUrl: string\n copilotToken: string | undefined\n upstreamTimeoutMs: number\n vsCodeVersion: string\n webSearchBackend?: string\n}\n\nexport interface ProxyEnv {\n Variables: {\n config: ProxyConfig\n requestErrorMessage?: string\n requestId: string\n }\n}\n\nexport const readProxyConfig = (config: AppConfig): ProxyConfig => ({\n copilotBaseUrl: config.copilotBaseUrl,\n copilotToken: undefined,\n host: config.host,\n port: config.port,\n upstreamTimeoutMs: config.upstreamTimeoutSeconds * 1000,\n vsCodeVersion: vscodeVersion,\n webSearchBackend: config.webSearchBackend,\n})\n","// `copilot-relay auth`: performs an explicit device-login flow and syncs tokens.\nimport { defineCommand } from \"citty\"\n\nimport { setupProxyAuth } from \"~/lib/auth\"\nimport { readAppConfig } from \"~/lib/app-config\"\nimport { readProxyConfig } from \"~/lib/config\"\nimport { log } from \"~/lib/log\"\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run GitHub device auth and cache credentials for copilot-relay.\",\n },\n async run() {\n const config = readProxyConfig(await readAppConfig())\n\n config.copilotToken = undefined\n\n const authSession = await setupProxyAuth(config, {\n force: true,\n })\n\n if (authSession.githubLogin) {\n log.info(`Logged in as ${authSession.githubLogin}`)\n }\n\n log.info(\"copilot-relay auth completed\")\n },\n})\n","// Process lifecycle helpers for stopping stale local relay instances.\nimport { execFile } from \"node:child_process\"\nimport fs from \"node:fs/promises\"\nimport { promisify } from \"node:util\"\n\nimport type { ProxyConfig } from \"~/lib/config\"\nimport { log } from \"~/lib/log\"\nimport { paths } from \"~/lib/paths\"\n\nconst execFileAsync = promisify(execFile)\nconst stopTimeoutMs = 5_000\nconst stopPollMs = 100\n\ninterface RelayPidFile {\n host: string\n pid: number\n port: number\n startedAt: string\n}\n\nconst isNodeErrno = (error: unknown): error is NodeJS.ErrnoException =>\n typeof error === \"object\" && error !== null && \"code\" in error\n\nconst sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nconst parsePid = (value: unknown): number | undefined => {\n const pid =\n typeof value === \"number\" ? value\n : typeof value === \"string\" ? Number.parseInt(value.trim(), 10)\n : Number.NaN\n\n return Number.isInteger(pid) && pid > 0 ? pid : undefined\n}\n\nconst readCommandOutput = async (\n file: string,\n args: Array<string>,\n): Promise<string> => {\n try {\n const { stdout } = await execFileAsync(file, args, {\n maxBuffer: 1024 * 1024,\n windowsHide: true,\n })\n return String(stdout)\n } catch (error) {\n if (\n typeof error === \"object\"\n && error !== null\n && \"stdout\" in error\n && (typeof error.stdout === \"string\" || Buffer.isBuffer(error.stdout))\n ) {\n return String(error.stdout)\n }\n return \"\"\n }\n}\n\nconst parsePidLines = (output: string): Array<number> =>\n output\n .split(/\\r?\\n/)\n .map((line) => parsePid(line))\n .filter((pid): pid is number => pid !== undefined)\n\nexport const isRelayStartProcess = (\n command: string,\n cwd?: string,\n): boolean => {\n const normalizedCommand = command.replaceAll(\"\\\\\", \"/\")\n const normalizedCwd = cwd?.replaceAll(\"\\\\\", \"/\")\n const hasStartArg = /(?:^|\\s)start(?:\\s|$)/.test(normalizedCommand)\n\n if (!hasStartArg) {\n return false\n }\n\n if (normalizedCommand.includes(\"copilot-relay\")) {\n return true\n }\n\n const usesNode = /(?:^|\\s|\\/)node(?:\\.exe)?(?:\\s|$)/i.test(normalizedCommand)\n const usesDistMain = /(?:^|\\s|\\/)dist\\/main\\.js(?:\\s|$)/.test(\n normalizedCommand,\n )\n\n return Boolean(\n usesNode\n && usesDistMain\n && normalizedCwd\n && normalizedCwd.split(\"/\").some((part) => part.includes(\"copilot-relay\")),\n )\n}\n\nconst isProcessAlive = (pid: number): boolean => {\n try {\n process.kill(pid, 0)\n return true\n } catch (error) {\n return isNodeErrno(error) && error.code === \"EPERM\"\n }\n}\n\nconst readRelayPidFile = async (): Promise<number | undefined> => {\n try {\n const content = await fs.readFile(paths.pidPath, \"utf8\")\n const trimmed = content.trim()\n if (!trimmed) {\n return undefined\n }\n\n if (trimmed.startsWith(\"{\")) {\n const payload = JSON.parse(trimmed) as Partial<RelayPidFile>\n return parsePid(payload.pid)\n }\n\n return parsePid(trimmed)\n } catch (error) {\n if (isNodeErrno(error) && error.code === \"ENOENT\") {\n return undefined\n }\n throw error\n }\n}\n\nexport const writeRelayPidFile = async (\n config: Pick<ProxyConfig, \"host\" | \"port\">,\n): Promise<void> => {\n await fs.mkdir(paths.appDir, { recursive: true })\n const payload: RelayPidFile = {\n host: config.host,\n pid: process.pid,\n port: config.port,\n startedAt: new Date().toISOString(),\n }\n await fs.writeFile(paths.pidPath, `${JSON.stringify(payload, null, 2)}\\n`, {\n mode: 0o600,\n })\n}\n\nexport const clearRelayPidFile = async (\n pid = process.pid,\n options: { force?: boolean } = {},\n): Promise<void> => {\n const currentPid = await readRelayPidFile()\n if (!options.force && currentPid !== undefined && currentPid !== pid) {\n return\n }\n\n await fs.unlink(paths.pidPath).catch((error: unknown) => {\n if (!isNodeErrno(error) || error.code !== \"ENOENT\") {\n throw error\n }\n })\n}\n\nconst getProcessCommand = async (pid: number): Promise<string | undefined> => {\n if (process.platform === \"win32\") {\n const output = await readCommandOutput(\"powershell.exe\", [\n \"-NoProfile\",\n \"-Command\",\n `Get-CimInstance Win32_Process -Filter \"ProcessId = ${pid}\" | Select-Object -ExpandProperty CommandLine`,\n ])\n return output.trim() || undefined\n }\n\n const output = await readCommandOutput(\"ps\", [\n \"-p\",\n String(pid),\n \"-o\",\n \"command=\",\n ])\n return output.trim() || undefined\n}\n\nconst getProcessCwd = async (pid: number): Promise<string | undefined> => {\n if (process.platform === \"win32\") {\n return undefined\n }\n\n const output = await readCommandOutput(\"lsof\", [\n \"-a\",\n \"-p\",\n String(pid),\n \"-d\",\n \"cwd\",\n \"-Fn\",\n ])\n return output\n .split(/\\r?\\n/)\n .find((line) => line.startsWith(\"n\"))\n ?.slice(1)\n}\n\nconst getPortListenerPids = async (port: number): Promise<Array<number>> => {\n if (process.platform === \"win32\") {\n return parsePidLines(await readCommandOutput(\"powershell.exe\", [\n \"-NoProfile\",\n \"-Command\",\n `Get-NetTCPConnection -LocalPort ${port} -State Listen -ErrorAction SilentlyContinue | Select-Object -ExpandProperty OwningProcess -Unique`,\n ]))\n }\n\n return parsePidLines(await readCommandOutput(\"lsof\", [\n \"-nP\",\n `-iTCP:${port}`,\n \"-sTCP:LISTEN\",\n \"-t\",\n ]))\n}\n\nconst getProcessList = async (): Promise<Array<{ command: string; pid: number }>> => {\n const output =\n process.platform === \"win32\" ?\n await readCommandOutput(\"powershell.exe\", [\n \"-NoProfile\",\n \"-Command\",\n \"Get-CimInstance Win32_Process | ForEach-Object { \\\"$($_.ProcessId)`t$($_.CommandLine)\\\" }\",\n ])\n : await readCommandOutput(\"ps\", [\"-axo\", \"pid=,command=\"])\n\n return output\n .split(/\\r?\\n/)\n .flatMap((line) => {\n const match =\n process.platform === \"win32\" ?\n line.match(/^(\\d+)\\t(.+)$/)\n : line.match(/^\\s*(\\d+)\\s+(.+)$/)\n const pid = parsePid(match?.[1])\n const command = match?.[2]?.trim()\n return pid && command ? [{ command, pid }] : []\n })\n}\n\nconst isRelayPid = async (pid: number): Promise<boolean> => {\n if (pid === process.pid || !isProcessAlive(pid)) {\n return false\n }\n\n const command = await getProcessCommand(pid)\n if (!command) {\n return false\n }\n\n return isRelayStartProcess(command, await getProcessCwd(pid))\n}\n\nconst findRelayProcessIds = async (\n config: Pick<ProxyConfig, \"port\">,\n): Promise<Array<number>> => {\n const candidates = new Set<number>()\n const storedPid = await readRelayPidFile()\n if (storedPid) {\n candidates.add(storedPid)\n }\n\n for (const pid of await getPortListenerPids(config.port)) {\n candidates.add(pid)\n }\n\n for (const { command, pid } of await getProcessList()) {\n if (pid === process.pid) {\n continue\n }\n\n if (command.includes(\"copilot-relay\") || command.includes(\"dist/main.js\")) {\n const cwd = await getProcessCwd(pid)\n if (isRelayStartProcess(command, cwd)) {\n candidates.add(pid)\n }\n }\n }\n\n const relayPids: Array<number> = []\n for (const pid of candidates) {\n if (await isRelayPid(pid)) {\n relayPids.push(pid)\n }\n }\n return [...new Set(relayPids)].sort((left, right) => left - right)\n}\n\nconst waitForExit = async (pid: number, timeoutMs: number): Promise<boolean> => {\n const deadline = Date.now() + timeoutMs\n while (Date.now() < deadline) {\n if (!isProcessAlive(pid)) {\n return true\n }\n await sleep(stopPollMs)\n }\n return !isProcessAlive(pid)\n}\n\nconst stopProcess = async (pid: number): Promise<void> => {\n if (!isProcessAlive(pid)) {\n return\n }\n\n log.info(`Stopping existing copilot-relay process pid=${pid}`)\n process.kill(pid, \"SIGTERM\")\n if (await waitForExit(pid, stopTimeoutMs)) {\n return\n }\n\n log.error(`copilot-relay process pid=${pid} did not stop; forcing termination`)\n process.kill(pid, \"SIGKILL\")\n if (!(await waitForExit(pid, stopTimeoutMs))) {\n throw new Error(`Could not stop copilot-relay process pid=${pid}`)\n }\n}\n\nexport const stopExistingRelay = async (\n config: Pick<ProxyConfig, \"port\">,\n): Promise<Array<number>> => {\n const relayPids = await findRelayProcessIds(config)\n if (relayPids.length === 0) {\n log.info(\"No existing copilot-relay instance found\")\n await clearRelayPidFile(0, { force: true })\n return []\n }\n\n for (const pid of relayPids) {\n await stopProcess(pid)\n }\n await clearRelayPidFile(0, { force: true })\n return relayPids\n}\n","// Optional writer for Claude Code settings so it points at the local proxy.\nimport fs from \"node:fs/promises\"\nimport path from \"node:path\"\n\ninterface ApplyClaudeConfigInput {\n baseUrl: string\n configPath: string\n}\n\ninterface ApplyClaudeResult {\n configPath: string\n changed: boolean\n created: boolean\n previousBaseUrl?: string\n}\n\n/**\n * Update `~/.claude/settings.json` so its env block points Claude Code at the\n * running proxy. Preserves all unrelated keys (model overrides, plugins,\n * marketplaces, etc.). Sets a dummy auth token only if none is present.\n */\nexport async function applyClaudeConfig(\n input: ApplyClaudeConfigInput,\n): Promise<ApplyClaudeResult> {\n const { configPath, baseUrl } = input\n\n let raw = \"\"\n let created = false\n try {\n raw = await fs.readFile(configPath, \"utf8\")\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n created = true\n } else {\n throw error\n }\n }\n\n let parsed: Record<string, unknown> = {}\n if (raw.trim().length > 0) {\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n parsed = {}\n }\n } catch {\n // Refuse to overwrite a malformed file; bail without changes.\n return { configPath, changed: false, created: false }\n }\n }\n\n const env: Record<string, unknown> =\n typeof parsed.env === \"object\"\n && parsed.env !== null\n && !Array.isArray(parsed.env)\n ? { ...(parsed.env as Record<string, unknown>) }\n : {}\n\n const previousBaseUrl =\n typeof env.ANTHROPIC_BASE_URL === \"string\"\n ? (env.ANTHROPIC_BASE_URL as string)\n : undefined\n\n env.ANTHROPIC_BASE_URL = baseUrl\n // Claude Code only requires a syntactically present auth token here; real\n // upstream authentication is handled by copilot-relay's Copilot token.\n if (typeof env.ANTHROPIC_AUTH_TOKEN !== \"string\" || !env.ANTHROPIC_AUTH_TOKEN) {\n env.ANTHROPIC_AUTH_TOKEN = \"dummy\"\n }\n\n const next: Record<string, unknown> = { ...parsed, env }\n const serialized = `${JSON.stringify(next, null, 2)}\\n`\n\n if (serialized === raw) {\n return { configPath, changed: false, created: false, previousBaseUrl }\n }\n\n await fs.mkdir(path.dirname(configPath), { recursive: true })\n await fs.writeFile(configPath, serialized)\n return { configPath, changed: true, created, previousBaseUrl }\n}\n","// Static process defaults that are not intended to be user-tuned.\nimport path from \"node:path\"\nimport os from \"node:os\"\n\n/**\n * Static defaults for copilot-relay. Previously these lived in\n * `~/.config/copilot-relay/settings.json`, but that file became an implicit\n * third source of truth alongside `~/.claude/settings.json`, which caused\n * subtle port-mismatch bugs. copilot-relay now relies on these defaults plus\n * CLI flags only.\n */\n\nexport const defaultHost = \"127.0.0.1\"\nexport const defaultPort = 4142\n\nexport const claudeConfigPath = path.join(\n os.homedir(),\n \".claude\",\n \"settings.json\",\n)\n","// Low-level GitHub Copilot HTTP client: adds required headers, retries transient failures, and logs timing.\nimport { randomUUID } from \"node:crypto\"\n\nimport { Agent, fetch as undiciFetch } from \"undici\"\n\nimport type { ProxyConfig } from \"~/lib/config\"\nimport { HTTPError, ProxyNotImplementedError } from \"~/lib/error\"\nimport { log } from \"~/lib/log\"\n\nconst copilotVersion = \"0.26.7\"\nconst editorPluginVersion = `copilot-chat/${copilotVersion}`\nconst userAgent = `GitHubCopilotChat/${copilotVersion}`\nconst apiVersion = \"2025-04-01\"\nconst maxFetchAttempts = 2\nexport const copilotRequestTimeoutMs = 180_000\nconst copilotDispatcher = new Agent({\n allowH2: false,\n connect: { allowH2: false },\n})\n\nexport interface CopilotProviderContext {\n baseUrl: string\n token: string | undefined\n vsCodeVersion: string\n}\n\nexport const getCopilotProviderContext = (\n config: ProxyConfig,\n): CopilotProviderContext => ({\n baseUrl: config.copilotBaseUrl,\n token: config.copilotToken,\n vsCodeVersion: config.vsCodeVersion,\n})\n\nexport interface FetchCopilotOptions {\n vision?: boolean\n initiator?: \"agent\" | \"user\"\n requestId?: string\n signal?: AbortSignal\n timeoutMs?: number\n}\n\ninterface CopilotRequestInit {\n body?: string\n headers?: RequestInit[\"headers\"]\n method?: string\n}\n\nconst shouldRetryResponse = (response: Response): boolean =>\n // Retry only transient upstream failures; 4xx responses may contain routing\n // signals, such as \"unsupported_api_for_model\", that callers need to inspect.\n response.status >= 500 && response.status <= 599\n\nexport const createCopilotRequestSignal = (\n signal?: AbortSignal,\n timeoutMs = copilotRequestTimeoutMs,\n): AbortSignal | undefined => {\n const signals = [\n signal,\n timeoutMs > 0 ? AbortSignal.timeout(timeoutMs) : undefined,\n ].filter((value): value is AbortSignal => value !== undefined)\n\n if (signals.length === 0) {\n return undefined\n }\n\n return signals.length === 1 ? signals[0] : AbortSignal.any(signals)\n}\n\nconst getAbortName = (value: unknown): string | undefined =>\n typeof value === \"object\"\n && value !== null\n && \"name\" in value\n && typeof value.name === \"string\" ?\n value.name\n : undefined\n\nconst isAbortLikeError = (error: unknown): boolean => {\n const name = getAbortName(error)\n return name === \"AbortError\" || name === \"TimeoutError\"\n}\n\nconst getErrorCode = (value: unknown): string | undefined =>\n typeof value === \"object\"\n && value !== null\n && \"code\" in value\n && typeof value.code === \"string\" ?\n value.code\n : undefined\n\nexport const isRetryableFetchError = (error: unknown): boolean =>\n getErrorCode(error) === \"ERR_HTTP2_INVALID_SESSION\"\n || (\n typeof error === \"object\"\n && error !== null\n && \"cause\" in error\n && getErrorCode(error.cause) === \"ERR_HTTP2_INVALID_SESSION\"\n )\n\nexport const toCopilotAbortHTTPError = (\n error: unknown,\n signal: AbortSignal | undefined,\n timeoutMs = copilotRequestTimeoutMs,\n): HTTPError | undefined => {\n if (!signal?.aborted && !isAbortLikeError(error)) {\n return undefined\n }\n\n const timedOut =\n getAbortName(signal?.reason) === \"TimeoutError\"\n || getAbortName(error) === \"TimeoutError\"\n const message =\n timedOut ?\n `Copilot upstream request timed out after ${Math.round(timeoutMs / 1000)}s.`\n : \"Client request cancelled before Copilot upstream completed.\"\n const code = timedOut ? \"upstream_timeout\" : \"request_cancelled\"\n\n return new HTTPError(\n message,\n new Response(JSON.stringify({ error: { message, code } }), {\n status: timedOut ? 504 : 499,\n headers: { \"content-type\": \"application/json\" },\n }),\n message,\n )\n}\n\nexport const readCopilotJson = async <T>(\n response: Response,\n signal: AbortSignal | undefined,\n timeoutMs = copilotRequestTimeoutMs,\n): Promise<T> => {\n try {\n return (await response.json()) as T\n } catch (error) {\n throw toCopilotAbortHTTPError(error, signal, timeoutMs) ?? error\n }\n}\n\nexport const readCopilotText = async (\n response: Response,\n signal: AbortSignal | undefined,\n timeoutMs = copilotRequestTimeoutMs,\n): Promise<string> => {\n try {\n return await response.text()\n } catch (error) {\n throw toCopilotAbortHTTPError(error, signal, timeoutMs) ?? error\n }\n}\n\nconst buildHeaders = (\n provider: CopilotProviderContext,\n init: CopilotRequestInit,\n options: FetchCopilotOptions,\n upstreamRequestId: string,\n): Record<string, string> => {\n const headers = new Headers(init.headers)\n\n headers.set(\"authorization\", `Bearer ${provider.token}`)\n headers.set(\"copilot-integration-id\", \"vscode-chat\")\n headers.set(\"editor-version\", `vscode/${provider.vsCodeVersion}`)\n headers.set(\"editor-plugin-version\", editorPluginVersion)\n headers.set(\"user-agent\", userAgent)\n headers.set(\"openai-intent\", \"conversation-panel\")\n headers.set(\"x-github-api-version\", apiVersion)\n headers.set(\"x-request-id\", upstreamRequestId)\n headers.set(\"x-vscode-user-agent-library-version\", \"electron-fetch\")\n\n if (options.vision) {\n headers.set(\"copilot-vision-request\", \"true\")\n }\n\n if (options.initiator) {\n headers.set(\"x-initiator\", options.initiator)\n }\n\n if (!headers.has(\"content-type\") && init.body !== undefined) {\n headers.set(\"content-type\", \"application/json\")\n }\n\n if (!headers.has(\"accept\")) {\n headers.set(\"accept\", \"application/json\")\n }\n\n return Object.fromEntries(headers.entries())\n}\n\nconst formatRequestId = (requestId: string | undefined): string =>\n requestId ? `request_id=${requestId} ` : \"\"\n\nconst logUpstreamLifecycle = (\n requestId: string | undefined,\n message: string,\n): void => {\n if (requestId) {\n log.info(`${formatRequestId(requestId)}${message}`)\n return\n }\n\n log.debug(message)\n}\n\nexport const fetchCopilot = async (\n provider: CopilotProviderContext,\n path: string,\n init: CopilotRequestInit,\n options: FetchCopilotOptions = {},\n) => {\n if (!provider.token) {\n throw new ProxyNotImplementedError(\n \"Copilot token is not configured for copilot-relay.\",\n )\n }\n\n const timeoutMs = options.timeoutMs ?? copilotRequestTimeoutMs\n const signal = createCopilotRequestSignal(options.signal, timeoutMs)\n let lastError: unknown\n\n for (let attempt = 1; attempt <= maxFetchAttempts; attempt++) {\n const upstreamRequestId = randomUUID()\n try {\n const started = performance.now()\n logUpstreamLifecycle(\n options.requestId,\n `send upstream method=${init.method ?? \"GET\"} path=${path} attempt=${attempt} upstream_request_id=${upstreamRequestId}`,\n )\n const response = await undiciFetch(`${provider.baseUrl}${path}`, {\n ...init,\n headers: buildHeaders(provider, init, options, upstreamRequestId),\n dispatcher: copilotDispatcher,\n signal,\n })\n const ms = Math.round(performance.now() - started)\n logUpstreamLifecycle(\n options.requestId,\n `return from upstream method=${init.method ?? \"GET\"} path=${path} status=${response.status} ms=${ms} attempt=${attempt} upstream_request_id=${upstreamRequestId}`,\n )\n log.debug(\n `${formatRequestId(options.requestId)}Copilot ${init.method ?? \"GET\"} ${path} -> ${response.status} ${ms}ms (attempt ${attempt}) upstream_request_id=${upstreamRequestId}`,\n )\n\n if (!shouldRetryResponse(response) || attempt === maxFetchAttempts) {\n return response\n }\n log.error(\n `${formatRequestId(options.requestId)}Copilot ${path} returned ${response.status}; retrying (${attempt}/${maxFetchAttempts}) upstream_request_id=${upstreamRequestId}`,\n )\n } catch (error) {\n const abortError = toCopilotAbortHTTPError(error, signal, timeoutMs)\n if (abortError) {\n logUpstreamLifecycle(\n options.requestId,\n `upstream failed method=${init.method ?? \"GET\"} path=${path} attempt=${attempt} upstream_request_id=${upstreamRequestId}`,\n )\n throw abortError\n }\n\n logUpstreamLifecycle(\n options.requestId,\n `upstream failed method=${init.method ?? \"GET\"} path=${path} attempt=${attempt} upstream_request_id=${upstreamRequestId}`,\n )\n lastError = error\n if (attempt === maxFetchAttempts) {\n log.error(\n `${formatRequestId(options.requestId)}Copilot ${path} request failed after ${attempt} attempts upstream_request_id=${upstreamRequestId}`,\n error,\n )\n throw error\n }\n log.error(\n `${formatRequestId(options.requestId)}Copilot ${path} request failed; retrying (${attempt}/${maxFetchAttempts}) upstream_request_id=${upstreamRequestId}`,\n error,\n )\n }\n }\n\n throw lastError\n}\n","// Internal conversion between Copilot Responses API payloads and chat-completion-like results.\nimport { createHash, randomUUID } from \"node:crypto\"\n\nimport type {\n ChatCompletionChunk,\n ChatCompletionResponse,\n ChatCompletionsPayload,\n ContentPart,\n Message,\n Tool,\n} from \"~/copilot/types\"\n\nimport { sanitizeUserIdentifier } from \"./chat\"\n\nexport interface ResponseStreamEventMessage {\n data?: string\n event?: string\n}\n\nexport interface ResponsesApiResponse {\n id: string\n created_at: number\n model: string\n output: Array<ResponsesOutputItem>\n reasoning?: ResponsesReasoningSummaryContainer | null\n usage?: {\n input_tokens: number\n input_tokens_details?: {\n cached_tokens?: number\n }\n output_tokens: number\n output_tokens_details?: {\n reasoning_tokens?: number\n }\n total_tokens: number\n }\n incomplete_details?: {\n reason?: string | null\n } | null\n}\n\nexport type ResponsesReasoningEffort =\n | \"none\"\n | \"low\"\n | \"medium\"\n | \"high\"\n | \"xhigh\"\n\ntype ResponsesInput = string | Array<ResponsesInputItem>\n\ntype ResponsesInputItem =\n | ResponsesMessageInput\n | ResponsesFunctionCallInput\n | ResponsesFunctionCallOutputInput\n\ntype ResponsesMessageInput = {\n role: \"user\" | \"assistant\" | \"system\" | \"developer\"\n content: string | Array<ResponsesInputContentPart>\n}\n\ntype ResponsesInputContentPart =\n | {\n type: \"input_text\"\n text: string\n }\n | {\n type: \"input_image\"\n image_url: string\n detail: \"low\" | \"high\" | \"auto\"\n }\n\ntype ResponsesFunctionCallInput = {\n type: \"function_call\"\n call_id: string\n name: string\n arguments: string\n}\n\ntype ResponsesFunctionCallOutputInput = {\n type: \"function_call_output\"\n call_id: string\n output: string\n}\n\ntype ResponsesToolChoice =\n | \"none\"\n | \"auto\"\n | \"required\"\n | { type: \"function\"; name: string }\n\nexport interface ResponsesRequestPayload {\n model: string\n input: ResponsesInput\n stream?: boolean | null\n max_output_tokens?: number | null\n temperature?: number | null\n top_p?: number | null\n user?: string | null\n prompt_cache_key?: string | null\n reasoning?: {\n effort: ResponsesReasoningEffort\n }\n tools?: Array<ResponsesTool>\n tool_choice?: ResponsesToolChoice | null\n text?: {\n format: {\n type: \"json_object\"\n }\n }\n}\n\ninterface ResponsesTool {\n type: \"function\"\n name: string\n description?: string\n parameters: Record<string, unknown>\n}\n\ntype ResponsesOutputItem =\n | ResponsesMessageOutputItem\n | ResponsesFunctionCallOutputItem\n | ResponsesReasoningOutputItem\n\ninterface ResponsesMessageOutputItem {\n type: \"message\"\n role: \"assistant\"\n content: Array<ResponsesMessageContentPart>\n}\n\ninterface ResponsesMessageContentPart {\n type: \"output_text\"\n text: string\n}\n\ninterface ResponsesFunctionCallOutputItem {\n type: \"function_call\"\n call_id: string\n name: string\n arguments: string\n}\n\ninterface ResponsesReasoningOutputItem {\n type: \"reasoning\"\n summary?: ResponsesReasoningSummary\n}\n\ntype ResponsesReasoningSummary =\n | string\n | Array<ResponsesReasoningSummaryPart>\n | null\n\ntype ResponsesReasoningSummaryPart = {\n type?: string\n text?: string\n}\n\ninterface ResponsesReasoningSummaryContainer {\n summary?: ResponsesReasoningSummary\n}\n\ninterface ResponsesStreamEnvelope {\n type: string\n response?: {\n id: string\n created_at: number\n model: string\n usage?: ResponsesApiResponse[\"usage\"]\n output?: Array<ResponsesOutputItem>\n reasoning?: ResponsesReasoningSummaryContainer | null\n incomplete_details?: ResponsesApiResponse[\"incomplete_details\"]\n }\n item?:\n | Partial<ResponsesMessageOutputItem>\n | Partial<ResponsesFunctionCallOutputItem>\n | Partial<ResponsesReasoningOutputItem>\n output_index?: number\n delta?: string\n text?: string\n arguments?: string\n}\n\ninterface ResponseTranslationState {\n responseId: string\n createdAt: number\n model: string\n started: boolean\n reasoningTextSent: boolean\n outputTextByIndex: Record<number, string>\n toolArgumentsByIndex: Record<number, string>\n toolStartedByIndex: Record<number, boolean>\n}\n\ninterface CreateChunkOptions {\n delta: ChatCompletionChunk[\"choices\"][0][\"delta\"]\n finishReason?: ChatCompletionChunk[\"choices\"][0][\"finish_reason\"]\n usage?: ChatCompletionChunk[\"usage\"]\n}\n\n// /models does not tell us which API surface a model requires, so keep the\n// Responses-only allowlist narrow and suffix-tolerant.\nconst responsesOnlyModelPattern = /^(?:gpt-5\\.5)(?:-|$)/i\n\nexport function shouldUseResponsesApiForModel(model: string): boolean {\n return responsesOnlyModelPattern.test(model)\n}\n\nexport function buildResponsesRequestPayload(\n payload: ChatCompletionsPayload,\n reasoningEffort: ResponsesReasoningEffort | undefined,\n): ResponsesRequestPayload {\n // Responses API uses an `input` tree instead of chat `messages`, but the\n // rest of the bridge still reasons in chat-completion terms. Keep this as\n // the single boundary where chat payloads become Responses payloads.\n return {\n model: payload.model,\n input: translateMessagesToResponsesInput(payload.messages),\n stream: payload.stream,\n max_output_tokens: payload.max_tokens,\n temperature: payload.temperature,\n top_p: payload.top_p,\n user: sanitizeUserIdentifier(payload.user),\n // Copilot /responses only returns prompt cache hits when a stable\n // prompt_cache_key pins repeated requests to the same backend. Without it,\n // cached_tokens randomly drops to 0 across turns even for identical\n // prefixes (measured). Derive a per-conversation key so a Claude Code\n // session keeps hitting its own warm cache while staying isolated from\n // other sessions.\n prompt_cache_key: deriveResponsesCacheKey(payload),\n tools: translateTools(payload.tools),\n tool_choice: translateToolChoice(payload.tool_choice),\n reasoning: reasoningEffort ? { effort: reasoningEffort } : undefined,\n text:\n payload.response_format?.type === \"json_object\" ?\n { format: { type: \"json_object\" } }\n : undefined,\n }\n}\n\nfunction deriveResponsesCacheKey(\n payload: ChatCompletionsPayload,\n): string | undefined {\n // Prefer the client-supplied conversation id (Claude Code sends a stable\n // metadata.user_id per session). Fall back to a hash of the system prompt so\n // even clients without a user id still route a stable prefix to one cache.\n const user = sanitizeUserIdentifier(payload.user)\n if (user) {\n return `cr-${createHash(\"sha256\").update(user).digest(\"hex\").slice(0, 32)}`\n }\n\n const systemPrompt = payload.messages.find((message) => message.role === \"system\")\n const systemText =\n typeof systemPrompt?.content === \"string\" ? systemPrompt.content\n : Array.isArray(systemPrompt?.content) ?\n systemPrompt.content\n .map((part) => (part.type === \"text\" ? part.text : \"\"))\n .join(\"\")\n : \"\"\n\n if (!systemText) {\n return undefined\n }\n\n return `cr-sys-${createHash(\"sha256\").update(systemText).digest(\"hex\").slice(0, 32)}`\n}\n\nexport function translateResponsesToChatCompletion(\n response: ResponsesApiResponse,\n): ChatCompletionResponse {\n const assistantMessages = response.output.filter(\n (item): item is ResponsesMessageOutputItem => item.type === \"message\",\n )\n const functionCalls = response.output.filter(\n (item): item is ResponsesFunctionCallOutputItem =>\n item.type === \"function_call\",\n )\n\n const content = assistantMessages\n .flatMap((item) => item.content)\n .map((part) => part.text)\n .join(\"\")\n const reasoningText = getResponsesReasoningText(response)\n\n // Merge Responses output items back into one chat-completion choice so the\n // Claude translation layer can stay shared for /chat/completions and\n // /responses upstream calls.\n return {\n id: response.id,\n object: \"chat.completion\",\n created: response.created_at,\n model: response.model,\n choices: [\n {\n index: 0,\n message: {\n role: \"assistant\",\n content: content || null,\n ...(reasoningText && { reasoning_text: reasoningText }),\n ...(functionCalls.length > 0 && {\n tool_calls: functionCalls.map((toolCall) => ({\n id: toolCall.call_id,\n type: \"function\" as const,\n function: {\n name: toolCall.name,\n arguments: toolCall.arguments,\n },\n })),\n }),\n },\n logprobs: null,\n finish_reason: getFinishReason(response, functionCalls.length > 0),\n },\n ],\n usage: translateUsage(response.usage),\n }\n}\n\nexport async function* translateResponsesStreamToChatCompletionStream(\n responseStream: AsyncIterable<ResponseStreamEventMessage>,\n): AsyncGenerator<ResponseStreamEventMessage> {\n // Responses streams can send deltas, done snapshots, and a final completed\n // payload. Track emitted suffixes so chat clients do not receive duplicates.\n const state: ResponseTranslationState = {\n responseId: randomUUID(),\n createdAt: Math.floor(Date.now() / 1000),\n model: \"\",\n started: false,\n reasoningTextSent: false,\n outputTextByIndex: {},\n toolArgumentsByIndex: {},\n toolStartedByIndex: {},\n }\n\n for await (const rawEvent of responseStream) {\n if (!rawEvent.data || rawEvent.data === \"[DONE]\") {\n continue\n }\n\n const event = JSON.parse(rawEvent.data) as ResponsesStreamEnvelope\n\n if (event.response) {\n state.responseId = event.response.id\n state.createdAt = event.response.created_at\n state.model = event.response.model\n }\n\n if (event.type === \"response.output_item.added\") {\n const chunk = handleOutputItemAdded(state, event)\n if (chunk) {\n yield chunk\n }\n continue\n }\n\n if (event.type === \"response.output_item.done\") {\n for (const chunk of handleOutputItemDone(state, event)) {\n yield chunk\n }\n continue\n }\n\n if (event.type === \"response.reasoning_summary_text.delta\") {\n if (event.delta) {\n yield createRoleChunk(state)\n yield createChunk(state, { delta: { reasoning_text: event.delta } })\n state.reasoningTextSent = true\n }\n continue\n }\n\n if (event.type === \"response.output_text.delta\") {\n const outputIndex = event.output_index ?? 0\n state.outputTextByIndex[outputIndex] = `${state.outputTextByIndex[outputIndex] ?? \"\"}${event.delta ?? \"\"}`\n yield createRoleChunk(state)\n yield createChunk(state, { delta: { content: event.delta } })\n continue\n }\n\n if (event.type === \"response.output_text.done\") {\n const outputIndex = event.output_index ?? 0\n const content = getMissingSuffix(\n state.outputTextByIndex[outputIndex] ?? \"\",\n event.text,\n )\n if (content) {\n state.outputTextByIndex[outputIndex] = `${state.outputTextByIndex[outputIndex] ?? \"\"}${content}`\n yield createRoleChunk(state)\n yield createChunk(state, { delta: { content } })\n }\n continue\n }\n\n if (event.type === \"response.function_call_arguments.delta\") {\n if (event.output_index === undefined) {\n continue\n }\n\n state.toolArgumentsByIndex[event.output_index] = `${state.toolArgumentsByIndex[event.output_index] ?? \"\"}${event.delta ?? \"\"}`\n yield createRoleChunk(state)\n yield createChunk(state, {\n delta: {\n tool_calls: [\n {\n index: event.output_index,\n type: \"function\",\n function: {\n arguments: event.delta ?? \"\",\n },\n },\n ],\n },\n })\n continue\n }\n\n if (event.type === \"response.function_call_arguments.done\") {\n if (event.output_index === undefined) {\n continue\n }\n\n const content = getMissingSuffix(\n state.toolArgumentsByIndex[event.output_index] ?? \"\",\n event.arguments,\n )\n if (content) {\n state.toolArgumentsByIndex[event.output_index] = `${state.toolArgumentsByIndex[event.output_index] ?? \"\"}${content}`\n yield createRoleChunk(state)\n yield createChunk(state, {\n delta: {\n tool_calls: [\n {\n index: event.output_index,\n type: \"function\",\n function: { arguments: content },\n },\n ],\n },\n })\n }\n continue\n }\n\n if (event.type === \"response.completed\") {\n if (!event.response) {\n continue\n }\n\n const reasoningText = getResponsesReasoningText({\n output: event.response.output ?? [],\n reasoning: event.response.reasoning,\n })\n if (reasoningText && !state.reasoningTextSent) {\n yield createRoleChunk(state)\n yield createChunk(state, { delta: { reasoning_text: reasoningText } })\n state.reasoningTextSent = true\n }\n\n yield createChunk(\n {\n ...state,\n responseId: event.response.id,\n createdAt: event.response.created_at,\n model: event.response.model,\n },\n {\n delta: {},\n finishReason: getFinishReason(\n {\n output: event.response.output ?? [],\n incomplete_details: event.response.incomplete_details,\n },\n (event.response.output ?? []).some(\n (item) => item.type === \"function_call\",\n ),\n ),\n usage: translateUsage(event.response.usage),\n },\n )\n yield { data: \"[DONE]\" }\n return\n }\n }\n}\n\nfunction handleOutputItemAdded(\n state: ResponseTranslationState,\n event: ResponsesStreamEnvelope,\n): ResponseStreamEventMessage | undefined {\n if (event.item?.type === \"message\") {\n return createRoleChunk(state)\n }\n\n if (event.item?.type === \"reasoning\") {\n const reasoningText = getSummaryText(event.item.summary)\n if (!reasoningText) {\n return undefined\n }\n\n state.reasoningTextSent = true\n return createChunk(state, { delta: { reasoning_text: reasoningText } })\n }\n\n if (\n event.item?.type === \"function_call\"\n && event.output_index !== undefined\n ) {\n const initialArguments = event.item.arguments ?? \"\"\n state.started = true\n state.toolStartedByIndex[event.output_index] = true\n state.toolArgumentsByIndex[event.output_index] = initialArguments\n return createChunk(state, {\n delta: {\n role: \"assistant\",\n tool_calls: [\n {\n index: event.output_index,\n id: event.item.call_id,\n type: \"function\",\n function: {\n name: event.item.name,\n arguments: initialArguments,\n },\n },\n ],\n },\n })\n }\n\n return undefined\n}\n\nfunction handleOutputItemDone(\n state: ResponseTranslationState,\n event: ResponsesStreamEnvelope,\n): Array<ResponseStreamEventMessage> {\n if (event.item?.type === \"reasoning\") {\n const reasoningText = getSummaryText(event.item.summary)\n if (!reasoningText || state.reasoningTextSent) {\n return []\n }\n\n state.reasoningTextSent = true\n return [createChunk(state, { delta: { reasoning_text: reasoningText } })]\n }\n\n if (event.item?.type === \"message\") {\n const outputIndex = event.output_index ?? 0\n const fullText = getMessageOutputText(event.item.content)\n const content = getMissingSuffix(\n state.outputTextByIndex[outputIndex] ?? \"\",\n fullText,\n )\n if (!content) {\n return []\n }\n\n state.outputTextByIndex[outputIndex] = `${state.outputTextByIndex[outputIndex] ?? \"\"}${content}`\n return [createRoleChunk(state), createChunk(state, { delta: { content } })]\n }\n\n if (\n event.item?.type === \"function_call\"\n && event.output_index !== undefined\n ) {\n const outputIndex = event.output_index\n const chunks: Array<ResponseStreamEventMessage> = []\n\n if (!state.toolStartedByIndex[outputIndex]) {\n const initialArguments = event.item.arguments ?? \"\"\n state.started = true\n state.toolStartedByIndex[outputIndex] = true\n state.toolArgumentsByIndex[outputIndex] = initialArguments\n chunks.push(\n createChunk(state, {\n delta: {\n role: \"assistant\",\n tool_calls: [\n {\n index: outputIndex,\n id: event.item.call_id,\n type: \"function\",\n function: {\n name: event.item.name,\n arguments: initialArguments,\n },\n },\n ],\n },\n }),\n )\n return chunks\n }\n\n const content = getMissingSuffix(\n state.toolArgumentsByIndex[outputIndex] ?? \"\",\n event.item.arguments,\n )\n if (content) {\n state.toolArgumentsByIndex[outputIndex] = `${state.toolArgumentsByIndex[outputIndex] ?? \"\"}${content}`\n chunks.push(\n createRoleChunk(state),\n createChunk(state, {\n delta: {\n tool_calls: [\n {\n index: outputIndex,\n type: \"function\",\n function: { arguments: content },\n },\n ],\n },\n }),\n )\n }\n\n return chunks\n }\n\n return []\n}\n\nfunction createRoleChunk(\n state: ResponseTranslationState,\n): ResponseStreamEventMessage {\n if (state.started) {\n return { data: \"\" }\n }\n\n state.started = true\n return createChunk(state, { delta: { role: \"assistant\" } })\n}\n\nfunction createChunk(\n state: ResponseTranslationState,\n { delta, finishReason = null, usage }: CreateChunkOptions,\n): ResponseStreamEventMessage {\n return {\n data: JSON.stringify({\n id: state.responseId,\n object: \"chat.completion.chunk\",\n created: state.createdAt,\n model: state.model,\n choices: [\n {\n index: 0,\n delta,\n finish_reason: finishReason,\n logprobs: null,\n },\n ],\n usage,\n } satisfies ChatCompletionChunk),\n }\n}\n\nfunction translateMessagesToResponsesInput(\n messages: Array<Message>,\n): ResponsesInput {\n // Copilot accepts a bare string for the simplest single-user prompt, but\n // multi-turn, tool, or image conversations need structured input items.\n const items = messages.flatMap((message) => translateMessage(message))\n\n if (\n items.length === 1\n && \"role\" in items[0]\n && items[0].role === \"user\"\n && typeof items[0].content === \"string\"\n ) {\n return items[0].content\n }\n\n return items\n}\n\nfunction translateMessage(message: Message): Array<ResponsesInputItem> {\n if (message.role === \"tool\") {\n return [\n {\n type: \"function_call_output\",\n call_id: message.tool_call_id ?? \"\",\n output: stringifyToolOutput(message.content),\n },\n ]\n }\n\n const translated: Array<ResponsesInputItem> = []\n\n if (hasContent(message.content)) {\n translated.push({\n role: message.role,\n content: translateContent(message.content),\n })\n }\n\n if (message.role === \"assistant\" && message.tool_calls) {\n translated.push(\n ...message.tool_calls.map((toolCall) => ({\n type: \"function_call\" as const,\n call_id: toolCall.id,\n name: toolCall.function.name,\n arguments: toolCall.function.arguments,\n })),\n )\n }\n\n return translated\n}\n\nfunction hasContent(content: Message[\"content\"]): boolean {\n if (content === null) {\n return false\n }\n\n if (typeof content === \"string\") {\n return content.length > 0\n }\n\n return content.length > 0\n}\n\nfunction translateContent(\n content: Message[\"content\"],\n): ResponsesMessageInput[\"content\"] {\n if (typeof content === \"string\") {\n return content\n }\n\n if (!content || content.length === 0) {\n return \"\"\n }\n\n return content.map((part) => translateContentPart(part))\n}\n\nfunction translateContentPart(part: ContentPart): ResponsesInputContentPart {\n if (part.type === \"text\") {\n return {\n type: \"input_text\",\n text: part.text,\n }\n }\n\n return {\n type: \"input_image\",\n image_url: part.image_url.url,\n detail: part.image_url.detail ?? \"auto\",\n }\n}\n\nfunction stringifyToolOutput(content: Message[\"content\"]): string {\n if (typeof content === \"string\") {\n return content\n }\n\n if (!content) {\n return \"\"\n }\n\n const text = content\n .filter(\n (part): part is Extract<ContentPart, { type: \"text\" }> =>\n part.type === \"text\",\n )\n .map((part) => part.text)\n .join(\"\\n\\n\")\n\n return text || JSON.stringify(content)\n}\n\nfunction translateTools(\n tools: Array<Tool> | null | undefined,\n): Array<ResponsesTool> | undefined {\n if (!tools) {\n return undefined\n }\n\n return tools.map((tool) => ({\n type: \"function\",\n name: tool.function.name,\n description: tool.function.description,\n parameters: tool.function.parameters,\n }))\n}\n\nfunction translateToolChoice(\n toolChoice: ChatCompletionsPayload[\"tool_choice\"],\n): ResponsesToolChoice | undefined {\n if (!toolChoice) {\n return undefined\n }\n\n if (typeof toolChoice === \"string\") {\n return toolChoice\n }\n\n return {\n type: \"function\",\n name: toolChoice.function.name,\n }\n}\n\nfunction translateUsage(\n usage: ResponsesApiResponse[\"usage\"] | undefined,\n): ChatCompletionResponse[\"usage\"] | undefined {\n if (!usage) {\n return undefined\n }\n\n return {\n prompt_tokens: usage.input_tokens,\n completion_tokens: usage.output_tokens,\n total_tokens: usage.total_tokens,\n ...(usage.input_tokens_details?.cached_tokens !== undefined && {\n prompt_tokens_details: {\n cached_tokens: usage.input_tokens_details.cached_tokens,\n },\n }),\n }\n}\n\nfunction getMessageOutputText(\n content: ResponsesMessageOutputItem[\"content\"] | undefined,\n): string | undefined {\n const text = content\n ?.filter((part) => part.type === \"output_text\")\n .map((part) => part.text)\n .join(\"\")\n\n return text || undefined\n}\n\nfunction getMissingSuffix(\n alreadySent: string,\n finalValue: string | undefined,\n): string | undefined {\n // Responses \"done\" events often repeat the full text/arguments after deltas;\n // emit only the suffix that has not already been forwarded to the chat stream.\n if (!finalValue) {\n return undefined\n }\n\n if (!alreadySent) {\n return finalValue\n }\n\n if (!finalValue.startsWith(alreadySent)) {\n return undefined\n }\n\n const suffix = finalValue.slice(alreadySent.length)\n return suffix || undefined\n}\n\nfunction getResponsesReasoningText(\n response: Pick<ResponsesApiResponse, \"output\" | \"reasoning\">,\n): string | undefined {\n const parts = [\n getSummaryText(response.reasoning?.summary),\n ...response.output\n .filter((item): item is ResponsesReasoningOutputItem => item.type === \"reasoning\")\n .map((item) => getSummaryText(item.summary)),\n ].filter((part): part is string => Boolean(part))\n\n return parts.length > 0 ? parts.join(\"\\n\\n\") : undefined\n}\n\nfunction getSummaryText(summary: ResponsesReasoningSummary | undefined): string | undefined {\n if (typeof summary === \"string\") {\n return summary || undefined\n }\n\n if (!Array.isArray(summary)) {\n return undefined\n }\n\n const text = summary\n .map((part) => part.text)\n .filter((part): part is string => Boolean(part))\n .join(\"\\n\\n\")\n\n return text || undefined\n}\n\nfunction getFinishReason(\n response: Pick<ResponsesApiResponse, \"output\" | \"incomplete_details\">,\n hasFunctionCalls: boolean,\n): \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" {\n if (hasFunctionCalls) {\n return \"tool_calls\"\n }\n\n if (response.incomplete_details?.reason?.includes(\"max_output_tokens\")) {\n return \"length\"\n }\n\n return \"stop\"\n}\n","// Internal Copilot chat API wrapper used by the Claude route and startup preflight.\nimport { events } from \"fetch-event-stream\"\n\nimport type { ProxyConfig } from \"~/lib/config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { log } from \"~/lib/log\"\nimport { defaultReasoningEffort } from \"~/lib/models\"\nimport { routeModelId } from \"~/lib/models\"\nimport { runtimeState } from \"~/lib/state\"\nimport {\n createCopilotRequestSignal,\n fetchCopilot,\n getCopilotProviderContext,\n readCopilotJson,\n readCopilotText,\n} from \"~/copilot/client\"\nimport type {\n ChatCompletionResponse,\n ChatCompletionsPayload,\n} from \"~/copilot/types\"\n\nimport {\n buildResponsesRequestPayload,\n shouldUseResponsesApiForModel,\n translateResponsesStreamToChatCompletionStream,\n translateResponsesToChatCompletion,\n type ResponsesApiResponse,\n type ResponsesReasoningEffort,\n type ResponsesRequestPayload,\n} from \"./responses\"\n\nconst usesMaxCompletionTokens = (modelId: string): boolean =>\n modelId.startsWith(\"gpt-5\")\n\nconst continuePrefillPrompt =\n \"Continue the assistant response from the previous assistant message.\"\n\ntype ClientKind = \"claude\" | \"generic\"\n\ninterface CreateChatCompletionsOptions {\n client?: ClientKind\n requestId?: string\n requestedModel?: string\n requestedThinkEffort?: string\n requestedThinking?: string\n signal?: AbortSignal\n timeoutMs?: number\n}\n\nconst maxUserLength = 64\n\nexport const sanitizeReasoningEffortForModel = (\n _modelId: string,\n reasoningEffort: ChatCompletionsPayload[\"reasoning_effort\"],\n): ChatCompletionsPayload[\"reasoning_effort\"] => {\n return reasoningEffort ?? undefined\n}\n\nconst getRequestedReasoningEffort = (\n payload: ChatCompletionsPayload,\n): ChatCompletionsPayload[\"reasoning_effort\"] => {\n // Configured think effort wins over client input so startup preflight and\n // actual Claude Code traffic exercise the same upstream behavior.\n return sanitizeReasoningEffortForModel(\n payload.model,\n runtimeState.thinkEffort ?? defaultReasoningEffort,\n )\n}\n\nexport const sanitizeUserIdentifier = (\n user: string | null | undefined,\n): string | undefined => {\n if (!user) {\n return undefined\n }\n\n return user.slice(0, maxUserLength)\n}\n\ntype ChatCompletionsRequestPayload = Omit<\n ChatCompletionsPayload,\n \"max_tokens\"\n> & {\n max_tokens?: number | null\n max_completion_tokens?: number | null\n}\n\nconst buildRequestPayload = (\n payload: ChatCompletionsPayload,\n): ChatCompletionsRequestPayload => {\n const requestedReasoningEffort = getRequestedReasoningEffort(payload)\n\n if (\n !usesMaxCompletionTokens(payload.model)\n || payload.max_tokens === null\n || payload.max_tokens === undefined\n ) {\n const sanitizedPayload = {\n ...payload,\n reasoning_effort: requestedReasoningEffort,\n user: sanitizeUserIdentifier(payload.user),\n }\n\n return sanitizedPayload\n }\n\n // GPT-5-class Copilot endpoints reject max_tokens and require the newer\n // max_completion_tokens field; older models still use max_tokens.\n return {\n ...payload,\n max_tokens: undefined,\n max_completion_tokens: payload.max_tokens,\n reasoning_effort: requestedReasoningEffort,\n user: sanitizeUserIdentifier(payload.user),\n }\n}\n\nconst normalizeFinalAssistantPrefill = (\n payload: ChatCompletionsPayload,\n): ChatCompletionsPayload => {\n const lastMessage = payload.messages.at(-1)\n if (lastMessage?.role !== \"assistant\") {\n return payload\n }\n\n const messages = [...payload.messages]\n if (typeof lastMessage.content !== \"string\") {\n messages.pop()\n return { ...payload, messages }\n }\n\n const content = lastMessage.content.trimEnd()\n if (!content) {\n messages.pop()\n return { ...payload, messages }\n }\n\n messages[messages.length - 1] = {\n ...lastMessage,\n content,\n }\n messages.push({ role: \"user\", content: continuePrefillPrompt })\n return { ...payload, messages }\n}\n\nconst isAgentInitiator = (\n messages: ChatCompletionsPayload[\"messages\"],\n): \"agent\" | \"user\" =>\n messages.some((msg) => msg.role === \"assistant\" || msg.role === \"tool\") ?\n \"agent\"\n : \"user\"\n\nconst messagesIncludeImage = (\n messages: ChatCompletionsPayload[\"messages\"],\n): boolean =>\n messages.some(\n (msg) =>\n typeof msg.content !== \"string\"\n && msg.content?.some((part) => part.type === \"image_url\"),\n )\n\nexport const createChatCompletions = async (\n config: ProxyConfig,\n payload: ChatCompletionsPayload,\n options: CreateChatCompletionsOptions = {},\n) => {\n const client = options.client ?? \"generic\"\n const requestedModel = options.requestedModel ?? payload.model\n const requestedThinkEffort =\n options.requestedThinkEffort ?? payload.reasoning_effort ?? \"none\"\n const requestedThinking = options.requestedThinking ?? \"none\"\n const signal = createCopilotRequestSignal(options.signal, options.timeoutMs)\n const upstreamModelId = routeModelId(payload.model)\n const upstreamPayload =\n upstreamModelId === payload.model ? payload : { ...payload, model: upstreamModelId }\n const useResponsesApi = shouldUseResponsesApiForModel(upstreamPayload.model)\n const compatiblePayload =\n useResponsesApi ? upstreamPayload : normalizeFinalAssistantPrefill(upstreamPayload)\n const provider = getCopilotProviderContext(config)\n const enableVision = messagesIncludeImage(compatiblePayload.messages)\n const initiator = isAgentInitiator(compatiblePayload.messages)\n const requestPayload = buildRequestPayload(compatiblePayload)\n log.debug(\n [\n \"Model request\",\n `client=${client}`,\n `requested_model=${requestedModel}`,\n ...(options.requestId ? [`request_id=${options.requestId}`] : []),\n `upstream_model=${compatiblePayload.model}`,\n `requested_think_effort=${requestedThinkEffort}`,\n `requested_thinking=${requestedThinking}`,\n `effective_think_effort=${requestPayload.reasoning_effort ?? \"none\"}`,\n ].join(\" \"),\n )\n log.debug(\"Full request payload\", {\n payload: requestPayload,\n })\n // Choose the Copilot API surface after model routing, because aliases can\n // resolve to a Responses-only upstream model even when the client asked for a\n // generic Claude model name.\n if (useResponsesApi) {\n return createResponses(provider, compatiblePayload, {\n vision: enableVision,\n initiator,\n requestId: options.requestId,\n signal,\n timeoutMs: options.timeoutMs,\n })\n }\n\n const response = await fetchCopilot(\n provider,\n \"/chat/completions\",\n {\n method: \"POST\",\n headers: {\n accept: compatiblePayload.stream ? \"text/event-stream\" : \"application/json\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(requestPayload),\n },\n {\n vision: enableVision,\n initiator,\n requestId: options.requestId,\n signal,\n timeoutMs: options.timeoutMs,\n },\n )\n\n if (!response.ok) {\n if (await shouldRetryWithResponses(response, signal, options.timeoutMs)) {\n return createResponses(provider, compatiblePayload, {\n vision: enableVision,\n initiator,\n requestId: options.requestId,\n signal,\n timeoutMs: options.timeoutMs,\n })\n }\n\n const detail = await logUpstreamError(\"Failed to create chat completions\", response, {\n model: payload.model,\n request: requestPayload,\n route: \"/chat/completions\",\n requestId: options.requestId,\n }, signal, options.timeoutMs)\n throw new HTTPError(\n \"Failed to create chat completions\",\n response,\n detail,\n )\n }\n\n if (compatiblePayload.stream) {\n return events(response)\n }\n\n return readCopilotJson<ChatCompletionResponse>(\n response,\n signal,\n options.timeoutMs,\n )\n}\n\nasync function createResponses(\n provider: ReturnType<typeof getCopilotProviderContext>,\n payload: ChatCompletionsPayload,\n options: {\n vision: boolean\n initiator: \"agent\" | \"user\"\n requestId?: string\n signal?: AbortSignal\n timeoutMs?: number\n },\n) {\n const reasoningEffort = getRequestedReasoningEffort(\n payload,\n ) as ResponsesReasoningEffort | undefined\n const requestPayload = buildResponsesRequestPayload(payload, reasoningEffort)\n\n const response = await fetchCopilot(\n provider,\n \"/responses\",\n {\n method: \"POST\",\n headers: {\n accept: payload.stream ? \"text/event-stream\" : \"application/json\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(requestPayload),\n },\n {\n vision: options.vision,\n initiator: options.initiator,\n requestId: options.requestId,\n signal: options.signal,\n timeoutMs: options.timeoutMs,\n },\n )\n\n if (!response.ok) {\n const detail = await logUpstreamError(\"Failed to create responses\", response, {\n model: payload.model,\n request: requestPayload,\n route: \"/responses\",\n requestId: options.requestId,\n }, options.signal, options.timeoutMs)\n throw new HTTPError(\n \"Failed to create responses\",\n response,\n detail,\n )\n }\n\n if (payload.stream) {\n return translateResponsesStreamToChatCompletionStream(events(response))\n }\n\n return translateResponsesToChatCompletion(\n await readCopilotJson<ResponsesApiResponse>(\n response,\n options.signal,\n options.timeoutMs,\n ),\n )\n}\n\nasync function logUpstreamError(\n message: string,\n response: Response,\n context: {\n model: string\n request?: ChatCompletionsRequestPayload | ResponsesRequestPayload\n route: string\n requestId?: string\n },\n signal?: AbortSignal,\n timeoutMs?: number,\n): Promise<string | undefined> {\n const errorBody = await readCopilotText(\n response.clone(),\n signal,\n timeoutMs,\n ).catch(() => \"\")\n const detail = getUpstreamErrorDetail(response, errorBody)\n\n log.error(`${message}: route=${context.route} model=${context.model} status=${response.status}${context.requestId ? ` request_id=${context.requestId}` : \"\"}`, {\n message,\n route: context.route,\n model: context.model,\n requestId: context.requestId,\n request: context.request,\n response: {\n status: response.status,\n statusText: response.statusText || undefined,\n url: response.url || undefined,\n headers: Object.fromEntries(response.headers.entries()),\n body: errorBody || undefined,\n },\n })\n\n return detail\n}\n\nfunction getUpstreamErrorDetail(\n response: Response,\n body: string,\n): string | undefined {\n if (!body) {\n return response.statusText || undefined\n }\n\n try {\n const payload = JSON.parse(body) as {\n error?: {\n code?: string\n message?: string\n }\n }\n return payload.error?.message ?? payload.error?.code ?? body.slice(0, 240)\n } catch {\n return body.slice(0, 240)\n }\n}\n\nasync function shouldRetryWithResponses(\n response: Response,\n signal?: AbortSignal,\n timeoutMs?: number,\n): Promise<boolean> {\n // Copilot can list a model but reject the chat endpoint for it; only this\n // explicit upstream code is treated as a signal to retry via /responses.\n try {\n const errorBody = await readCopilotJson<{\n error?: {\n code?: string\n }\n }>(response.clone(), signal, timeoutMs)\n return errorBody.error?.code === \"unsupported_api_for_model\"\n } catch {\n return false\n }\n}\n","// Startup preflight: fail fast if configured models or think effort cannot be used upstream.\nimport type { ProxyConfig } from \"~/lib/config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { log } from \"~/lib/log\"\nimport type { ReasoningEffort } from \"~/lib/models\"\nimport { getExposedModelIds } from \"~/lib/models\"\nimport {\n createCopilotRequestSignal,\n fetchCopilot,\n getCopilotProviderContext,\n readCopilotJson,\n} from \"~/copilot/client\"\nimport type { ChatCompletionsPayload } from \"~/copilot/types\"\nimport { createChatCompletions } from \"~/copilot/chat\"\n\ninterface CopilotModelsResponse {\n data?: Array<{ id?: string }>\n}\n\nconst getUpstreamModelIds = async (config: ProxyConfig): Promise<Set<string>> => {\n const provider = getCopilotProviderContext(config)\n const signal = createCopilotRequestSignal(undefined, config.upstreamTimeoutMs)\n const response = await fetchCopilot(provider, \"/models\", {\n method: \"GET\",\n headers: { accept: \"application/json\" },\n }, { signal, timeoutMs: config.upstreamTimeoutMs })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to validate upstream models\", response)\n }\n\n const payload = await readCopilotJson<CopilotModelsResponse>(\n response,\n signal,\n config.upstreamTimeoutMs,\n )\n return new Set(\n (payload.data ?? [])\n .map((model) => model.id)\n .filter((id): id is string => typeof id === \"string\" && id.length > 0),\n )\n}\n\nconst ensureRequiredModels = async (config: ProxyConfig): Promise<void> => {\n const upstreamModels = await getUpstreamModelIds(config)\n const requiredModels = getExposedModelIds()\n const missingModels = requiredModels.filter((model) => !upstreamModels.has(model))\n\n if (missingModels.length > 0) {\n throw new Error(\n `Required Copilot model(s) unavailable upstream: ${missingModels.join(\", \")}`,\n )\n }\n\n log.info(`Upstream models available: ${requiredModels.join(\", \")}`)\n}\n\nconst createProbePayload = (model: string): ChatCompletionsPayload => ({\n model,\n max_tokens: 16,\n stream: false,\n messages: [\n {\n role: \"user\",\n content: \"Reply with OK only.\",\n },\n ],\n})\n\nconst validateModelRequest = async (\n config: ProxyConfig,\n model: string,\n thinkEffort: ReasoningEffort,\n): Promise<void> => {\n try {\n // Probe through the same internal chat path as real requests so routing,\n // token headers, think effort, and /responses fallback are validated together.\n const response = await createChatCompletions(\n config,\n createProbePayload(model),\n {\n client: \"generic\",\n requestedModel: model,\n timeoutMs: config.upstreamTimeoutMs,\n },\n )\n\n if (typeof response !== \"object\" || response === null || !(\"choices\" in response)) {\n throw new Error(`Preflight request for ${model} unexpectedly streamed`)\n }\n\n log.info(`Preflight OK: model=${model} think_effort=${thinkEffort}`)\n } catch (error) {\n if (error instanceof HTTPError) {\n const text = await error.response.text().catch(() => \"\")\n throw new Error(\n `Preflight failed for model=${model} think_effort=${thinkEffort}: ${error.response.status} ${error.response.statusText}${text ? ` ${text}` : \"\"}`,\n )\n }\n throw error\n }\n}\n\nexport const validateUpstream = async (\n config: ProxyConfig,\n thinkEffort: ReasoningEffort,\n): Promise<void> => {\n log.info(\"Running upstream preflight\")\n await ensureRequiredModels(config)\n\n for (const model of getExposedModelIds()) {\n await validateModelRequest(config, model, thinkEffort)\n }\n}\n","// Reads package.json version from either source or bundled dist layouts.\nimport { readFileSync } from \"node:fs\"\nimport { dirname, resolve } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\ninterface PackageJson {\n name?: string\n version?: string\n}\n\nconst packageName = \"copilot-relay\"\n\nconst readPackageVersion = (): string => {\n let currentDir = dirname(fileURLToPath(import.meta.url))\n\n while (true) {\n try {\n const packageJsonPath = resolve(currentDir, \"package.json\")\n const packageJson = JSON.parse(\n readFileSync(packageJsonPath, \"utf8\"),\n ) as PackageJson\n\n if (\n packageJson.name === packageName\n && typeof packageJson.version === \"string\"\n ) {\n return packageJson.version\n }\n } catch {\n // Keep walking upward; source and dist builds sit at different depths.\n }\n\n const parentDir = dirname(currentDir)\n if (parentDir === currentDir) {\n return \"unknown\"\n }\n\n currentDir = parentDir\n }\n}\n\nexport const appVersion = readPackageVersion()\n","// Small Claude protocol helpers shared by streaming and non-streaming translators.\nimport type { ClaudeResponse } from \"~/claude/types\"\n\nexport function mapOpenAIStopReasonToClaude(\n finishReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null,\n): ClaudeResponse[\"stop_reason\"] {\n if (finishReason === null) {\n return null\n }\n\n const stopReasonMap = {\n stop: \"end_turn\",\n length: \"max_tokens\",\n tool_calls: \"tool_use\",\n content_filter: \"end_turn\",\n } as const\n\n return stopReasonMap[finishReason]\n}\n","// Maps Claude tool names to Copilot-compatible tool names and back.\nimport { createHash } from \"node:crypto\"\n\nimport type { ClaudeTool } from \"~/claude/types\"\n\nconst strictToolNameCharsPattern = /^[A-Za-z0-9_-]+$/\nconst dottedToolNameCharsPattern = /^[A-Za-z0-9_.-]+$/\nconst defaultToolNameMaxLength = 64\nconst extendedToolNameMaxLength = 128\nconst hashLength = 10\n\nexport interface ClaudeToolNameMapper {\n toClaude(name: string): string\n toOpenAI(name: string): string\n}\n\ninterface ToolNameMapperOptions {\n allowDots?: boolean\n maxNameLength?: number\n}\n\nexport const getToolNameMapperOptionsForModel = (\n modelId: string,\n): Required<ToolNameMapperOptions> => {\n const normalized = modelId\n .trim()\n .toLowerCase()\n .replace(/\\[1m\\]$/, \"-1m\")\n .replace(/[._]/g, \"-\")\n\n if (normalized.startsWith(\"gpt-\")) {\n return { allowDots: false, maxNameLength: extendedToolNameMaxLength }\n }\n\n return { allowDots: false, maxNameLength: defaultToolNameMaxLength }\n}\n\nexport const getClaudeToolNameMaxLength = (modelId: string): number =>\n getToolNameMapperOptionsForModel(modelId).maxNameLength\n\nconst makeHash = (value: string): string =>\n createHash(\"sha1\").update(value).digest(\"hex\").slice(0, hashLength)\n\nconst getAllowedNamePattern = (allowDots: boolean): RegExp =>\n allowDots ? dottedToolNameCharsPattern : strictToolNameCharsPattern\n\nconst cleanToolName = (name: string, allowDots: boolean): string => {\n const invalidCharsPattern = allowDots ? /[^A-Za-z0-9_.-]/g : /[^A-Za-z0-9_-]/g\n const cleaned = name.replace(invalidCharsPattern, \"_\").replace(/_+/g, \"_\")\n return cleaned.replace(/^_+|_+$/g, \"\") || \"tool\"\n}\n\nconst isValidToolName = (\n name: string,\n maxNameLength: number,\n allowDots: boolean,\n): boolean =>\n name.length > 0\n && name.length <= maxNameLength\n && getAllowedNamePattern(allowDots).test(name)\n\nconst makeValidToolName = (\n name: string,\n maxNameLength: number,\n allowDots: boolean,\n): string => {\n if (isValidToolName(name, maxNameLength, allowDots)) {\n return name\n }\n\n const cleaned = cleanToolName(name, allowDots)\n if (cleaned.length <= maxNameLength) {\n return cleaned\n }\n\n const hash = makeHash(name)\n const prefixLength = maxNameLength - hash.length - 1\n return `${cleaned.slice(0, prefixLength)}_${hash}`\n}\n\nconst makeUniqueToolName = (\n name: string,\n used: Set<string>,\n maxNameLength: number,\n allowDots: boolean,\n): string => {\n const candidate = makeValidToolName(name, maxNameLength, allowDots)\n if (!used.has(candidate)) {\n return candidate\n }\n\n for (let index = 2; ; index++) {\n const suffix = `_${makeHash(`${name}:${index}`)}`\n const prefixLength = maxNameLength - suffix.length\n const next = `${cleanToolName(name, allowDots).slice(0, prefixLength)}${suffix}`\n if (!used.has(next)) {\n return next\n }\n }\n}\n\nexport const createClaudeToolNameMapper = (\n tools: Array<ClaudeTool> | undefined,\n options: ToolNameMapperOptions = {},\n): ClaudeToolNameMapper => {\n const maxNameLength = options.maxNameLength ?? defaultToolNameMaxLength\n const allowDots = options.allowDots ?? false\n const claudeToOpenAI = new Map<string, string>()\n const openAIToClaude = new Map<string, string>()\n const used = new Set<string>()\n\n for (const tool of tools ?? []) {\n if (claudeToOpenAI.has(tool.name)) {\n continue\n }\n\n const openAIName = makeUniqueToolName(\n tool.name,\n used,\n maxNameLength,\n allowDots,\n )\n used.add(openAIName)\n claudeToOpenAI.set(tool.name, openAIName)\n openAIToClaude.set(openAIName, tool.name)\n }\n\n return {\n toClaude: (name) => openAIToClaude.get(name) ?? name,\n toOpenAI: (name) =>\n claudeToOpenAI.get(name)\n ?? makeValidToolName(name, maxNameLength, allowDots),\n }\n}\n","// Non-streaming protocol translation between Claude Messages and Copilot chat completions.\nimport { defaultReasoningEffort } from \"~/lib/models\"\nimport { routeModelId } from \"~/lib/models\"\nimport { runtimeState } from \"~/lib/state\"\nimport type {\n ChatCompletionResponse,\n ChatCompletionsPayload,\n ContentPart,\n Message,\n TextPart,\n Tool,\n ToolCall,\n} from \"~/copilot/types\"\n\nimport {\n type ClaudeAssistantContentBlock,\n type ClaudeAssistantMessage,\n type ClaudeMessage,\n type ClaudeMessagesPayload,\n type ClaudeResponse,\n type ClaudeTextBlock,\n type ClaudeThinkingBlock,\n type ClaudeTool,\n type ClaudeToolResultBlock,\n type ClaudeToolUseBlock,\n type ClaudeUserContentBlock,\n type ClaudeUserMessage,\n} from \"~/claude/types\"\nimport { mapOpenAIStopReasonToClaude } from \"~/claude/utils\"\nimport {\n createClaudeToolNameMapper,\n getToolNameMapperOptionsForModel,\n type ClaudeToolNameMapper,\n} from \"~/claude/tool-names\"\n\nexport function translateModelName(model: string): string {\n return routeModelId(model)\n}\n\nexport function translateToOpenAI(\n payload: ClaudeMessagesPayload,\n _settings?: undefined,\n toolNameMapper?: ClaudeToolNameMapper,\n): ChatCompletionsPayload {\n const model = translateModelName(payload.model)\n const mapper = toolNameMapper ?? createClaudeToolNameMapper(payload.tools, {\n ...getToolNameMapperOptionsForModel(model),\n })\n const tools = translateClaudeToolsToOpenAI(payload.tools, mapper)\n const messages = translateClaudeMessagesToOpenAI(\n payload.messages,\n payload.system,\n mapper,\n )\n\n return {\n model,\n messages: normalizeFinalAssistantPrefill(messages),\n max_tokens: payload.max_tokens,\n stop: payload.stop_sequences,\n stream: payload.stream,\n temperature: payload.temperature,\n top_p: payload.top_p,\n reasoning_effort: runtimeState.thinkEffort ?? defaultReasoningEffort,\n user: payload.metadata?.user_id,\n tools,\n tool_choice:\n tools && tools.length > 0 ?\n translateClaudeToolChoiceToOpenAI(payload.tool_choice, mapper)\n : undefined,\n }\n}\n\nfunction translateClaudeMessagesToOpenAI(\n claudeMessages: Array<ClaudeMessage>,\n system: string | Array<ClaudeTextBlock> | undefined,\n toolNameMapper: ClaudeToolNameMapper,\n): Array<Message> {\n const systemMessages = handleSystemPrompt(system)\n const otherMessages = claudeMessages.flatMap((message) =>\n message.role === \"user\" ? handleUserMessage(message) : handleAssistantMessage(message, toolNameMapper),\n )\n return [...systemMessages, ...otherMessages]\n}\n\nfunction handleSystemPrompt(\n system: string | Array<ClaudeTextBlock> | undefined,\n): Array<Message> {\n if (!system) {\n return []\n }\n\n if (typeof system === \"string\") {\n return [{ role: \"system\", content: system }]\n }\n\n // Claude accepts multiple system text blocks; Copilot chat expects one\n // system message, so preserve block boundaries with blank lines.\n return [{ role: \"system\", content: system.map((block) => block.text).join(\"\\n\\n\") }]\n}\n\nfunction handleUserMessage(message: ClaudeUserMessage): Array<Message> {\n const newMessages: Array<Message> = []\n\n if (Array.isArray(message.content)) {\n const toolResultBlocks = message.content.filter(\n (block): block is ClaudeToolResultBlock => block.type === \"tool_result\",\n )\n const otherBlocks = message.content.filter((block) => block.type !== \"tool_result\")\n\n // Tool results must become standalone OpenAI tool messages before any\n // remaining user content, otherwise upstream cannot associate them with\n // prior assistant tool calls.\n for (const block of toolResultBlocks) {\n newMessages.push({\n role: \"tool\",\n tool_call_id: block.tool_use_id,\n content: mapContent(block.content),\n })\n }\n\n if (otherBlocks.length > 0) {\n newMessages.push({\n role: \"user\",\n content: mapContent(otherBlocks),\n })\n }\n } else {\n newMessages.push({\n role: \"user\",\n content: mapContent(message.content),\n })\n }\n\n return newMessages\n}\n\nfunction handleAssistantMessage(\n message: ClaudeAssistantMessage,\n toolNameMapper: ClaudeToolNameMapper,\n): Array<Message> {\n if (!Array.isArray(message.content)) {\n return [{ role: \"assistant\", content: mapContent(message.content) }]\n }\n\n const toolUseBlocks = message.content.filter(\n (block): block is ClaudeToolUseBlock => block.type === \"tool_use\",\n )\n const textBlocks = message.content.filter(\n (block): block is ClaudeTextBlock => block.type === \"text\",\n )\n const thinkingBlocks = message.content.filter(\n (block): block is ClaudeThinkingBlock => block.type === \"thinking\",\n )\n\n const allTextContent = [\n ...textBlocks.map((b) => b.text),\n ...thinkingBlocks.map((b) => b.thinking),\n ].join(\"\\n\\n\")\n\n // Assistant tool_use blocks bridge to OpenAI tool_calls; plain text and\n // thinking content stay on the assistant message as context for those calls.\n return toolUseBlocks.length > 0\n ? [\n {\n role: \"assistant\",\n content: allTextContent || null,\n tool_calls: toolUseBlocks.map((toolUse) => ({\n id: toolUse.id,\n type: \"function\",\n function: {\n name: toolNameMapper.toOpenAI(toolUse.name),\n arguments: JSON.stringify(toolUse.input),\n },\n })),\n },\n ]\n : [{ role: \"assistant\", content: mapContent(message.content) }]\n}\n\nconst continuePrefillPrompt =\n \"Continue the assistant response from the previous assistant message.\"\n\nconst normalizeFinalAssistantPrefill = (\n messages: Array<Message>,\n): Array<Message> => {\n let lastAssistantIndex = -1\n for (let index = messages.length - 1; index >= 0; index--) {\n if (messages[index]?.role === \"assistant\") {\n lastAssistantIndex = index\n break\n }\n }\n if (lastAssistantIndex < 0) {\n return messages\n }\n if (lastAssistantIndex !== messages.length - 1) {\n return messages\n }\n\n const lastAssistant = messages[lastAssistantIndex]\n if (typeof lastAssistant.content !== \"string\") {\n return messages.slice(0, -1)\n }\n\n const trimmedContent = lastAssistant.content.trimEnd()\n // Claude Messages allows a final assistant message as a prefill prefix.\n // Copilot rejects that shape, so keep the prefix as context and append a\n // minimal user turn that asks upstream to continue from it.\n const nextMessages = [...messages]\n if (trimmedContent) {\n nextMessages[lastAssistantIndex] = {\n ...lastAssistant,\n content: trimmedContent,\n }\n nextMessages.push({ role: \"user\", content: continuePrefillPrompt })\n } else {\n nextMessages.pop()\n }\n return nextMessages\n}\n\nfunction mapContent(\n content:\n | string\n | Array<ClaudeUserContentBlock | ClaudeAssistantContentBlock>,\n): string | Array<ContentPart> | null {\n if (typeof content === \"string\") {\n return content\n }\n\n if (!Array.isArray(content)) {\n return null\n }\n\n const hasImage = content.some((block) => block.type === \"image\")\n if (!hasImage) {\n // Without images the OpenAI-compatible chat surface accepts plain strings;\n // image messages must use content parts instead.\n return content\n .filter(\n (block): block is ClaudeTextBlock | ClaudeThinkingBlock =>\n block.type === \"text\" || block.type === \"thinking\",\n )\n .map((block) => (block.type === \"text\" ? block.text : block.thinking))\n .join(\"\\n\\n\")\n }\n\n const contentParts: Array<ContentPart> = []\n for (const block of content) {\n switch (block.type) {\n case \"text\": {\n contentParts.push({ type: \"text\", text: block.text })\n break\n }\n case \"thinking\": {\n contentParts.push({ type: \"text\", text: block.thinking })\n break\n }\n case \"image\": {\n contentParts.push({\n type: \"image_url\",\n image_url: {\n url: `data:${block.source.media_type};base64,${block.source.data}`,\n },\n })\n break\n }\n }\n }\n\n return contentParts\n}\n\nfunction translateClaudeToolsToOpenAI(\n claudeTools: Array<ClaudeTool> | undefined,\n toolNameMapper: ClaudeToolNameMapper,\n): Array<Tool> | undefined {\n if (!claudeTools || claudeTools.length === 0) {\n return undefined\n }\n\n const tools = claudeTools.flatMap((tool) => {\n if (!tool.input_schema) {\n return []\n }\n\n return [{\n type: \"function\" as const,\n function: {\n name: toolNameMapper.toOpenAI(tool.name),\n description: tool.description,\n parameters: tool.input_schema,\n },\n }]\n })\n\n return tools.length > 0 ? tools : undefined\n}\n\nfunction translateClaudeToolChoiceToOpenAI(\n claudeToolChoice: ClaudeMessagesPayload[\"tool_choice\"],\n toolNameMapper: ClaudeToolNameMapper,\n): ChatCompletionsPayload[\"tool_choice\"] {\n if (!claudeToolChoice) {\n return undefined\n }\n\n switch (claudeToolChoice.type) {\n case \"auto\": {\n return \"auto\"\n }\n case \"any\": {\n return \"required\"\n }\n case \"tool\": {\n if (claudeToolChoice.name) {\n return {\n type: \"function\",\n function: { name: toolNameMapper.toOpenAI(claudeToolChoice.name) },\n }\n }\n return undefined\n }\n case \"none\": {\n return \"none\"\n }\n default: {\n return undefined\n }\n }\n}\n\nexport function translateToClaude(\n response: ChatCompletionResponse,\n toolNameMapper: ClaudeToolNameMapper = createClaudeToolNameMapper(\n undefined,\n ),\n): ClaudeResponse {\n const allThinkingBlocks: Array<ClaudeThinkingBlock> = []\n const allTextBlocks: Array<ClaudeTextBlock> = []\n const allToolUseBlocks: Array<ClaudeToolUseBlock> = []\n let stopReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null = null\n\n stopReason = response.choices[0]?.finish_reason ?? stopReason\n\n // Multiple choices can mix text and tool calls. Claude has one stop_reason,\n // so prefer tool_calls when present while preserving a normal stop result.\n for (const choice of response.choices) {\n allThinkingBlocks.push(\n ...getClaudeThinkingBlocks(\n choice.message.reasoning_text ?? choice.message.reasoning_content,\n ),\n )\n allTextBlocks.push(...getClaudeTextBlocks(choice.message.content))\n allToolUseBlocks.push(\n ...getClaudeToolUseBlocks(choice.message.tool_calls, toolNameMapper),\n )\n\n if (choice.finish_reason === \"tool_calls\" || stopReason === \"stop\") {\n stopReason = choice.finish_reason\n }\n }\n\n return {\n id: response.id,\n type: \"message\",\n role: \"assistant\",\n model: response.model,\n content: [...allThinkingBlocks, ...allTextBlocks, ...allToolUseBlocks],\n stop_reason: mapOpenAIStopReasonToClaude(stopReason),\n stop_sequence: null,\n usage: {\n input_tokens:\n (response.usage?.prompt_tokens ?? 0)\n - (response.usage?.prompt_tokens_details?.cached_tokens ?? 0),\n output_tokens: response.usage?.completion_tokens ?? 0,\n ...(response.usage?.prompt_tokens_details?.cached_tokens !== undefined && {\n cache_read_input_tokens: response.usage.prompt_tokens_details.cached_tokens,\n }),\n },\n }\n}\n\nfunction getClaudeThinkingBlocks(\n reasoningContent: string | null | undefined,\n): Array<ClaudeThinkingBlock> {\n if (!reasoningContent) {\n return []\n }\n\n return [{ type: \"thinking\", thinking: reasoningContent }]\n}\n\nfunction getClaudeTextBlocks(\n messageContent: Message[\"content\"],\n): Array<ClaudeTextBlock> {\n if (typeof messageContent === \"string\") {\n return [{ type: \"text\", text: messageContent }]\n }\n\n if (Array.isArray(messageContent)) {\n return messageContent\n .filter((part): part is TextPart => part.type === \"text\")\n .map((part) => ({ type: \"text\", text: part.text }))\n }\n\n return []\n}\n\nfunction getClaudeToolUseBlocks(\n toolCalls: Array<ToolCall> | undefined,\n toolNameMapper: ClaudeToolNameMapper,\n): Array<ClaudeToolUseBlock> {\n if (!toolCalls) {\n return []\n }\n\n return toolCalls.map((toolCall) => ({\n type: \"tool_use\",\n id: toolCall.id,\n name: toolNameMapper.toClaude(toolCall.function.name),\n input: safeJsonParse(toolCall.function.arguments),\n }))\n}\n\nfunction safeJsonParse(input: string): Record<string, unknown> {\n try {\n return JSON.parse(input) as Record<string, unknown>\n } catch {\n return { raw: input }\n }\n}\n","// Stateful streaming adapter from Copilot chat completion chunks to Claude SSE events.\nimport type {\n ClaudeStreamEventData,\n ClaudeStreamState,\n} from \"~/claude/types\"\nimport {\n createClaudeToolNameMapper,\n type ClaudeToolNameMapper,\n} from \"~/claude/tool-names\"\nimport { mapOpenAIStopReasonToClaude } from \"~/claude/utils\"\nimport type { ChatCompletionChunk } from \"~/copilot/types\"\n\nfunction isToolBlockOpen(state: ClaudeStreamState): boolean {\n if (!state.contentBlockOpen) {\n return false\n }\n\n return Object.values(state.toolCalls).some(\n (tc) => tc.claudeBlockIndex === state.contentBlockIndex,\n )\n}\n\nconst closeOpenContentBlock = (\n events: Array<ClaudeStreamEventData>,\n state: ClaudeStreamState,\n): void => {\n if (!state.contentBlockOpen) {\n return\n }\n\n events.push({\n type: \"content_block_stop\",\n index: state.contentBlockIndex,\n })\n state.contentBlockIndex++\n state.contentBlockOpen = false\n state.thinkingBlockOpen = false\n}\n\nexport function translateChunkToClaudeEvents(\n chunk: ChatCompletionChunk,\n state: ClaudeStreamState,\n toolNameMapper: ClaudeToolNameMapper = createClaudeToolNameMapper(\n undefined,\n ),\n): Array<ClaudeStreamEventData> {\n // This is a stateful adapter from Copilot's OpenAI-style deltas to Claude's\n // stricter SSE protocol. Claude requires every thinking/text/tool block to\n // be explicitly opened, filled with deltas, and then closed in order.\n const events: Array<ClaudeStreamEventData> = []\n\n if (chunk.choices.length === 0) {\n return events\n }\n\n const choice = chunk.choices[0]\n const { delta } = choice\n const reasoningContent = delta.reasoning_text ?? delta.reasoning_content\n\n if (!state.messageStartSent) {\n events.push({\n type: \"message_start\",\n message: {\n id: chunk.id,\n type: \"message\",\n role: \"assistant\",\n content: [],\n model: chunk.model,\n stop_reason: null,\n stop_sequence: null,\n usage: {\n input_tokens:\n (chunk.usage?.prompt_tokens ?? 0)\n - (chunk.usage?.prompt_tokens_details?.cached_tokens ?? 0),\n output_tokens: 0,\n ...(chunk.usage?.prompt_tokens_details?.cached_tokens !== undefined && {\n cache_read_input_tokens: chunk.usage.prompt_tokens_details.cached_tokens,\n }),\n },\n },\n })\n state.messageStartSent = true\n }\n\n if (reasoningContent) {\n // Claude allows only one open content block at a time. Switching from text\n // or tool output into thinking must close the previous block first.\n if (state.contentBlockOpen && !state.thinkingBlockOpen) {\n closeOpenContentBlock(events, state)\n }\n\n if (!state.contentBlockOpen) {\n events.push({\n type: \"content_block_start\",\n index: state.contentBlockIndex,\n content_block: {\n type: \"thinking\",\n thinking: \"\",\n },\n })\n state.contentBlockOpen = true\n state.thinkingBlockOpen = true\n }\n\n events.push({\n type: \"content_block_delta\",\n index: state.contentBlockIndex,\n delta: {\n type: \"thinking_delta\",\n thinking: reasoningContent,\n },\n })\n }\n\n if (delta.content) {\n // Text deltas cannot be appended to an open thinking or tool_use block, so\n // close whichever block is active before starting/resuming text output.\n if (state.thinkingBlockOpen || isToolBlockOpen(state)) {\n closeOpenContentBlock(events, state)\n }\n\n if (!state.contentBlockOpen) {\n events.push({\n type: \"content_block_start\",\n index: state.contentBlockIndex,\n content_block: {\n type: \"text\",\n text: \"\",\n },\n })\n state.contentBlockOpen = true\n }\n\n events.push({\n type: \"content_block_delta\",\n index: state.contentBlockIndex,\n delta: {\n type: \"text_delta\",\n text: delta.content,\n },\n })\n }\n\n if (delta.tool_calls) {\n for (const toolCall of delta.tool_calls) {\n if (toolCall.id && toolCall.function?.name) {\n // The first tool delta opens a Claude tool_use block; later argument\n // deltas are routed back to this block by Copilot's tool call index.\n if (state.contentBlockOpen) {\n closeOpenContentBlock(events, state)\n }\n\n const toolName = toolNameMapper.toClaude(toolCall.function.name)\n const claudeBlockIndex = state.contentBlockIndex\n state.toolCalls[toolCall.index] = {\n id: toolCall.id,\n name: toolName,\n claudeBlockIndex,\n }\n\n events.push({\n type: \"content_block_start\",\n index: claudeBlockIndex,\n content_block: {\n type: \"tool_use\",\n id: toolCall.id,\n name: toolName,\n input: {},\n },\n })\n state.contentBlockOpen = true\n }\n\n if (toolCall.function?.arguments) {\n const toolCallInfo = state.toolCalls[toolCall.index]\n if (toolCallInfo) {\n events.push({\n type: \"content_block_delta\",\n index: toolCallInfo.claudeBlockIndex,\n delta: {\n type: \"input_json_delta\",\n partial_json: toolCall.function.arguments,\n },\n })\n }\n }\n }\n }\n\n if (choice.finish_reason) {\n if (state.contentBlockOpen) {\n closeOpenContentBlock(events, state)\n }\n\n events.push(\n {\n type: \"message_delta\",\n delta: {\n stop_reason: mapOpenAIStopReasonToClaude(choice.finish_reason),\n stop_sequence: null,\n },\n usage: {\n input_tokens:\n (chunk.usage?.prompt_tokens ?? 0)\n - (chunk.usage?.prompt_tokens_details?.cached_tokens ?? 0),\n output_tokens: chunk.usage?.completion_tokens ?? 0,\n ...(chunk.usage?.prompt_tokens_details?.cached_tokens !== undefined && {\n cache_read_input_tokens: chunk.usage.prompt_tokens_details.cached_tokens,\n }),\n },\n },\n {\n type: \"message_stop\",\n },\n )\n }\n\n return events\n}\n\nexport function translateErrorToClaudeErrorEvent(): ClaudeStreamEventData {\n return {\n type: \"error\",\n error: {\n type: \"api_error\",\n message: \"An unexpected error occurred during streaming.\",\n },\n }\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type {\n ClaudeAssistantContentBlock,\n ClaudeMessage,\n ClaudeMessagesPayload,\n ClaudeResponse,\n ClaudeTextBlock,\n ClaudeTool,\n ClaudeWebSearchResultBlock,\n} from \"~/claude/types\"\nimport type { ClaudeToolNameMapper } from \"~/claude/tool-names\"\nimport {\n createCopilotRequestSignal,\n fetchCopilot,\n getCopilotProviderContext,\n readCopilotJson,\n readCopilotText,\n} from \"~/copilot/client\"\nimport type {\n ChatCompletionResponse,\n ChatCompletionsPayload,\n Message,\n ToolCall,\n} from \"~/copilot/types\"\nimport type { ProxyConfig } from \"~/lib/config\"\nimport { getModelRouting } from \"~/lib/models\"\n\nconst anthropicWebSearchToolPattern = /^web_search_\\d{8}$/\nconst claudeCodeWebSearchToolName = \"WebSearch\"\nconst searchResultLimit = 8\n\nconst webSearchInputSchema = {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description: \"The web search query.\",\n },\n },\n required: [\"query\"],\n additionalProperties: false,\n}\n\ninterface ResponsesWebSearchResponse {\n id: string\n created_at: number\n model: string\n output?: Array<ResponsesOutputItem>\n usage?: {\n input_tokens?: number\n output_tokens?: number\n }\n}\n\ntype ResponsesOutputItem =\n | {\n type: \"web_search_call\"\n action?: {\n query?: string\n queries?: Array<string>\n }\n }\n | {\n type: \"message\"\n content?: Array<{\n type?: string\n text?: string\n }>\n }\n | Record<string, unknown>\n\nexport interface WebSearchResult {\n title: string\n url: string\n}\n\nexport interface WebSearchExecutionResult {\n id: string\n inputTokens: number\n model: string\n outputTokens: number\n query: string\n results: Array<WebSearchResult>\n text: string\n}\n\nexport interface ClaudeWebSearchToolCall {\n query: string\n toolCall: ToolCall\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value)\n\nconst isAnthropicNativeWebSearchTool = (tool: ClaudeTool): boolean =>\n tool.name === \"web_search\"\n && typeof tool.type === \"string\"\n && anthropicWebSearchToolPattern.test(tool.type)\n\nconst isClaudeCodeWebSearchTool = (tool: ClaudeTool): boolean =>\n tool.name === claudeCodeWebSearchToolName\n\nexport const isClaudeWebSearchTool = (tool: ClaudeTool): boolean =>\n isAnthropicNativeWebSearchTool(tool) || isClaudeCodeWebSearchTool(tool)\n\nexport const hasClaudeWebSearch = (payload: ClaudeMessagesPayload): boolean =>\n payload.tools?.some(isClaudeWebSearchTool) ?? false\n\nconst isClaudeWebSearchToolName = (name: string): boolean =>\n name === \"web_search\" || name === claudeCodeWebSearchToolName\n\nexport const getWebSearchBackendModel = (config: ProxyConfig): string =>\n config.webSearchBackend?.trim() || getModelRouting().gptModel\n\nexport const prepareClaudeWebSearchDecisionPayload = (\n payload: ClaudeMessagesPayload,\n): ClaudeMessagesPayload => {\n if (!hasClaudeWebSearch(payload)) {\n return payload\n }\n\n return {\n ...payload,\n tools: payload.tools?.map((tool) =>\n isClaudeWebSearchTool(tool) ?\n {\n ...tool,\n input_schema: tool.input_schema ?? webSearchInputSchema,\n }\n : tool,\n ),\n }\n}\n\nconst textFromMessageContent = (content: ClaudeMessage[\"content\"]): string => {\n if (typeof content === \"string\") {\n return content\n }\n\n return content\n .flatMap((block) => {\n if (block.type === \"text\") return [block.text]\n if (block.type === \"tool_result\") return [block.content]\n return []\n })\n .join(\"\\n\\n\")\n}\n\nconst getRequestedQuery = (payload: ClaudeMessagesPayload): string => {\n const lastUserMessage = [...payload.messages]\n .reverse()\n .find((message) => message.role === \"user\")\n const rawText = lastUserMessage ? textFromMessageContent(lastUserMessage.content) : \"\"\n const cleaned = rawText\n .replace(/<system-reminder>[\\s\\S]*?<\\/system-reminder>/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim()\n const searchMatch = cleaned.match(/\\bsearch(?:\\s+the\\s+web)?(?:\\s+for)?\\s+(.+)$/i)\n return searchMatch?.[1]?.trim() || cleaned || \"web search\"\n}\n\nconst getQueryFromToolArguments = (value: string): string | undefined => {\n const trimmed = value.trim()\n if (!trimmed) {\n return undefined\n }\n\n try {\n const parsed = JSON.parse(trimmed) as unknown\n if (\n isRecord(parsed)\n && typeof parsed.query === \"string\"\n && parsed.query.trim()\n ) {\n return parsed.query.trim()\n }\n } catch {\n return trimmed\n }\n\n return trimmed\n}\n\nexport const getClaudeWebSearchToolCallFromChatResponse = (\n response: ChatCompletionResponse,\n toolNameMapper: ClaudeToolNameMapper,\n): ClaudeWebSearchToolCall | undefined => {\n const toolCall = response.choices\n .flatMap((choice) => choice.message.tool_calls ?? [])\n .find((call) =>\n isClaudeWebSearchToolName(\n toolNameMapper.toClaude(call.function.name),\n ),\n )\n\n if (!toolCall) {\n return undefined\n }\n\n const query = getQueryFromToolArguments(toolCall.function.arguments)\n return query ? { query, toolCall } : undefined\n}\n\nconst buildSearchInput = (\n payload: ClaudeMessagesPayload,\n requestedQuery: string,\n): string => {\n const systemText =\n typeof payload.system === \"string\" ? payload.system\n : Array.isArray(payload.system) ?\n payload.system.map((block: ClaudeTextBlock) => block.text).join(\"\\n\\n\")\n : \"\"\n const messages = payload.messages\n .map((message) => `${message.role}: ${textFromMessageContent(message.content)}`)\n .join(\"\\n\\n\")\n\n return [\n \"You are fulfilling an Anthropic web_search server tool request for Claude Code.\",\n \"Search the web using the provided web_search_preview tool.\",\n `Requested web search query: ${requestedQuery}`,\n \"Return useful search results as plain text lines in this exact shape:\",\n \"1. Title - https://example.com/page\",\n \"Include only real source URLs from the search results.\",\n systemText ? `System context:\\n${systemText}` : \"\",\n `Conversation:\\n${messages}`,\n ]\n .filter(Boolean)\n .join(\"\\n\\n\")\n}\n\nconst buildWebSearchRequestPayload = (\n payload: ClaudeMessagesPayload,\n requestedQuery: string,\n model: string,\n) => ({\n model,\n input: buildSearchInput(payload, requestedQuery),\n tools: [{ type: \"web_search_preview\" }],\n max_output_tokens: Math.max(256, Math.min(payload.max_tokens ?? 1024, 1200)),\n temperature: payload.temperature,\n top_p: payload.top_p,\n})\n\nconst getSearchQuery = (\n response: ResponsesWebSearchResponse,\n requestedQuery: string,\n): string => {\n for (const item of response.output ?? []) {\n if (item.type !== \"web_search_call\") continue\n const action = isRecord(item.action) ? item.action : undefined\n const queries = Array.isArray(action?.queries) ? action.queries : []\n const query =\n typeof action?.query === \"string\" ? action.query\n : typeof queries[0] === \"string\" ? queries[0]\n : undefined\n if (query) return query\n }\n\n return requestedQuery.slice(0, 200)\n}\n\nconst getResponseText = (response: ResponsesWebSearchResponse): string =>\n (response.output ?? [])\n .flatMap((item) => {\n if (item.type !== \"message\") return []\n const content = Array.isArray(item.content) ? item.content : []\n return content.flatMap((part) =>\n isRecord(part)\n && part.type === \"output_text\"\n && typeof part.text === \"string\" ?\n [part.text]\n : [],\n )\n })\n .join(\"\\n\")\n .trim()\n\nconst cleanTitle = (line: string, url: string): string => {\n const beforeUrl = line.slice(0, line.indexOf(url))\n const cleaned = beforeUrl\n .replace(/^\\s*(?:[-*]|\\d+[.)])\\s*/, \"\")\n .replace(/\\s*(?:[-:|])\\s*$/, \"\")\n .trim()\n return cleaned || new URL(url).hostname\n}\n\nconst parseSearchResults = (text: string): Array<WebSearchResult> => {\n const results: Array<WebSearchResult> = []\n const seenUrls = new Set<string>()\n\n for (const line of text.split(/\\r?\\n/)) {\n const markdownMatch = line.match(/\\[([^\\]]+)]\\((https?:\\/\\/[^)\\s]+)\\)/)\n const url = markdownMatch?.[2] ?? line.match(/https?:\\/\\/[^\\s)]+/)?.[0]\n if (!url || seenUrls.has(url)) {\n continue\n }\n\n seenUrls.add(url)\n results.push({\n title: markdownMatch?.[1]?.trim() || cleanTitle(line, url),\n url,\n })\n\n if (results.length >= searchResultLimit) {\n break\n }\n }\n\n return results\n}\n\nconst createFailedSearchExecution = (\n payload: ClaudeMessagesPayload,\n requestedQuery: string,\n model: string,\n message: string,\n): WebSearchExecutionResult => ({\n id: `msg_${randomUUID().replaceAll(\"-\", \"\")}`,\n inputTokens: 0,\n model,\n outputTokens: 0,\n query: requestedQuery || getRequestedQuery(payload),\n results: [],\n text: message,\n})\n\nexport const createClaudeWebSearchExecution = async (\n config: ProxyConfig,\n payload: ClaudeMessagesPayload,\n requestedQuery: string,\n options: { requestId?: string; signal?: AbortSignal; timeoutMs?: number } = {},\n): Promise<WebSearchExecutionResult> => {\n const backendModel = getWebSearchBackendModel(config)\n const signal = createCopilotRequestSignal(options.signal, options.timeoutMs)\n const response = await fetchCopilot(\n getCopilotProviderContext(config),\n \"/responses\",\n {\n method: \"POST\",\n headers: {\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(\n buildWebSearchRequestPayload(payload, requestedQuery, backendModel),\n ),\n },\n {\n initiator: \"agent\",\n requestId: options.requestId,\n signal,\n timeoutMs: options.timeoutMs,\n },\n )\n\n if (!response.ok) {\n const detail = await readCopilotText(\n response,\n signal,\n options.timeoutMs,\n ).catch(() => \"\")\n return createFailedSearchExecution(\n payload,\n requestedQuery,\n backendModel,\n [\n `Copilot web search is not available for model ${backendModel}.`,\n detail ? `Upstream response: ${detail}` : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n )\n }\n\n const upstream = await readCopilotJson<ResponsesWebSearchResponse>(\n response,\n signal,\n options.timeoutMs,\n )\n const text = getResponseText(upstream)\n const query = getSearchQuery(upstream, requestedQuery)\n const results = parseSearchResults(text)\n\n if (results.length === 0 && !text.trim()) {\n return createFailedSearchExecution(\n payload,\n requestedQuery,\n upstream.model,\n \"Copilot web search did not return search results.\",\n )\n }\n\n return {\n id: upstream.id,\n inputTokens: upstream.usage?.input_tokens ?? 0,\n model: upstream.model,\n outputTokens: upstream.usage?.output_tokens ?? 0,\n query,\n results,\n text,\n }\n}\n\nconst buildSearchResultBlock = (\n toolUseId: string,\n results: Array<WebSearchResult>,\n): ClaudeWebSearchResultBlock => ({\n type: \"web_search_tool_result\",\n tool_use_id: toolUseId,\n content:\n results.length > 0 ?\n results.map((result) => ({\n type: \"web_search_result\" as const,\n title: result.title,\n url: result.url,\n encrypted_content: \"\",\n page_age: null,\n }))\n : {\n type: \"web_search_tool_result_error\",\n error_code: \"unavailable\",\n },\n})\n\nexport const createClaudeWebSearchResponse = (\n search: WebSearchExecutionResult,\n): ClaudeResponse => {\n const toolUseId = `srvtoolu_${randomUUID().replaceAll(\"-\", \"\")}`\n const content: Array<ClaudeAssistantContentBlock> = [\n {\n type: \"server_tool_use\",\n id: toolUseId,\n name: \"web_search\",\n input: { query: search.query },\n },\n buildSearchResultBlock(toolUseId, search.results),\n ]\n\n if (search.text) {\n content.push({ type: \"text\", text: search.text })\n }\n\n return {\n id: search.id,\n type: \"message\",\n role: \"assistant\",\n content,\n model: search.model,\n stop_reason: \"end_turn\",\n stop_sequence: null,\n usage: {\n input_tokens: search.inputTokens,\n output_tokens: search.outputTokens,\n server_tool_use: { web_search_requests: 1 },\n },\n }\n}\n\nconst getWebSearchResultText = (search: WebSearchExecutionResult): string => {\n if (search.results.length === 0) {\n return search.text || \"Web search did not return search results.\"\n }\n\n return [\n `Web search results for query: \"${search.query}\"`,\n \"\",\n ...search.results.map((result, index) =>\n `${index + 1}. ${result.title} - ${result.url}`,\n ),\n ].join(\"\\n\")\n}\n\nconst createWebSearchResultContextMessage = (\n search: WebSearchExecutionResult,\n): Message => ({\n role: \"system\",\n content: [\n \"Trusted bridge retrieval context: the assistant selected web_search, and copilot-relay executed it.\",\n \"Use this context for the final answer. Do not describe it as user-provided or injected. Do not call web_search again.\",\n \"If the user requested a specific output format, answer using only matching information from this context.\",\n \"If the user asked for a URL only, output only that URL with no surrounding text.\",\n \"\",\n `Query: ${search.query}`,\n \"\",\n getWebSearchResultText(search),\n ].join(\"\\n\"),\n})\n\nexport const createFinalWebSearchPayload = (\n payload: ChatCompletionsPayload,\n search: WebSearchExecutionResult,\n): ChatCompletionsPayload => {\n const messages = payload.messages.flatMap<Message>((message) => {\n if (message.role === \"tool\") {\n return [\n {\n role: \"developer\",\n content: [\n \"Prior local tool result from the conversation:\",\n String(message.content ?? \"\"),\n ].join(\"\\n\"),\n },\n ]\n }\n\n if (message.tool_calls && message.tool_calls.length > 0) {\n return message.content ? [{ ...message, tool_calls: undefined }] : []\n }\n\n return [message]\n })\n\n return {\n ...payload,\n stream: false,\n tools: undefined,\n tool_choice: undefined,\n messages: [\n ...messages,\n createWebSearchResultContextMessage(search),\n ],\n }\n}\n\nexport const mergeWebSearchAndFinalResponse = (\n searchResponse: ClaudeResponse,\n finalResponse: ClaudeResponse,\n): ClaudeResponse => ({\n ...finalResponse,\n content: [...searchResponse.content.slice(0, 2), ...finalResponse.content],\n usage: {\n ...finalResponse.usage,\n input_tokens:\n searchResponse.usage.input_tokens + finalResponse.usage.input_tokens,\n output_tokens:\n searchResponse.usage.output_tokens + finalResponse.usage.output_tokens,\n server_tool_use: { web_search_requests: 1 },\n },\n})\n","// Token estimator for Claude Code's /v1/messages/count_tokens endpoint.\nimport type {\n ChatCompletionsPayload,\n ContentPart,\n Message,\n Tool,\n ToolCall,\n} from \"~/copilot/types\"\n\nexport interface TokenizerModel {\n capabilities: {\n tokenizer: string\n }\n id: string\n}\n\nconst encodingMap = {\n o200k_base: () => import(\"gpt-tokenizer/encoding/o200k_base\"),\n cl100k_base: () => import(\"gpt-tokenizer/encoding/cl100k_base\"),\n p50k_base: () => import(\"gpt-tokenizer/encoding/p50k_base\"),\n p50k_edit: () => import(\"gpt-tokenizer/encoding/p50k_edit\"),\n r50k_base: () => import(\"gpt-tokenizer/encoding/r50k_base\"),\n} as const\n\ntype SupportedEncoding = keyof typeof encodingMap\n\ninterface Encoder {\n encode: (text: string) => Array<number>\n}\n\nconst encodingCache = new Map<string, Encoder>()\n\nconst calculateToolCallsTokens = (\n toolCalls: Array<ToolCall>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = 0\n for (const toolCall of toolCalls) {\n tokens += constants.funcInit\n tokens += encoder.encode(JSON.stringify(toolCall)).length\n }\n tokens += constants.funcEnd\n return tokens\n}\n\nconst calculateContentPartsTokens = (\n contentParts: Array<ContentPart>,\n encoder: Encoder,\n): number => {\n let tokens = 0\n for (const part of contentParts) {\n if (part.type === \"image_url\") {\n // Claude Code needs a fast local estimate, not exact upstream billing.\n // Use a fixed image overhead plus URL token count to avoid severe\n // under-counting when screenshots are present.\n tokens += encoder.encode(part.image_url.url).length + 85\n } else if (part.text) {\n tokens += encoder.encode(part.text).length\n }\n }\n return tokens\n}\n\nconst calculateMessageTokens = (\n message: Message,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n // Mirrors OpenAI chat formatting heuristics closely enough for UI budgeting;\n // /count_tokens is advisory and should not call real Copilot services.\n const tokensPerMessage = 3\n const tokensPerName = 1\n let tokens = tokensPerMessage\n for (const [key, value] of Object.entries(message)) {\n if (typeof value === \"string\") {\n tokens += encoder.encode(value).length\n }\n if (key === \"name\") tokens += tokensPerName\n if (key === \"tool_calls\") {\n tokens += calculateToolCallsTokens(\n value as Array<ToolCall>,\n encoder,\n constants,\n )\n }\n if (key === \"content\" && Array.isArray(value)) {\n tokens += calculateContentPartsTokens(\n value as Array<ContentPart>,\n encoder,\n )\n }\n }\n return tokens\n}\n\nconst calculateTokens = (\n messages: Array<Message>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (messages.length === 0) return 0\n let numTokens = 0\n for (const message of messages) {\n numTokens += calculateMessageTokens(message, encoder, constants)\n }\n numTokens += 3\n return numTokens\n}\n\nconst getEncodeChatFunction = async (encoding: string): Promise<Encoder> => {\n if (encodingCache.has(encoding)) {\n const cached = encodingCache.get(encoding)\n if (cached) return cached\n }\n\n const supported = encoding as SupportedEncoding\n if (!(supported in encodingMap)) {\n const fallback = (await encodingMap.o200k_base()) as Encoder\n encodingCache.set(encoding, fallback)\n return fallback\n }\n\n const mod = (await encodingMap[supported]()) as Encoder\n encodingCache.set(encoding, mod)\n return mod\n}\n\nexport const getTokenizerFromModel = (model: TokenizerModel): string =>\n model.capabilities.tokenizer || \"o200k_base\"\n\nconst getModelConstants = (model: TokenizerModel) =>\n // Tool/function overhead differs by tokenizer family. Keep these constants\n // small and explicit so count_tokens remains deterministic in tests.\n model.id === \"gpt-3.5-turbo\" || model.id === \"gpt-4\"\n ? {\n funcInit: 10,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n : {\n funcInit: 7,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n\nconst calculateParameterTokens = (\n key: string,\n prop: unknown,\n context: {\n encoder: Encoder\n constants: ReturnType<typeof getModelConstants>\n },\n): number => {\n const { encoder, constants } = context\n let tokens = constants.propKey\n\n if (typeof prop !== \"object\" || prop === null) return tokens\n\n const param = prop as {\n type?: string\n description?: string\n enum?: Array<unknown>\n [key: string]: unknown\n }\n\n const paramName = key\n const paramType = param.type || \"string\"\n let paramDesc = param.description || \"\"\n\n if (param.enum && Array.isArray(param.enum)) {\n tokens += constants.enumInit\n for (const item of param.enum) {\n tokens += constants.enumItem\n tokens += encoder.encode(String(item)).length\n }\n }\n\n if (paramDesc.endsWith(\".\")) paramDesc = paramDesc.slice(0, -1)\n\n const line = `${paramName}:${paramType}:${paramDesc}`\n tokens += encoder.encode(line).length\n\n const excludedKeys = new Set([\"type\", \"description\", \"enum\"])\n for (const propertyName of Object.keys(param)) {\n if (excludedKeys.has(propertyName)) continue\n const propertyValue = param[propertyName]\n const propertyText =\n typeof propertyValue === \"string\" ? propertyValue : JSON.stringify(propertyValue)\n tokens += encoder.encode(`${propertyName}:${propertyText}`).length\n }\n\n return tokens\n}\n\nconst calculateParametersTokens = (\n parameters: unknown,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (!parameters || typeof parameters !== \"object\") return 0\n\n const params = parameters as Record<string, unknown>\n let tokens = 0\n\n for (const [key, value] of Object.entries(params)) {\n if (key === \"properties\") {\n const properties = value as Record<string, unknown>\n if (Object.keys(properties).length > 0) {\n tokens += constants.propInit\n for (const propKey of Object.keys(properties)) {\n tokens += calculateParameterTokens(propKey, properties[propKey], {\n encoder,\n constants,\n })\n }\n }\n } else {\n const paramText =\n typeof value === \"string\" ? value : JSON.stringify(value)\n tokens += encoder.encode(`${key}:${paramText}`).length\n }\n }\n\n return tokens\n}\n\nconst calculateToolTokens = (\n tool: Tool,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = constants.funcInit\n const func = tool.function\n const fName = func.name\n let fDesc = func.description || \"\"\n if (fDesc.endsWith(\".\")) fDesc = fDesc.slice(0, -1)\n tokens += encoder.encode(`${fName}:${fDesc}`).length\n if (typeof func.parameters === \"object\" && func.parameters !== null) {\n tokens += calculateParametersTokens(func.parameters, encoder, constants)\n }\n return tokens\n}\n\nexport const numTokensForTools = (\n tools: Array<Tool>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let funcTokenCount = 0\n for (const tool of tools) {\n funcTokenCount += calculateToolTokens(tool, encoder, constants)\n }\n funcTokenCount += constants.funcEnd\n return funcTokenCount\n}\n\nexport const getTokenCount = async (\n payload: ChatCompletionsPayload,\n model: TokenizerModel,\n): Promise<{ input: number; output: number }> => {\n const tokenizer = getTokenizerFromModel(model)\n const encoder = await getEncodeChatFunction(tokenizer)\n\n const inputMessages = payload.messages.filter((msg) => msg.role !== \"assistant\")\n const outputMessages = payload.messages.filter((msg) => msg.role === \"assistant\")\n\n const constants = getModelConstants(model)\n let inputTokens = calculateTokens(inputMessages, encoder, constants)\n if (payload.tools && payload.tools.length > 0) {\n inputTokens += numTokensForTools(payload.tools, encoder, constants)\n }\n const outputTokens = calculateTokens(outputMessages, encoder, constants)\n\n return { input: inputTokens, output: outputTokens }\n}\n","// Claude Code route surface: /v1/messages, /v1/messages/count_tokens, and /v1/models.\nimport { Hono } from \"hono\"\nimport { streamSSE } from \"hono/streaming\"\n\nimport {\n type ClaudeAssistantContentBlock,\n type ClaudeMessagesPayload,\n type ClaudeResponse,\n type ClaudeStreamEventData,\n type ClaudeStreamState,\n} from \"~/claude/types\"\nimport {\n translateModelName,\n translateToClaude,\n translateToOpenAI,\n} from \"~/claude/translate\"\nimport {\n translateChunkToClaudeEvents,\n translateErrorToClaudeErrorEvent,\n} from \"~/claude/stream\"\nimport {\n createClaudeToolNameMapper,\n getToolNameMapperOptionsForModel,\n} from \"~/claude/tool-names\"\nimport {\n createClaudeWebSearchExecution,\n createClaudeWebSearchResponse,\n createFinalWebSearchPayload,\n getClaudeWebSearchToolCallFromChatResponse,\n hasClaudeWebSearch,\n mergeWebSearchAndFinalResponse,\n prepareClaudeWebSearchDecisionPayload,\n} from \"~/claude/web-search\"\nimport type { ProxyEnv } from \"~/lib/config\"\nimport { HTTPError, ProxyNotImplementedError } from \"~/lib/error\"\nimport { log } from \"~/lib/log\"\nimport { getExposedModelIds } from \"~/lib/models\"\nimport { getTokenCount, type TokenizerModel } from \"~/lib/tokenizer\"\nimport type { ChatCompletionChunk, ChatCompletionResponse } from \"~/copilot/types\"\nimport { createChatCompletions } from \"~/copilot/chat\"\nimport { createCopilotRequestSignal } from \"~/copilot/client\"\n\nexport const claudeRoutes = new Hono<ProxyEnv>()\n\nconst createTokenCountModel = (modelId: string): TokenizerModel => ({\n capabilities: { tokenizer: \"o200k_base\" },\n id: modelId,\n})\n\nconst isNonStreamingResponse = (\n response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse =>\n typeof response === \"object\"\n && response !== null\n && Object.hasOwn(response, \"choices\")\n\nconst getClaudeRequestedThinkEffort = (\n payload: ClaudeMessagesPayload,\n): string => payload.reasoning_effort ?? \"none\"\n\nconst getClaudeRequestedThinking = (\n payload: ClaudeMessagesPayload,\n): string => {\n if (!payload.thinking) {\n return \"none\"\n }\n\n return [\n `type:${payload.thinking.type}`,\n `budget:${payload.thinking.budget_tokens ?? \"none\"}`,\n ].join(\",\")\n}\n\nconst eventsFromClaudeResponse = (\n response: ClaudeResponse,\n): Array<ClaudeStreamEventData> => {\n // When Claude Code asks for streaming but Copilot returned a completed JSON\n // response, synthesize the minimal Claude SSE sequence so client bookkeeping\n // remains identical to a real streaming response.\n const events: Array<ClaudeStreamEventData> = [\n {\n type: \"message_start\",\n message: {\n id: response.id,\n type: response.type,\n role: response.role,\n content: [],\n model: response.model,\n stop_reason: null,\n stop_sequence: null,\n usage: response.usage,\n },\n },\n ]\n\n response.content.forEach((block: ClaudeAssistantContentBlock, index) => {\n events.push({\n type: \"content_block_start\",\n index,\n content_block: block,\n })\n\n if (block.type === \"text\") {\n events.push({\n type: \"content_block_delta\",\n index,\n delta: { type: \"text_delta\", text: block.text },\n })\n } else if (block.type === \"thinking\") {\n events.push({\n type: \"content_block_delta\",\n index,\n delta: { type: \"thinking_delta\", thinking: block.thinking },\n })\n } else if (block.type === \"tool_use\" || block.type === \"server_tool_use\") {\n events.push({\n type: \"content_block_delta\",\n index,\n delta: {\n type: \"input_json_delta\",\n partial_json: JSON.stringify(block.input),\n },\n })\n }\n\n events.push({ type: \"content_block_stop\", index })\n })\n\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: response.stop_reason,\n stop_sequence: response.stop_sequence,\n },\n usage: { output_tokens: response.usage.output_tokens },\n })\n events.push({ type: \"message_stop\" })\n return events\n}\n\ntype ClaudeStreamEventWriter = (\n event: ClaudeStreamEventData,\n) => Promise<void>\n\nconst createQueuedClaudeStreamWriter = (\n write: ClaudeStreamEventWriter,\n): ClaudeStreamEventWriter => {\n let pending = Promise.resolve()\n\n return (event) => {\n pending = pending.then(() => write(event))\n return pending\n }\n}\n\nconst writeClaudeStreamEvents = async (\n events: Array<ClaudeStreamEventData>,\n writeEvent: ClaudeStreamEventWriter,\n): Promise<void> => {\n for (const event of events) {\n await writeEvent(event)\n }\n}\n\nconst handleClaudeMessageRequest = async (\n config: ProxyEnv[\"Variables\"][\"config\"],\n claudePayload: ClaudeMessagesPayload,\n requestSignal: AbortSignal | undefined,\n requestId: string,\n writeEvent?: ClaudeStreamEventWriter,\n): Promise<ClaudeResponse | undefined> => {\n const upstreamModel = translateModelName(claudePayload.model)\n const shouldLetModelDecideWebSearch = hasClaudeWebSearch(claudePayload)\n const decisionPayload =\n shouldLetModelDecideWebSearch ?\n prepareClaudeWebSearchDecisionPayload(claudePayload)\n : claudePayload\n const toolNameMapper = createClaudeToolNameMapper(decisionPayload.tools, {\n ...getToolNameMapperOptionsForModel(upstreamModel),\n })\n const openAIPayload = translateToOpenAI(\n decisionPayload,\n undefined,\n toolNameMapper,\n )\n if (shouldLetModelDecideWebSearch) {\n openAIPayload.stream = false\n }\n const response = await createChatCompletions(config, openAIPayload, {\n client: \"claude\",\n requestedModel: claudePayload.model,\n requestedThinkEffort: getClaudeRequestedThinkEffort(claudePayload),\n requestedThinking: getClaudeRequestedThinking(claudePayload),\n requestId,\n signal: requestSignal,\n timeoutMs: config.upstreamTimeoutMs,\n })\n\n if (isNonStreamingResponse(response)) {\n const webSearchToolCall = shouldLetModelDecideWebSearch ?\n getClaudeWebSearchToolCallFromChatResponse(response, toolNameMapper)\n : undefined\n let claudeResponse: ClaudeResponse\n\n if (webSearchToolCall) {\n const search = await createClaudeWebSearchExecution(\n config,\n claudePayload,\n webSearchToolCall.query,\n { requestId, signal: requestSignal, timeoutMs: config.upstreamTimeoutMs },\n )\n const searchResponse = createClaudeWebSearchResponse(search)\n\n if (search.results.length === 0) {\n claudeResponse = searchResponse\n } else {\n const finalResponse = await createChatCompletions(\n config,\n createFinalWebSearchPayload(openAIPayload, search),\n {\n client: \"claude\",\n requestedModel: claudePayload.model,\n requestedThinkEffort: getClaudeRequestedThinkEffort(claudePayload),\n requestedThinking: getClaudeRequestedThinking(claudePayload),\n requestId,\n signal: requestSignal,\n timeoutMs: config.upstreamTimeoutMs,\n },\n )\n\n if (!isNonStreamingResponse(finalResponse)) {\n throw new HTTPError(\n \"Claude web search final answer request unexpectedly streamed\",\n new Response(\"Claude web search final answer request unexpectedly streamed\", {\n status: 502,\n headers: { \"content-type\": \"text/plain\" },\n }),\n )\n }\n\n claudeResponse = mergeWebSearchAndFinalResponse(\n searchResponse,\n translateToClaude(finalResponse, toolNameMapper),\n )\n }\n } else {\n claudeResponse = translateToClaude(response, toolNameMapper)\n }\n\n if (writeEvent) {\n await writeClaudeStreamEvents(\n eventsFromClaudeResponse(claudeResponse),\n writeEvent,\n )\n return undefined\n }\n\n return claudeResponse\n }\n\n if (shouldLetModelDecideWebSearch) {\n throw new HTTPError(\n \"Claude web search model-decision request unexpectedly streamed\",\n new Response(\"Claude web search model-decision request unexpectedly streamed\", {\n status: 502,\n headers: { \"content-type\": \"text/plain\" },\n }),\n )\n }\n\n if (!writeEvent) {\n throw new HTTPError(\n \"Claude non-streaming request unexpectedly streamed\",\n new Response(\"Claude non-streaming request unexpectedly streamed\", {\n status: 502,\n headers: { \"content-type\": \"text/plain\" },\n }),\n )\n }\n\n const streamState: ClaudeStreamState = {\n messageStartSent: false,\n contentBlockIndex: 0,\n contentBlockOpen: false,\n thinkingBlockOpen: false,\n toolCalls: {},\n }\n\n for await (const rawEvent of response) {\n if (rawEvent.data === \"[DONE]\") {\n break\n }\n if (!rawEvent.data) {\n continue\n }\n\n let chunk: ChatCompletionChunk\n try {\n chunk = JSON.parse(rawEvent.data) as ChatCompletionChunk\n } catch {\n continue\n }\n\n await writeClaudeStreamEvents(\n translateChunkToClaudeEvents(\n chunk,\n streamState,\n toolNameMapper,\n ),\n writeEvent,\n )\n }\n\n return undefined\n}\n\nclaudeRoutes.get(\"/models\", (c) =>\n c.json({\n object: \"list\",\n data: getExposedModelIds().map((id) => ({\n id,\n object: \"model\",\n created: 0,\n owned_by: \"github-copilot\",\n })),\n }),\n)\n\nclaudeRoutes.post(\"/messages\", async (c) => {\n const config = c.get(\"config\")\n const requestId = c.get(\"requestId\")\n const claudePayload = await c.req.json<ClaudeMessagesPayload>()\n const requestSignal = createCopilotRequestSignal(\n c.req.raw.signal,\n config.upstreamTimeoutMs,\n )\n log.debug(\"Full Claude request payload\", { payload: claudePayload })\n\n if (claudePayload.stream) {\n return streamSSE(c, async (stream) => {\n const streamStarted = performance.now()\n const writeEvent = createQueuedClaudeStreamWriter((event) =>\n stream.writeSSE({\n event: event.type,\n data: JSON.stringify(event),\n }),\n )\n\n try {\n await handleClaudeMessageRequest(\n config,\n claudePayload,\n requestSignal,\n requestId,\n writeEvent,\n )\n } catch (error) {\n log.error(\"Error during Claude stream request:\", error)\n const errorEvent = translateErrorToClaudeErrorEvent()\n await writeEvent(errorEvent)\n } finally {\n log.info(\n `request_id=${requestId} stream completed ${Math.round(performance.now() - streamStarted)}ms`,\n )\n }\n })\n }\n\n try {\n return c.json(await handleClaudeMessageRequest(\n config,\n claudePayload,\n requestSignal,\n requestId,\n ))\n } catch (error) {\n if (error instanceof ProxyNotImplementedError) {\n c.set(\"requestErrorMessage\", error.message)\n return c.json(\n { error: { type: error.name, message: error.message } },\n 501,\n )\n }\n\n if (error instanceof HTTPError) {\n const text = await error.response.text().catch(() => \"\")\n c.set(\"requestErrorMessage\", error.detail ?? text.slice(0, 240))\n return new Response(text, {\n status: error.response.status,\n headers: {\n \"content-type\":\n error.response.headers.get(\"content-type\") ?? \"application/json\",\n },\n })\n }\n\n throw error\n }\n})\n\nclaudeRoutes.post(\"/messages/count_tokens\", async (c) => {\n try {\n const claudeBeta = c.req.header(\"claude-beta\")\n const claudePayload = await c.req.json<ClaudeMessagesPayload>()\n const openAIPayload = translateToOpenAI(claudePayload)\n const exposedModels = getExposedModelIds()\n const selectedModel = createTokenCountModel(\n openAIPayload.model === exposedModels[1] ? exposedModels[1] : exposedModels[0],\n )\n\n const tokenCount = await getTokenCount(openAIPayload, selectedModel)\n const effectiveModelId = selectedModel.id\n\n // Claude Code already accounts for MCP tool payloads differently. For\n // non-MCP local tools, add a small Claude-family overhead to avoid\n // under-reporting context use in the UI.\n if (claudePayload.tools && claudePayload.tools.length > 0) {\n let mcpToolExist = false\n if (claudeBeta?.startsWith(\"claude-code\")) {\n mcpToolExist = claudePayload.tools.some((tool) =>\n tool.name.startsWith(\"mcp__\"),\n )\n }\n if (!mcpToolExist && effectiveModelId.startsWith(\"claude\")) {\n tokenCount.input += 346\n }\n }\n\n const multiplier = effectiveModelId.startsWith(\"claude\") ? 1.15 : 1\n const finalTokenCount = Math.round(\n (tokenCount.input + tokenCount.output) * multiplier,\n )\n\n return c.json({ input_tokens: Math.max(1, finalTokenCount) })\n } catch (error) {\n log.error(\"Error counting tokens:\", error)\n return c.json({ input_tokens: 1 })\n }\n})\n","// HTTP server assembly: exposes only Claude Code-compatible public routes.\nimport { randomUUID } from \"node:crypto\"\n\nimport { createAdaptorServer, type ServerType } from \"@hono/node-server\"\nimport { Hono } from \"hono\"\nimport { cors } from \"hono/cors\"\n\nimport type { ProxyConfig, ProxyEnv } from \"~/lib/config\"\nimport { log } from \"~/lib/log\"\nimport { claudeRoutes } from \"~/routes/claude\"\n\nconst loggedRequestHeaders = [\n \"anthropic-beta\",\n \"anthropic-version\",\n \"claude-beta\",\n \"content-type\",\n]\n\nconst readRequestPayloadForLog = async (request: Request): Promise<unknown> => {\n const text = await request.clone().text().catch(() => \"\")\n if (!text) {\n return undefined\n }\n\n try {\n return JSON.parse(text) as unknown\n } catch {\n return text\n }\n}\n\nconst getLoggedHeaders = (request: Request): Record<string, string> =>\n Object.fromEntries(\n loggedRequestHeaders.flatMap((name) => {\n const value = request.headers.get(name)\n return value ? [[name, value]] : []\n }),\n )\n\nconst formatStatusLog = (\n requestId: string,\n method: string,\n path: string,\n status: number,\n ms: number,\n errorMessage: string | undefined,\n): string => {\n const base = `request_id=${requestId} ${method} ${path} -> ${status} ${ms}ms`\n return status >= 400 && errorMessage ? `${base} error=${JSON.stringify(errorMessage)}` : base\n}\n\nexport const createServer = (config: ProxyConfig) => {\n const app = new Hono<ProxyEnv>()\n\n app.use(\"*\", async (c, next) => {\n const requestId = randomUUID()\n c.set(\"config\", config)\n c.set(\"requestId\", requestId)\n c.header(\"x-copilot-relay-request-id\", requestId)\n log.info(`request_id=${requestId} request received method=${c.req.method} path=${c.req.path}`)\n\n const started = performance.now()\n try {\n await next()\n } finally {\n const ms = Math.round(performance.now() - started)\n // Emit exactly one info-level request summary even when downstream route\n // handling throws; deeper diagnostics belong to debug/error logs.\n log.info(formatStatusLog(\n requestId,\n c.req.method,\n c.req.path,\n c.res.status,\n ms,\n c.get(\"requestErrorMessage\"),\n ))\n }\n })\n app.use(\"*\", cors())\n\n app.onError((error, c) => {\n c.set(\"requestErrorMessage\", error.message)\n log.error(\"Unhandled Claude API request error\", {\n method: c.req.method,\n path: c.req.path,\n requestId: c.get(\"requestId\"),\n error,\n })\n return c.json({ error: { message: \"Internal server error\" } }, 500)\n })\n\n app.get(\"/\", (c) =>\n c.json({\n name: \"copilot-relay\",\n status: \"ok\",\n }),\n )\n\n app.get(\"/healthz\", (c) => c.json({ ok: true }))\n app.route(\"/v1\", claudeRoutes)\n app.notFound(async (c) => {\n const message = \"Unsupported Claude API route\"\n c.set(\"requestErrorMessage\", message)\n log.error(\"Unsupported Claude API request\", {\n method: c.req.method,\n path: c.req.path,\n requestId: c.get(\"requestId\"),\n headers: getLoggedHeaders(c.req.raw),\n payload: await readRequestPayloadForLog(c.req.raw),\n })\n return c.json({ error: { message } }, 500)\n })\n\n return app\n}\n\nexport const startServer = (config: ProxyConfig): Promise<ServerType> =>\n new Promise((resolve, reject) => {\n const server = createAdaptorServer({\n fetch: createServer(config).fetch,\n hostname: config.host,\n port: config.port,\n })\n\n const onError = (error: Error) => {\n server.off(\"listening\", onListening)\n reject(error)\n }\n const onListening = () => {\n server.off(\"error\", onError)\n resolve(server)\n }\n\n server.once(\"error\", onError)\n server.once(\"listening\", onListening)\n server.listen(config.port, config.host)\n })\n","// `copilot-relay start`: loads config, validates upstream access, and starts the local Claude Code proxy.\nimport { defineCommand } from \"citty\"\n\nimport { setupProxyAuth } from \"~/lib/auth\"\nimport { readAppConfig, watchAppConfig, type AppConfig } from \"~/lib/app-config\"\nimport { applyClaudeConfig } from \"~/lib/claude-settings\"\nimport { readProxyConfig } from \"~/lib/config\"\nimport { claudeConfigPath as defaultClaudeConfigPath } from \"~/lib/defaults\"\nimport { clearRelayPidFile, writeRelayPidFile } from \"~/lib/lifecycle\"\nimport { cleanupLogs, log, setLogLevel } from \"~/lib/log\"\nimport { getExposedModelIds } from \"~/lib/models\"\nimport { validateUpstream } from \"~/lib/preflight\"\nimport { runtimeState } from \"~/lib/state\"\nimport { appVersion } from \"~/lib/version\"\nimport { startServer } from \"~/server\"\n\nexport async function startRelay(appConfig?: AppConfig): Promise<void> {\n appConfig ??= await readAppConfig()\n setLogLevel(appConfig.logLevel)\n await cleanupLogs(appConfig.logRetentionDays)\n\n const claudeConfigPath = defaultClaudeConfigPath\n const config = readProxyConfig(appConfig)\n const applyRuntimeConfig = (nextConfig: AppConfig) => {\n // Hot reload updates behavior for future requests; it intentionally does\n // not rebind the already-listening socket when host or port changes.\n setLogLevel(nextConfig.logLevel)\n void cleanupLogs(nextConfig.logRetentionDays)\n runtimeState.debug = nextConfig.logLevel === \"debug\"\n runtimeState.thinkEffort = nextConfig.thinkEffort\n config.copilotBaseUrl = nextConfig.copilotBaseUrl\n config.host = nextConfig.host\n config.port = nextConfig.port\n config.upstreamTimeoutMs = nextConfig.upstreamTimeoutSeconds * 1000\n config.webSearchBackend = nextConfig.webSearchBackend\n runtimeState.modelRouting = {\n gptModel: nextConfig.gptModel,\n opusModel: nextConfig.opusModel,\n }\n }\n applyRuntimeConfig(appConfig)\n\n log.info(`Log level: ${appConfig.logLevel}`)\n log.info(`Think effort: ${appConfig.thinkEffort}`)\n log.info(`Upstream timeout: ${appConfig.upstreamTimeoutSeconds}s`)\n log.info(`Exposed models: ${getExposedModelIds().join(\", \")}`)\n\n const authSession = await setupProxyAuth(config)\n\n try {\n await validateUpstream(config, appConfig.thinkEffort)\n } catch (error) {\n log.error(\"Startup preflight failed:\", error)\n process.exit(1)\n }\n\n const server = await startServer(config)\n await writeRelayPidFile(config)\n\n log.info(`copilot-relay version: ${appVersion}`)\n if (authSession.githubLogin) {\n log.info(`GitHub user: ${authSession.githubLogin}`)\n } else {\n log.error(\"GitHub user: unavailable\")\n }\n\n log.info(\n `copilot-relay listening on http://${config.host}:${config.port}`,\n )\n log.info(`copilot base url: ${config.copilotBaseUrl}`)\n\n const baseUrl = `http://${config.host}:${config.port}`\n if (appConfig.claudeSetup) {\n try {\n const claudeResult = await applyClaudeConfig({\n baseUrl,\n configPath: claudeConfigPath,\n })\n if (claudeResult.changed) {\n log.info(\n `claude settings ${claudeResult.created ? \"created\" : \"updated\"}: ${claudeResult.configPath}`,\n )\n if (\n claudeResult.previousBaseUrl\n && claudeResult.previousBaseUrl !== baseUrl\n ) {\n log.info(\n `ANTHROPIC_BASE_URL: ${claudeResult.previousBaseUrl} → ${baseUrl}`,\n )\n }\n } else {\n log.info(\n `claude settings already up to date: ${claudeResult.configPath}`,\n )\n }\n } catch (error) {\n log.error(\n `Could not update claude settings (${claudeConfigPath}):`,\n error,\n )\n }\n }\n watchAppConfig((nextConfig) => {\n applyRuntimeConfig(nextConfig)\n log.info(\n `Config reloaded: logLevel=${nextConfig.logLevel} thinkEffort=${nextConfig.thinkEffort} upstreamTimeoutSeconds=${nextConfig.upstreamTimeoutSeconds}`,\n )\n })\n\n const shutdown = (signal: NodeJS.Signals) => {\n log.info(`Received ${signal}; shutting down copilot-relay`)\n server.close((error) => {\n if (error) {\n log.error(\"Error while shutting down copilot-relay:\", error)\n process.exitCode = 1\n }\n })\n }\n process.once(\"SIGINT\", shutdown)\n process.once(\"SIGTERM\", shutdown)\n\n try {\n await new Promise<void>((resolve, reject) => {\n server.on(\"close\", resolve)\n server.on(\"error\", reject)\n })\n } finally {\n process.off(\"SIGINT\", shutdown)\n process.off(\"SIGTERM\", shutdown)\n await clearRelayPidFile()\n }\n}\n\nexport const start = defineCommand({\n meta: {\n name: \"start\",\n description: \"Start the copilot-relay HTTP server.\",\n },\n async run() {\n await startRelay()\n },\n})\n","// `copilot-relay restart`: stop stale local relay processes, then start normally.\nimport { defineCommand } from \"citty\"\n\nimport { readAppConfig } from \"~/lib/app-config\"\nimport { readProxyConfig } from \"~/lib/config\"\nimport { cleanupLogs, log, setLogLevel } from \"~/lib/log\"\nimport { stopExistingRelay } from \"~/lib/lifecycle\"\nimport { startRelay } from \"./start\"\n\nexport const restart = defineCommand({\n meta: {\n name: \"restart\",\n description: \"Stop any existing copilot-relay instance and start a new one.\",\n },\n async run() {\n const appConfig = await readAppConfig()\n setLogLevel(appConfig.logLevel)\n await cleanupLogs(appConfig.logRetentionDays)\n\n const stopped = await stopExistingRelay(readProxyConfig(appConfig))\n if (stopped.length > 0) {\n log.info(`Stopped copilot-relay pid(s): ${stopped.join(\", \")}`)\n }\n log.info(\"Starting copilot-relay\")\n\n await startRelay(appConfig)\n },\n})\n","// `copilot-relay stop`: terminate all detected local relay server instances.\nimport { defineCommand } from \"citty\"\n\nimport { readAppConfig } from \"~/lib/app-config\"\nimport { readProxyConfig } from \"~/lib/config\"\nimport { cleanupLogs, log, setLogLevel } from \"~/lib/log\"\nimport { stopExistingRelay } from \"~/lib/lifecycle\"\n\nexport const stop = defineCommand({\n meta: {\n name: \"stop\",\n description: \"Stop all detected copilot-relay server instances.\",\n },\n async run() {\n const appConfig = await readAppConfig()\n setLogLevel(appConfig.logLevel)\n await cleanupLogs(appConfig.logRetentionDays)\n\n const stopped = await stopExistingRelay(readProxyConfig(appConfig))\n if (stopped.length > 0) {\n log.info(`Stopped copilot-relay pid(s): ${stopped.join(\", \")}`)\n }\n },\n})\n","#!/usr/bin/env node\n\n// CLI entrypoint: wires top-level commands without owning runtime behavior.\nimport { defineCommand, runMain } from \"citty\"\n\nimport { auth } from \"./auth\"\nimport { restart } from \"./restart\"\nimport { start } from \"./start\"\nimport { stop } from \"./stop\"\n\nconst main = defineCommand({\n meta: {\n name: \"copilot-relay\",\n description:\n \"Yet, just another relay for Claude Code to use a GitHub Copilot subscription.\",\n },\n subCommands: { auth, restart, start, stop },\n})\n\nawait runMain(main)\n"],"mappings":"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"}
1
+ {"version":3,"file":"main.js","names":["consolaLevelByName: Record<LogLevelName, number>","fileLevelByMethod: Record<string, number>","copilotVersion","editorPluginVersion","userAgent","copilotTokenRefreshTimer: ReturnType<typeof setTimeout> | undefined","sleep","resolve","payload: StoredCopilotToken","refreshIn","refreshIn: number","runtimeState: RuntimeState","defaultReasoningEffort: ReasoningEffort","defaultModelRouting: ModelRoutingConfig","defaultConfig: AppConfig","config: Record<string, unknown>","logRetentionDays","config: AppConfig","resolve","payload: RelayPidFile","relayPids: Array<number>","configPath","parsed: Record<string, unknown>","env: Record<string, unknown>","next: Record<string, unknown>","lastError: unknown","path","undiciFetch","state: ResponseTranslationState","chunks: Array<ResponseStreamEventMessage>","translated: Array<ResponsesInputItem>","continuePrefillPrompt","normalizeFinalAssistantPrefill","newMessages: Array<Message>","contentParts: Array<ContentPart>","allThinkingBlocks: Array<ClaudeThinkingBlock>","allTextBlocks: Array<ClaudeTextBlock>","allToolUseBlocks: Array<ClaudeToolUseBlock>","stopReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null","events: Array<ClaudeStreamEventData>","events","results: Array<WebSearchResult>","content: Array<ClaudeAssistantContentBlock>","events: Array<ClaudeStreamEventData>","events","claudeResponse: ClaudeResponse","streamState: ClaudeStreamState","chunk: ChatCompletionChunk","path","claudeConfigPath","defaultClaudeConfigPath","resolve"],"sources":["../src/lib/error.ts","../src/lib/paths.ts","../src/lib/log.ts","../src/lib/auth.ts","../src/lib/state.ts","../src/lib/models.ts","../src/lib/app-config.ts","../src/lib/config.ts","../src/auth.ts","../src/lib/lifecycle.ts","../src/lib/claude-settings.ts","../src/lib/defaults.ts","../src/copilot/client.ts","../src/copilot/responses.ts","../src/copilot/chat.ts","../src/lib/preflight.ts","../src/lib/version.ts","../src/claude/utils.ts","../src/claude/tool-names.ts","../src/claude/translate.ts","../src/claude/stream.ts","../src/claude/web-search.ts","../src/lib/tokenizer.ts","../src/routes/claude.ts","../src/server.ts","../src/start.ts","../src/restart.ts","../src/stop.ts","../src/main.ts"],"sourcesContent":["// Error wrappers used to preserve upstream HTTP status and response bodies.\nexport class ProxyNotImplementedError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"ProxyNotImplementedError\"\n }\n}\n\nexport class HTTPError extends Error {\n detail?: string\n response: Response\n\n constructor(message: string, response: Response, detail?: string) {\n super(message)\n this.name = \"HTTPError\"\n this.detail = detail\n this.response = response\n }\n}\n","// File-system layout for config, token cache, logs, and legacy migration paths.\nimport fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nconst homeDir = os.homedir()\n\nconst appDir = path.join(homeDir, \".copilot-relay\")\n\nconst legacyGithubTokenPaths = [\n path.join(homeDir, \".copilot-tennel\", \"github_token\"),\n path.join(homeDir, \"Library\", \"Application Support\", \"copilot-tennel\", \"github_token\"),\n path.join(homeDir, \".local\", \"share\", \"copilot-tennel\", \"github_token\"),\n path.join(homeDir, \"Library\", \"Application Support\", \"copilot-relay\", \"github_token\"),\n path.join(homeDir, \".local\", \"share\", \"copilot-relay\", \"github_token\"),\n path.join(homeDir, \".local\", \"share\", \"copilot-bridge\", \"github_token\"),\n]\n\nconst legacyCopilotTokenPaths = [\n path.join(homeDir, \".copilot-tennel\", \"copilot_token.json\"),\n path.join(homeDir, \"Library\", \"Application Support\", \"copilot-tennel\", \"copilot_token.json\"),\n path.join(homeDir, \".local\", \"share\", \"copilot-tennel\", \"copilot_token.json\"),\n path.join(homeDir, \"Library\", \"Application Support\", \"copilot-relay\", \"copilot_token.json\"),\n path.join(homeDir, \".local\", \"share\", \"copilot-relay\", \"copilot_token.json\"),\n]\n\nconst configPath = path.join(appDir, \"config.yaml\")\nconst copilotTokenPath = path.join(appDir, \"copilot_token.json\")\nconst githubTokenPath = path.join(appDir, \"github_token\")\nconst logsDir = path.join(appDir, \"logs\")\nconst logPath = path.join(logsDir, \"copilot-relay.log\")\nconst pidPath = path.join(appDir, \"copilot-relay.pid\")\n\nexport const paths = {\n appDir,\n configPath,\n copilotTokenPath,\n githubTokenPath,\n legacyConfigPaths: [\n path.join(homeDir, \".copilot-relay.yaml\"),\n path.join(homeDir, \".copilot-tennel\", \"config.yaml\"),\n path.join(homeDir, \".copilot-tennel.yaml\"),\n ],\n legacyCopilotTokenPaths,\n logPath,\n logsDir,\n pidPath,\n}\n\nexport async function ensurePaths(): Promise<void> {\n await fs.mkdir(paths.appDir, { recursive: true })\n // GitHub tokens are plain text and safe to migrate here. Copilot token\n // migration is handled in auth.ts because that cache has a JSON schema.\n await ensureFile(paths.githubTokenPath, {\n legacyPaths: legacyGithubTokenPaths,\n })\n}\n\nasync function ensureFile(\n filePath: string,\n options: { legacyPaths?: Array<string> } = {},\n): Promise<void> {\n try {\n await fs.access(filePath, fs.constants.W_OK)\n } catch {\n for (const legacyPath of options.legacyPaths ?? []) {\n if (legacyPath === filePath) {\n continue\n }\n\n try {\n const content = await fs.readFile(legacyPath, \"utf8\")\n if (content.trim()) {\n await fs.writeFile(filePath, content, { mode: 0o600 })\n await fs.chmod(filePath, 0o600)\n return\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error\n }\n }\n }\n\n await fs.writeFile(filePath, \"\")\n await fs.chmod(filePath, 0o600)\n }\n}","// Central logger: writes to console and ~/.copilot-relay/logs with retention cleanup.\nimport fs from \"node:fs/promises\"\nimport { inspect } from \"node:util\"\n\nimport consola from \"consola\"\n\nimport type { LogLevelName } from \"~/lib/app-config\"\nimport { paths } from \"~/lib/paths\"\n\nconst logCleanupCheckIntervalMs = 60 * 60 * 1000\nlet logRetentionDays = 3\nlet nextLogCleanupCheckAt = 0\n\nconst consolaLevelByName: Record<LogLevelName, number> = {\n error: 0,\n info: 3,\n debug: 4,\n}\n\n// Keep runtime logging intentionally small: error carries full failure context,\n// info is operational status, and debug is detailed tracing for local diagnosis.\nconst fileLevelByMethod: Record<string, number> = {\n error: consolaLevelByName.error,\n info: consolaLevelByName.info,\n debug: consolaLevelByName.debug,\n}\n\nlet currentLogLevel = consolaLevelByName.info\n\nexport const setLogLevel = (level: LogLevelName): void => {\n currentLogLevel = consolaLevelByName[level]\n consola.level = consolaLevelByName[level]\n}\n\nconst formatLogValue = (value: unknown): string =>\n typeof value === \"string\" ? value : inspect(value, { depth: null })\n\nconst writeLogFile = async (\n level: string,\n values: Array<unknown>,\n): Promise<void> => {\n await fs.mkdir(paths.logsDir, { recursive: true })\n await cleanupLogsIfDue()\n const line = [\n new Date().toISOString(),\n level,\n values.map(formatLogValue).join(\" \"),\n ].join(\" \")\n await fs.appendFile(paths.logPath, `${line}\\n`)\n}\n\nconst cleanupLogsIfDue = async (): Promise<void> => {\n const now = Date.now()\n if (now < nextLogCleanupCheckAt) {\n return\n }\n\n nextLogCleanupCheckAt = now + logCleanupCheckIntervalMs\n await cleanupLogs(logRetentionDays)\n}\n\nconst wrapFileLog = <T extends (...args: Array<unknown>) => unknown>(\n level: string,\n fn: T,\n): T =>\n ((...args: Array<unknown>) => {\n if ((fileLevelByMethod[level] ?? consolaLevelByName.info) <= currentLogLevel) {\n // File logging must never block the console path or fail a request. If\n // the disk write fails, the original consola call still runs.\n void writeLogFile(level, args).catch(() => undefined)\n }\n return fn(...args)\n }) as T\n\nconsola.error = wrapFileLog(\"error\", consola.error.bind(consola))\nconsola.info = wrapFileLog(\"info\", consola.info.bind(consola))\nconsola.debug = wrapFileLog(\"debug\", consola.debug.bind(consola))\n\nexport const cleanupLogs = async (retentionDays: number): Promise<void> => {\n logRetentionDays = retentionDays\n await fs.mkdir(paths.logsDir, { recursive: true })\n // Retention uses file mtime rather than per-line timestamps; the active log\n // naturally remains fresh while the long-running proxy keeps appending to it.\n const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1000\n const entries = await fs.readdir(paths.logsDir, { withFileTypes: true })\n await Promise.all(\n entries\n .filter((entry) => entry.isFile() && entry.name.endsWith(\".log\"))\n .map(async (entry) => {\n const filePath = `${paths.logsDir}/${entry.name}`\n const stat = await fs.stat(filePath)\n if (stat.mtimeMs < cutoff) {\n await fs.unlink(filePath)\n }\n }),\n )\n}\n\nexport const log = consola\n","// GitHub device auth plus file-backed Copilot token cache and refresh scheduling.\nimport fs from \"node:fs/promises\"\n\nimport type { ProxyConfig } from \"~/lib/config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { log } from \"~/lib/log\"\nimport { paths, ensurePaths } from \"~/lib/paths\"\n\nconst copilotVersion = \"0.26.7\"\nconst editorPluginVersion = `copilot-chat/${copilotVersion}`\nconst userAgent = `GitHubCopilotChat/${copilotVersion}`\nconst githubApiVersion = \"2022-11-28\"\n\nconst githubApiBaseUrl = \"https://api.github.com\"\nconst githubBaseUrl = \"https://github.com\"\nconst githubClientId = \"Iv1.b507a08c87ecfe98\"\nconst githubAppScopes = [\"read:user\"].join(\" \")\n\ninterface DeviceCodeResponse {\n device_code: string\n expires_in: number\n interval: number\n user_code: string\n verification_uri: string\n}\n\ninterface AccessTokenResponse {\n access_token?: string\n}\n\ninterface CopilotTokenResponse {\n refresh_in: number\n token: string\n}\n\ninterface StoredCopilotToken {\n refreshedAt: number\n refreshIn: number\n token: string\n}\n\ninterface GitHubUserResponse {\n login: string\n}\n\ninterface AuthOptions {\n force?: boolean\n}\n\nexport interface ProxyAuthSession {\n githubLogin?: string\n source: \"github-token\"\n}\n\nlet copilotTokenRefreshTimer: ReturnType<typeof setTimeout> | undefined\n\nconst standardHeaders = () => ({\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n})\n\nconst sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nconst readGitHubToken = async () => {\n await ensurePaths()\n const token = await fs.readFile(paths.githubTokenPath, \"utf8\")\n return token.trim()\n}\n\nconst writeGitHubToken = async (token: string) => {\n await ensurePaths()\n await fs.writeFile(paths.githubTokenPath, `${token.trim()}\\n`, {\n mode: 0o600,\n })\n}\n\nconst readStoredCopilotToken = async (): Promise<StoredCopilotToken | undefined> => {\n await ensurePaths()\n try {\n const payload = JSON.parse(\n await fs.readFile(paths.copilotTokenPath, \"utf8\"),\n ) as Partial<StoredCopilotToken>\n if (\n typeof payload.token === \"string\"\n && typeof payload.refreshedAt === \"number\"\n && typeof payload.refreshIn === \"number\"\n ) {\n return payload as StoredCopilotToken\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error\n }\n }\n\n // Migrate only caches that still match the current JSON shape; older files\n // are ignored so a corrupt token cache does not poison new installs.\n for (const legacyPath of paths.legacyCopilotTokenPaths) {\n try {\n const content = await fs.readFile(legacyPath, \"utf8\")\n const payload = JSON.parse(content) as Partial<StoredCopilotToken>\n if (\n typeof payload.token === \"string\"\n && typeof payload.refreshedAt === \"number\"\n && typeof payload.refreshIn === \"number\"\n ) {\n await fs.writeFile(paths.copilotTokenPath, content, { mode: 0o600 })\n await fs.chmod(paths.copilotTokenPath, 0o600)\n return payload as StoredCopilotToken\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error\n }\n }\n }\n\n return undefined\n}\n\nconst writeStoredCopilotToken = async (\n input: CopilotTokenResponse,\n): Promise<void> => {\n await ensurePaths()\n const payload: StoredCopilotToken = {\n refreshedAt: Date.now(),\n refreshIn: input.refresh_in,\n token: input.token,\n }\n await fs.writeFile(\n paths.copilotTokenPath,\n `${JSON.stringify(payload, null, 2)}\\n`,\n { mode: 0o600 },\n )\n}\n\nconst getStoredTokenRemainingSeconds = (token: StoredCopilotToken): number => {\n const ageSeconds = Math.floor((Date.now() - token.refreshedAt) / 1000)\n return token.refreshIn - ageSeconds\n}\n\nconst githubHeaders = (githubToken: string, vsCodeVersion: string) => ({\n ...standardHeaders(),\n authorization: `token ${githubToken}`,\n \"editor-plugin-version\": editorPluginVersion,\n \"editor-version\": `vscode/${vsCodeVersion}`,\n \"user-agent\": userAgent,\n \"x-github-api-version\": githubApiVersion,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n})\n\nconst getDeviceCode = async (): Promise<DeviceCodeResponse> => {\n const response = await fetch(`${githubBaseUrl}/login/device/code`, {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: githubClientId,\n scope: githubAppScopes,\n }),\n })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get device code\", response)\n }\n\n return (await response.json()) as DeviceCodeResponse\n}\n\nconst pollAccessToken = async (\n deviceCode: DeviceCodeResponse,\n): Promise<string> => {\n // GitHub asks clients to poll at `interval`; add a one-second cushion so\n // long waits do not accidentally trigger OAuth `slow_down` responses.\n const sleepDuration = (deviceCode.interval + 1) * 1000\n\n // Device auth is intentionally user-driven: keep polling until the user\n // finishes authorization in the browser instead of treating pending states\n // as fatal startup errors.\n while (true) {\n const response = await fetch(`${githubBaseUrl}/login/oauth/access_token`, {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: githubClientId,\n device_code: deviceCode.device_code,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }),\n })\n\n if (!response.ok) {\n await sleep(sleepDuration)\n continue\n }\n\n const json = (await response.json()) as AccessTokenResponse\n if (json.access_token) {\n return json.access_token\n }\n\n await sleep(sleepDuration)\n }\n}\n\nconst getGitHubUser = async (\n githubToken: string,\n vsCodeVersion: string,\n): Promise<GitHubUserResponse> => {\n const response = await fetch(`${githubApiBaseUrl}/user`, {\n headers: githubHeaders(githubToken, vsCodeVersion),\n })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get GitHub user\", response)\n }\n\n return (await response.json()) as GitHubUserResponse\n}\n\nconst getCopilotToken = async (\n githubToken: string,\n vsCodeVersion: string,\n): Promise<CopilotTokenResponse> => {\n const response = await fetch(\n `${githubApiBaseUrl}/copilot_internal/v2/token`,\n {\n headers: githubHeaders(githubToken, vsCodeVersion),\n },\n )\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get Copilot token\", response)\n }\n\n return (await response.json()) as CopilotTokenResponse\n}\n\nconst isCopilotTokenError = (error: unknown): boolean =>\n error instanceof HTTPError && error.message === \"Failed to get Copilot token\"\n\nconst ensureGitHubToken = async (options: AuthOptions = {}) => {\n const existingToken = options.force ? \"\" : await readGitHubToken()\n if (existingToken) {\n log.info(`Using cached GitHub token at ${paths.githubTokenPath}`)\n return existingToken\n }\n\n const deviceCode = await getDeviceCode()\n log.info(\n `Open ${deviceCode.verification_uri} and enter code ${deviceCode.user_code}`,\n )\n\n const githubToken = await pollAccessToken(deviceCode)\n await writeGitHubToken(githubToken)\n log.info(`GitHub token synced to ${paths.githubTokenPath}`)\n\n return githubToken\n}\n\nconst loadGitHubLogin = async (\n githubToken: string,\n vsCodeVersion: string,\n): Promise<string | undefined> => {\n try {\n const user = await getGitHubUser(githubToken, vsCodeVersion)\n return user.login\n } catch (error) {\n log.error(\"Could not load GitHub user:\", error)\n return undefined\n }\n}\n\nexport const setupProxyAuth = async (\n config: ProxyConfig,\n options: AuthOptions = {},\n): Promise<ProxyAuthSession> => {\n let githubToken = await ensureGitHubToken(options)\n const applyCopilotToken = async () => {\n const tokenResponse = await getCopilotToken(\n githubToken,\n config.vsCodeVersion,\n )\n\n config.copilotToken = tokenResponse.token\n await writeStoredCopilotToken(tokenResponse)\n return tokenResponse.refresh_in\n }\n\n const scheduleCopilotTokenRefresh = (refreshIn: number) => {\n if (copilotTokenRefreshTimer) {\n clearTimeout(copilotTokenRefreshTimer)\n }\n\n // Refresh one minute before GitHub's `refresh_in` deadline, but keep a\n // one-minute floor so failure retries do not spin in a tight loop.\n const refreshMs = Math.max(refreshIn - 60, 60) * 1000\n log.info(\n `Next Copilot token refresh in ${Math.round(refreshMs / 1000)}s`,\n )\n\n copilotTokenRefreshTimer = setTimeout(async () => {\n try {\n const nextRefreshIn = await applyCopilotToken()\n log.info(\"Refreshed Copilot token\")\n scheduleCopilotTokenRefresh(nextRefreshIn)\n } catch (error) {\n log.error(\"Failed to refresh Copilot token:\", error)\n // Keep the last token active and retry soon; in-flight requests can\n // continue until the bearer token actually expires.\n scheduleCopilotTokenRefresh(60)\n }\n }, refreshMs)\n\n if (typeof copilotTokenRefreshTimer.unref === \"function\") {\n copilotTokenRefreshTimer.unref()\n }\n }\n\n const storedToken = await readStoredCopilotToken()\n let refreshIn: number\n if (storedToken && getStoredTokenRemainingSeconds(storedToken) > 60) {\n // Avoid using tokens that are close to expiry; Claude Code requests can\n // be long-running, so keep at least one minute of freshness for new calls.\n config.copilotToken = storedToken.token\n refreshIn = getStoredTokenRemainingSeconds(storedToken)\n log.info(`Using cached Copilot token at ${paths.copilotTokenPath}`)\n } else {\n try {\n refreshIn = await applyCopilotToken()\n } catch (error) {\n if (options.force || !isCopilotTokenError(error)) {\n throw error\n }\n\n // A cached GitHub token can still become unable to mint Copilot tokens\n // after revocation or account changes; only this specific failure gets\n // a fresh device-auth attempt.\n log.error(\n \"Cached GitHub auth could not get a Copilot token; running device auth again.\",\n )\n githubToken = await ensureGitHubToken({\n ...options,\n force: true,\n })\n refreshIn = await applyCopilotToken()\n }\n }\n scheduleCopilotTokenRefresh(refreshIn)\n\n return {\n githubLogin: await loadGitHubLogin(githubToken, config.vsCodeVersion),\n source: \"github-token\",\n }\n}\n\nexport const runProxyAuth = async (\n config: ProxyConfig,\n options: AuthOptions = {},\n) => {\n const githubToken = await ensureGitHubToken({\n ...options,\n force: true,\n })\n\n const user = await getGitHubUser(githubToken, config.vsCodeVersion)\n log.info(`GitHub token written to ${paths.githubTokenPath}`)\n log.info(`Logged in as ${user.login}`)\n}","// Process-local mutable state for values that can change after config hot reload.\nimport type { ReasoningEffort } from \"~/lib/models\"\nimport type { ModelRoutingConfig } from \"~/lib/models\"\n\nexport interface RuntimeState {\n debug?: boolean\n modelRouting?: ModelRoutingConfig\n thinkEffort?: ReasoningEffort\n}\n\nexport const runtimeState: RuntimeState = {}\n","// Config-driven model routing and think-effort validation.\nimport { runtimeState } from \"~/lib/state\"\n\nexport type ReasoningEffort =\n | \"none\"\n | \"low\"\n | \"medium\"\n | \"high\"\n | \"xhigh\"\n | \"max\"\n\nexport interface ModelRoutingConfig {\n gptModel: string\n opusModel: string\n}\n\nexport const defaultReasoningEffort: ReasoningEffort = \"max\"\n\nexport const defaultModelRouting: ModelRoutingConfig = {\n gptModel: \"gpt-5.6-sol\",\n opusModel: \"claude-opus-4.8\",\n}\n\nexport const isReasoningEffort = (value: unknown): value is ReasoningEffort =>\n value === \"none\"\n || value === \"low\"\n || value === \"medium\"\n || value === \"high\"\n || value === \"xhigh\"\n || value === \"max\"\n\nexport const getModelRouting = (): ModelRoutingConfig =>\n runtimeState.modelRouting ?? defaultModelRouting\n\nexport const getExposedModelIds = (): Array<string> => {\n const routing = getModelRouting()\n return [routing.gptModel, routing.opusModel]\n}\n\nexport const routeModelId = (model: string): string => {\n const routing = getModelRouting()\n // Keep routing intentionally predictable for Claude Code: any alias that\n // mentions Opus gets the configured Opus upstream, all other model names use\n // the configured GPT upstream.\n return model.trim().toLowerCase().includes(\"opus\") ?\n routing.opusModel\n : routing.gptModel\n}\n","// Runtime YAML config loader/writer with hot-reload support for ~/.copilot-relay/config.yaml.\nimport fs from \"node:fs/promises\"\nimport { dirname, resolve } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nimport {\n defaultReasoningEffort,\n isReasoningEffort,\n type ReasoningEffort,\n} from \"~/lib/models\"\nimport { paths } from \"~/lib/paths\"\n\nexport const logLevels = [\"error\", \"info\", \"debug\"] as const\nexport type LogLevelName = (typeof logLevels)[number]\nexport interface AppConfig {\n claudeSetup: boolean\n copilotBaseUrl: string\n gptModel: string\n host: string\n logLevel: LogLevelName\n logRetentionDays: number\n opusModel: string\n port: number\n thinkEffort: ReasoningEffort\n upstreamTimeoutSeconds: number\n webSearchBackend?: string\n}\n\nconst defaultConfig: AppConfig = {\n claudeSetup: true,\n copilotBaseUrl: \"https://api.githubcopilot.com\",\n gptModel: \"gpt-5.6-sol\",\n host: \"127.0.0.1\",\n logLevel: \"info\",\n logRetentionDays: 3,\n opusModel: \"claude-opus-4.8\",\n port: 4142,\n thinkEffort: defaultReasoningEffort,\n upstreamTimeoutSeconds: 180,\n webSearchBackend: undefined,\n}\n\nexport const isLogLevelName = (value: unknown): value is LogLevelName =>\n typeof value === \"string\"\n && logLevels.includes(value.toLowerCase() as LogLevelName)\n\nexport const normalizeLogLevel = (value: unknown): LogLevelName | undefined => {\n if (value === undefined) {\n return undefined\n }\n\n if (typeof value !== \"string\") {\n throw new Error(\n `Invalid logLevel: expected one of ${logLevels.join(\", \")}`,\n )\n }\n\n const normalized = value.toLowerCase()\n if (!isLogLevelName(normalized)) {\n throw new Error(\n `Invalid logLevel \"${value}\": expected one of ${logLevels.join(\", \")}`,\n )\n }\n\n return normalized\n}\n\nconst normalizeBoolean = (value: unknown): boolean | undefined => {\n if (typeof value === \"boolean\") {\n return value\n }\n if (typeof value !== \"string\") {\n return undefined\n }\n const normalized = value.toLowerCase()\n if (normalized === \"true\") return true\n if (normalized === \"false\") return false\n return undefined\n}\n\nconst normalizePort = (value: unknown): number | undefined => {\n const port =\n typeof value === \"number\" ? value\n : typeof value === \"string\" ? Number.parseInt(value, 10)\n : Number.NaN\n return Number.isInteger(port) && port > 0 && port <= 65_535 ? port : undefined\n}\n\nconst normalizePositiveInteger = (value: unknown): number | undefined => {\n const number =\n typeof value === \"number\" ? value\n : typeof value === \"string\" ? Number.parseInt(value, 10)\n : Number.NaN\n return Number.isInteger(number) && number > 0 ? number : undefined\n}\n\nconst normalizeString = (value: unknown): string | undefined =>\n typeof value === \"string\" && value.trim() ? value.trim() : undefined\n\nexport const normalizeThinkEffort = (\n value: unknown,\n): ReasoningEffort | undefined => {\n if (typeof value !== \"string\") {\n return undefined\n }\n const normalized = value.toLowerCase() === \"minimal\" ? \"low\" : value.toLowerCase()\n return isReasoningEffort(normalized) ? normalized : undefined\n}\n\nexport const normalizeUpstreamTimeoutSeconds = (\n value: unknown,\n): number | undefined => {\n if (value === undefined) {\n return undefined\n }\n\n const timeout = normalizePositiveInteger(value)\n if (timeout === undefined) {\n throw new Error(\"Invalid upstreamTimeoutSeconds: expected a positive integer\")\n }\n\n return timeout\n}\n\nconst readRawConfig = async (): Promise<Record<string, unknown>> => {\n try {\n const content = await fs.readFile(paths.configPath, \"utf8\")\n return parseConfigYaml(content)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n for (const legacyPath of paths.legacyConfigPaths) {\n try {\n const content = await fs.readFile(legacyPath, \"utf8\")\n return parseConfigYaml(content)\n } catch (legacyError) {\n if ((legacyError as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw legacyError\n }\n }\n }\n return readDefaultConfigTemplate()\n }\n throw error\n }\n}\n\nconst readDefaultConfigTemplate = async (): Promise<Record<string, unknown>> => {\n let currentDir = dirname(fileURLToPath(import.meta.url))\n\n // Bundled code may run from src/ during development or from dist/ after\n // packaging, so walk upward until the package-level config template is found.\n while (true) {\n try {\n const content = await fs.readFile(\n resolve(currentDir, \"config.default.yaml\"),\n \"utf8\",\n )\n return parseConfigYaml(content)\n } catch {\n const parentDir = dirname(currentDir)\n if (parentDir === currentDir) {\n return {}\n }\n currentDir = parentDir\n }\n }\n}\n\nconst unquoteYamlScalar = (value: string): string => {\n const trimmed = value.trim()\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"'))\n || (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n ) {\n return trimmed.slice(1, -1)\n }\n return trimmed\n}\n\nconst parseConfigYaml = (content: string): Record<string, unknown> => {\n const config: Record<string, unknown> = {}\n for (const line of content.split(/\\r?\\n/)) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith(\"#\")) {\n continue\n }\n\n const match = trimmed.match(/^([A-Za-z][A-Za-z0-9_-]*)\\s*:\\s*(.*?)\\s*$/)\n if (!match) {\n throw new Error(`Invalid config line in ${paths.configPath}: ${line}`)\n }\n\n const [, key, value] = match\n // The runtime config intentionally supports only a flat key/value YAML\n // subset. That keeps startup dependency-free and makes bad edits fail\n // predictably instead of being partially interpreted.\n switch (key) {\n case \"claudeSetup\":\n case \"claude_setup\": {\n config.claudeSetup = unquoteYamlScalar(value)\n break\n }\n case \"copilotBaseUrl\":\n case \"copilot_base_url\": {\n config.copilotBaseUrl = unquoteYamlScalar(value)\n break\n }\n case \"host\": {\n config.host = unquoteYamlScalar(value)\n break\n }\n case \"gptModel\":\n case \"gpt_model\": {\n config.gptModel = unquoteYamlScalar(value)\n break\n }\n case \"logLevel\":\n case \"log_level\": {\n config.logLevel = unquoteYamlScalar(value)\n break\n }\n case \"logRetentionDays\":\n case \"log_retention_days\": {\n config.logRetentionDays = unquoteYamlScalar(value)\n break\n }\n case \"opusModel\":\n case \"opus_model\": {\n config.opusModel = unquoteYamlScalar(value)\n break\n }\n case \"port\": {\n config.port = unquoteYamlScalar(value)\n break\n }\n case \"thinkEffort\":\n case \"think_effort\": {\n config.thinkEffort = unquoteYamlScalar(value)\n break\n }\n case \"upstreamTimeoutSeconds\":\n case \"upstream_timeout_seconds\": {\n config.upstreamTimeoutSeconds = unquoteYamlScalar(value)\n break\n }\n case \"webSearchBackend\":\n case \"web_search_backend\": {\n config.webSearchBackend = unquoteYamlScalar(value)\n break\n }\n default: {\n break\n }\n }\n }\n return config\n}\n\nconst writeConfig = async (config: AppConfig): Promise<void> => {\n await fs.mkdir(paths.appDir, { recursive: true })\n const content = serializeConfig(config)\n const existing = await fs.readFile(paths.configPath, \"utf8\").catch(() => \"\")\n if (existing === content) {\n return\n }\n await fs.writeFile(paths.configPath, content, { mode: 0o600 })\n}\n\nconst serializeConfig = (config: AppConfig): string =>\n [\n \"# copilot-relay configuration\",\n \"#\",\n \"# This file is hot-reloaded while copilot-relay is running.\",\n \"\",\n \"# Local host for the Claude Code-compatible HTTP server.\",\n `host: ${config.host}`,\n \"\",\n \"# Local port for the HTTP server.\",\n `port: ${config.port}`,\n \"\",\n \"# GitHub Copilot API base URL.\",\n `copilotBaseUrl: ${config.copilotBaseUrl}`,\n \"\",\n \"# Update ~/.claude/settings.json on start.\",\n `claudeSetup: ${config.claudeSetup}`,\n \"\",\n \"# Log verbosity:\",\n \"# error - startup/preflight/request failures only\",\n \"# info - error logs plus startup status, preflight status, and local HTTP\",\n \"# status codes\",\n \"# debug - info logs plus model routing summaries, Copilot upstream timings,\",\n \"# and request payloads\",\n `logLevel: ${config.logLevel}`,\n \"\",\n \"# Number of days to keep files in ~/.copilot-relay/logs.\",\n `logRetentionDays: ${config.logRetentionDays}`,\n \"\",\n \"# Default upstream thinking/reasoning effort: none, low, medium, high, xhigh, max.\",\n `thinkEffort: ${config.thinkEffort}`,\n \"\",\n \"# Max seconds to wait for a single Claude request's upstream Copilot calls.\",\n `upstreamTimeoutSeconds: ${config.upstreamTimeoutSeconds}`,\n \"\",\n \"# Copilot model used for bridge-managed Claude WebSearch. Empty uses gptModel.\",\n `webSearchBackend: ${config.webSearchBackend ?? \"\"}`,\n \"\",\n \"# Model routing: requests containing \\\"opus\\\" use opusModel; all others use gptModel.\",\n \"\",\n \"# Upstream Copilot model used for non-Opus requests.\",\n `gptModel: ${config.gptModel}`,\n \"\",\n \"# Upstream Copilot model used for requests containing \\\"opus\\\".\",\n `opusModel: ${config.opusModel}`,\n \"\",\n ].join(\"\\n\")\n\nexport async function readAppConfig(): Promise<AppConfig> {\n const raw = await readRawConfig()\n const claudeSetup = normalizeBoolean(raw.claudeSetup)\n const host = normalizeString(raw.host)\n const logLevel = normalizeLogLevel(raw.logLevel)\n const logRetentionDays = normalizePositiveInteger(raw.logRetentionDays)\n const port = normalizePort(raw.port)\n const thinkEffort = normalizeThinkEffort(raw.thinkEffort)\n const upstreamTimeoutSeconds = normalizeUpstreamTimeoutSeconds(\n raw.upstreamTimeoutSeconds,\n )\n\n const config: AppConfig = {\n claudeSetup: claudeSetup ?? defaultConfig.claudeSetup,\n copilotBaseUrl: normalizeString(raw.copilotBaseUrl) ?? defaultConfig.copilotBaseUrl,\n gptModel: normalizeString(raw.gptModel) ?? defaultConfig.gptModel,\n host: host ?? defaultConfig.host,\n logLevel: logLevel ?? defaultConfig.logLevel,\n logRetentionDays: logRetentionDays ?? defaultConfig.logRetentionDays,\n opusModel: normalizeString(raw.opusModel) ?? defaultConfig.opusModel,\n port: port ?? defaultConfig.port,\n thinkEffort: thinkEffort ?? defaultConfig.thinkEffort,\n upstreamTimeoutSeconds:\n upstreamTimeoutSeconds ?? defaultConfig.upstreamTimeoutSeconds,\n webSearchBackend: normalizeString(raw.webSearchBackend),\n }\n\n await writeConfig(config)\n return config\n}\n\nconst getConfigMtime = async (): Promise<number> => {\n try {\n return (await fs.stat(paths.configPath)).mtimeMs\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return 0\n }\n throw error\n }\n}\n\nexport const watchAppConfig = (\n onReload: (config: AppConfig) => void,\n): ReturnType<typeof setInterval> => {\n let lastMtime = 0\n\n const timer = setInterval(async () => {\n try {\n const nextMtime = await getConfigMtime()\n if (nextMtime === lastMtime) {\n return\n }\n\n lastMtime = nextMtime\n onReload(await readAppConfig())\n } catch {\n // Config editors can briefly write invalid partial files. Keep the last\n // good runtime config rather than degrading live requests mid-edit.\n }\n }, 1000)\n\n if (typeof timer.unref === \"function\") {\n timer.unref()\n }\n\n void getConfigMtime().then((mtime) => {\n lastMtime = mtime\n })\n\n return timer\n}\n","// Converts hot-loaded app config into the mutable runtime config shared with routes.\nimport type { AppConfig } from \"~/lib/app-config\"\n\nconst vscodeVersion = \"1.99.3\"\n\nexport interface ProxyConfig {\n host: string\n port: number\n copilotBaseUrl: string\n copilotToken: string | undefined\n upstreamTimeoutMs: number\n vsCodeVersion: string\n webSearchBackend?: string\n}\n\nexport interface ProxyEnv {\n Variables: {\n config: ProxyConfig\n requestErrorMessage?: string\n requestId: string\n }\n}\n\nexport const readProxyConfig = (config: AppConfig): ProxyConfig => ({\n copilotBaseUrl: config.copilotBaseUrl,\n copilotToken: undefined,\n host: config.host,\n port: config.port,\n upstreamTimeoutMs: config.upstreamTimeoutSeconds * 1000,\n vsCodeVersion: vscodeVersion,\n webSearchBackend: config.webSearchBackend,\n})\n","// `copilot-relay auth`: performs an explicit device-login flow and syncs tokens.\nimport { defineCommand } from \"citty\"\n\nimport { setupProxyAuth } from \"~/lib/auth\"\nimport { readAppConfig } from \"~/lib/app-config\"\nimport { readProxyConfig } from \"~/lib/config\"\nimport { log } from \"~/lib/log\"\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run GitHub device auth and cache credentials for copilot-relay.\",\n },\n async run() {\n const config = readProxyConfig(await readAppConfig())\n\n config.copilotToken = undefined\n\n const authSession = await setupProxyAuth(config, {\n force: true,\n })\n\n if (authSession.githubLogin) {\n log.info(`Logged in as ${authSession.githubLogin}`)\n }\n\n log.info(\"copilot-relay auth completed\")\n },\n})\n","// Process lifecycle helpers for stopping stale local relay instances.\nimport { execFile } from \"node:child_process\"\nimport fs from \"node:fs/promises\"\nimport { promisify } from \"node:util\"\n\nimport type { ProxyConfig } from \"~/lib/config\"\nimport { log } from \"~/lib/log\"\nimport { paths } from \"~/lib/paths\"\n\nconst execFileAsync = promisify(execFile)\nconst stopTimeoutMs = 5_000\nconst stopPollMs = 100\n\ninterface RelayPidFile {\n host: string\n pid: number\n port: number\n startedAt: string\n}\n\nconst isNodeErrno = (error: unknown): error is NodeJS.ErrnoException =>\n typeof error === \"object\" && error !== null && \"code\" in error\n\nconst sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nconst parsePid = (value: unknown): number | undefined => {\n const pid =\n typeof value === \"number\" ? value\n : typeof value === \"string\" ? Number.parseInt(value.trim(), 10)\n : Number.NaN\n\n return Number.isInteger(pid) && pid > 0 ? pid : undefined\n}\n\nconst readCommandOutput = async (\n file: string,\n args: Array<string>,\n): Promise<string> => {\n try {\n const { stdout } = await execFileAsync(file, args, {\n maxBuffer: 1024 * 1024,\n windowsHide: true,\n })\n return String(stdout)\n } catch (error) {\n if (\n typeof error === \"object\"\n && error !== null\n && \"stdout\" in error\n && (typeof error.stdout === \"string\" || Buffer.isBuffer(error.stdout))\n ) {\n return String(error.stdout)\n }\n return \"\"\n }\n}\n\nconst parsePidLines = (output: string): Array<number> =>\n output\n .split(/\\r?\\n/)\n .map((line) => parsePid(line))\n .filter((pid): pid is number => pid !== undefined)\n\nexport const isRelayStartProcess = (\n command: string,\n cwd?: string,\n): boolean => {\n const normalizedCommand = command.replaceAll(\"\\\\\", \"/\")\n const normalizedCwd = cwd?.replaceAll(\"\\\\\", \"/\")\n const hasStartArg = /(?:^|\\s)start(?:\\s|$)/.test(normalizedCommand)\n\n if (!hasStartArg) {\n return false\n }\n\n if (normalizedCommand.includes(\"copilot-relay\")) {\n return true\n }\n\n const usesNode = /(?:^|\\s|\\/)node(?:\\.exe)?(?:\\s|$)/i.test(normalizedCommand)\n const usesDistMain = /(?:^|\\s|\\/)dist\\/main\\.js(?:\\s|$)/.test(\n normalizedCommand,\n )\n\n return Boolean(\n usesNode\n && usesDistMain\n && normalizedCwd\n && normalizedCwd.split(\"/\").some((part) => part.includes(\"copilot-relay\")),\n )\n}\n\nconst isProcessAlive = (pid: number): boolean => {\n try {\n process.kill(pid, 0)\n return true\n } catch (error) {\n return isNodeErrno(error) && error.code === \"EPERM\"\n }\n}\n\nconst readRelayPidFile = async (): Promise<number | undefined> => {\n try {\n const content = await fs.readFile(paths.pidPath, \"utf8\")\n const trimmed = content.trim()\n if (!trimmed) {\n return undefined\n }\n\n if (trimmed.startsWith(\"{\")) {\n const payload = JSON.parse(trimmed) as Partial<RelayPidFile>\n return parsePid(payload.pid)\n }\n\n return parsePid(trimmed)\n } catch (error) {\n if (isNodeErrno(error) && error.code === \"ENOENT\") {\n return undefined\n }\n throw error\n }\n}\n\nexport const writeRelayPidFile = async (\n config: Pick<ProxyConfig, \"host\" | \"port\">,\n): Promise<void> => {\n await fs.mkdir(paths.appDir, { recursive: true })\n const payload: RelayPidFile = {\n host: config.host,\n pid: process.pid,\n port: config.port,\n startedAt: new Date().toISOString(),\n }\n await fs.writeFile(paths.pidPath, `${JSON.stringify(payload, null, 2)}\\n`, {\n mode: 0o600,\n })\n}\n\nexport const clearRelayPidFile = async (\n pid = process.pid,\n options: { force?: boolean } = {},\n): Promise<void> => {\n const currentPid = await readRelayPidFile()\n if (!options.force && currentPid !== undefined && currentPid !== pid) {\n return\n }\n\n await fs.unlink(paths.pidPath).catch((error: unknown) => {\n if (!isNodeErrno(error) || error.code !== \"ENOENT\") {\n throw error\n }\n })\n}\n\nconst getProcessCommand = async (pid: number): Promise<string | undefined> => {\n if (process.platform === \"win32\") {\n const output = await readCommandOutput(\"powershell.exe\", [\n \"-NoProfile\",\n \"-Command\",\n `Get-CimInstance Win32_Process -Filter \"ProcessId = ${pid}\" | Select-Object -ExpandProperty CommandLine`,\n ])\n return output.trim() || undefined\n }\n\n const output = await readCommandOutput(\"ps\", [\n \"-p\",\n String(pid),\n \"-o\",\n \"command=\",\n ])\n return output.trim() || undefined\n}\n\nconst getProcessCwd = async (pid: number): Promise<string | undefined> => {\n if (process.platform === \"win32\") {\n return undefined\n }\n\n const output = await readCommandOutput(\"lsof\", [\n \"-a\",\n \"-p\",\n String(pid),\n \"-d\",\n \"cwd\",\n \"-Fn\",\n ])\n return output\n .split(/\\r?\\n/)\n .find((line) => line.startsWith(\"n\"))\n ?.slice(1)\n}\n\nconst getPortListenerPids = async (port: number): Promise<Array<number>> => {\n if (process.platform === \"win32\") {\n return parsePidLines(await readCommandOutput(\"powershell.exe\", [\n \"-NoProfile\",\n \"-Command\",\n `Get-NetTCPConnection -LocalPort ${port} -State Listen -ErrorAction SilentlyContinue | Select-Object -ExpandProperty OwningProcess -Unique`,\n ]))\n }\n\n return parsePidLines(await readCommandOutput(\"lsof\", [\n \"-nP\",\n `-iTCP:${port}`,\n \"-sTCP:LISTEN\",\n \"-t\",\n ]))\n}\n\nconst getProcessList = async (): Promise<Array<{ command: string; pid: number }>> => {\n const output =\n process.platform === \"win32\" ?\n await readCommandOutput(\"powershell.exe\", [\n \"-NoProfile\",\n \"-Command\",\n \"Get-CimInstance Win32_Process | ForEach-Object { \\\"$($_.ProcessId)`t$($_.CommandLine)\\\" }\",\n ])\n : await readCommandOutput(\"ps\", [\"-axo\", \"pid=,command=\"])\n\n return output\n .split(/\\r?\\n/)\n .flatMap((line) => {\n const match =\n process.platform === \"win32\" ?\n line.match(/^(\\d+)\\t(.+)$/)\n : line.match(/^\\s*(\\d+)\\s+(.+)$/)\n const pid = parsePid(match?.[1])\n const command = match?.[2]?.trim()\n return pid && command ? [{ command, pid }] : []\n })\n}\n\nconst isRelayPid = async (pid: number): Promise<boolean> => {\n if (pid === process.pid || !isProcessAlive(pid)) {\n return false\n }\n\n const command = await getProcessCommand(pid)\n if (!command) {\n return false\n }\n\n return isRelayStartProcess(command, await getProcessCwd(pid))\n}\n\nconst findRelayProcessIds = async (\n config: Pick<ProxyConfig, \"port\">,\n): Promise<Array<number>> => {\n const candidates = new Set<number>()\n const storedPid = await readRelayPidFile()\n if (storedPid) {\n candidates.add(storedPid)\n }\n\n for (const pid of await getPortListenerPids(config.port)) {\n candidates.add(pid)\n }\n\n for (const { command, pid } of await getProcessList()) {\n if (pid === process.pid) {\n continue\n }\n\n if (command.includes(\"copilot-relay\") || command.includes(\"dist/main.js\")) {\n const cwd = await getProcessCwd(pid)\n if (isRelayStartProcess(command, cwd)) {\n candidates.add(pid)\n }\n }\n }\n\n const relayPids: Array<number> = []\n for (const pid of candidates) {\n if (await isRelayPid(pid)) {\n relayPids.push(pid)\n }\n }\n return [...new Set(relayPids)].sort((left, right) => left - right)\n}\n\nconst waitForExit = async (pid: number, timeoutMs: number): Promise<boolean> => {\n const deadline = Date.now() + timeoutMs\n while (Date.now() < deadline) {\n if (!isProcessAlive(pid)) {\n return true\n }\n await sleep(stopPollMs)\n }\n return !isProcessAlive(pid)\n}\n\nconst stopProcess = async (pid: number): Promise<void> => {\n if (!isProcessAlive(pid)) {\n return\n }\n\n log.info(`Stopping existing copilot-relay process pid=${pid}`)\n process.kill(pid, \"SIGTERM\")\n if (await waitForExit(pid, stopTimeoutMs)) {\n return\n }\n\n log.error(`copilot-relay process pid=${pid} did not stop; forcing termination`)\n process.kill(pid, \"SIGKILL\")\n if (!(await waitForExit(pid, stopTimeoutMs))) {\n throw new Error(`Could not stop copilot-relay process pid=${pid}`)\n }\n}\n\nexport const stopExistingRelay = async (\n config: Pick<ProxyConfig, \"port\">,\n): Promise<Array<number>> => {\n const relayPids = await findRelayProcessIds(config)\n if (relayPids.length === 0) {\n log.info(\"No existing copilot-relay instance found\")\n await clearRelayPidFile(0, { force: true })\n return []\n }\n\n for (const pid of relayPids) {\n await stopProcess(pid)\n }\n await clearRelayPidFile(0, { force: true })\n return relayPids\n}\n","// Optional writer for Claude Code settings so it points at the local proxy.\nimport fs from \"node:fs/promises\"\nimport path from \"node:path\"\n\ninterface ApplyClaudeConfigInput {\n baseUrl: string\n configPath: string\n}\n\ninterface ApplyClaudeResult {\n configPath: string\n changed: boolean\n created: boolean\n previousBaseUrl?: string\n}\n\n/**\n * Update `~/.claude/settings.json` so its env block points Claude Code at the\n * running proxy. Preserves all unrelated keys (model overrides, plugins,\n * marketplaces, etc.). Sets a dummy auth token only if none is present.\n */\nexport async function applyClaudeConfig(\n input: ApplyClaudeConfigInput,\n): Promise<ApplyClaudeResult> {\n const { configPath, baseUrl } = input\n\n let raw = \"\"\n let created = false\n try {\n raw = await fs.readFile(configPath, \"utf8\")\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n created = true\n } else {\n throw error\n }\n }\n\n let parsed: Record<string, unknown> = {}\n if (raw.trim().length > 0) {\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n parsed = {}\n }\n } catch {\n // Refuse to overwrite a malformed file; bail without changes.\n return { configPath, changed: false, created: false }\n }\n }\n\n const env: Record<string, unknown> =\n typeof parsed.env === \"object\"\n && parsed.env !== null\n && !Array.isArray(parsed.env)\n ? { ...(parsed.env as Record<string, unknown>) }\n : {}\n\n const previousBaseUrl =\n typeof env.ANTHROPIC_BASE_URL === \"string\"\n ? (env.ANTHROPIC_BASE_URL as string)\n : undefined\n\n env.ANTHROPIC_BASE_URL = baseUrl\n // Claude Code only requires a syntactically present auth token here; real\n // upstream authentication is handled by copilot-relay's Copilot token.\n if (typeof env.ANTHROPIC_AUTH_TOKEN !== \"string\" || !env.ANTHROPIC_AUTH_TOKEN) {\n env.ANTHROPIC_AUTH_TOKEN = \"dummy\"\n }\n\n const next: Record<string, unknown> = { ...parsed, env }\n const serialized = `${JSON.stringify(next, null, 2)}\\n`\n\n if (serialized === raw) {\n return { configPath, changed: false, created: false, previousBaseUrl }\n }\n\n await fs.mkdir(path.dirname(configPath), { recursive: true })\n await fs.writeFile(configPath, serialized)\n return { configPath, changed: true, created, previousBaseUrl }\n}\n","// Static process defaults that are not intended to be user-tuned.\nimport path from \"node:path\"\nimport os from \"node:os\"\n\n/**\n * Static defaults for copilot-relay. Previously these lived in\n * `~/.config/copilot-relay/settings.json`, but that file became an implicit\n * third source of truth alongside `~/.claude/settings.json`, which caused\n * subtle port-mismatch bugs. copilot-relay now relies on these defaults plus\n * CLI flags only.\n */\n\nexport const defaultHost = \"127.0.0.1\"\nexport const defaultPort = 4142\n\nexport const claudeConfigPath = path.join(\n os.homedir(),\n \".claude\",\n \"settings.json\",\n)\n","// Low-level GitHub Copilot HTTP client: adds required headers, retries transient failures, and logs timing.\nimport { randomUUID } from \"node:crypto\"\n\nimport { Agent, fetch as undiciFetch } from \"undici\"\n\nimport type { ProxyConfig } from \"~/lib/config\"\nimport { HTTPError, ProxyNotImplementedError } from \"~/lib/error\"\nimport { log } from \"~/lib/log\"\n\nconst copilotVersion = \"0.26.7\"\nconst editorPluginVersion = `copilot-chat/${copilotVersion}`\nconst userAgent = `GitHubCopilotChat/${copilotVersion}`\nconst apiVersion = \"2025-04-01\"\nconst maxFetchAttempts = 2\nexport const copilotRequestTimeoutMs = 180_000\nconst copilotDispatcher = new Agent({\n allowH2: false,\n connect: { allowH2: false },\n})\n\nexport interface CopilotProviderContext {\n baseUrl: string\n token: string | undefined\n vsCodeVersion: string\n}\n\nexport const getCopilotProviderContext = (\n config: ProxyConfig,\n): CopilotProviderContext => ({\n baseUrl: config.copilotBaseUrl,\n token: config.copilotToken,\n vsCodeVersion: config.vsCodeVersion,\n})\n\nexport interface FetchCopilotOptions {\n vision?: boolean\n initiator?: \"agent\" | \"user\"\n requestId?: string\n signal?: AbortSignal\n timeoutMs?: number\n}\n\ninterface CopilotRequestInit {\n body?: string\n headers?: RequestInit[\"headers\"]\n method?: string\n}\n\nconst shouldRetryResponse = (response: Response): boolean =>\n // Retry only transient upstream failures; 4xx responses may contain routing\n // signals, such as \"unsupported_api_for_model\", that callers need to inspect.\n response.status >= 500 && response.status <= 599\n\nexport const createCopilotRequestSignal = (\n signal?: AbortSignal,\n timeoutMs = copilotRequestTimeoutMs,\n): AbortSignal | undefined => {\n const signals = [\n signal,\n timeoutMs > 0 ? AbortSignal.timeout(timeoutMs) : undefined,\n ].filter((value): value is AbortSignal => value !== undefined)\n\n if (signals.length === 0) {\n return undefined\n }\n\n return signals.length === 1 ? signals[0] : AbortSignal.any(signals)\n}\n\nconst getAbortName = (value: unknown): string | undefined =>\n typeof value === \"object\"\n && value !== null\n && \"name\" in value\n && typeof value.name === \"string\" ?\n value.name\n : undefined\n\nconst isAbortLikeError = (error: unknown): boolean => {\n const name = getAbortName(error)\n return name === \"AbortError\" || name === \"TimeoutError\"\n}\n\nconst getErrorCode = (value: unknown): string | undefined =>\n typeof value === \"object\"\n && value !== null\n && \"code\" in value\n && typeof value.code === \"string\" ?\n value.code\n : undefined\n\nexport const isRetryableFetchError = (error: unknown): boolean =>\n getErrorCode(error) === \"ERR_HTTP2_INVALID_SESSION\"\n || (\n typeof error === \"object\"\n && error !== null\n && \"cause\" in error\n && getErrorCode(error.cause) === \"ERR_HTTP2_INVALID_SESSION\"\n )\n\nexport const toCopilotAbortHTTPError = (\n error: unknown,\n signal: AbortSignal | undefined,\n timeoutMs = copilotRequestTimeoutMs,\n): HTTPError | undefined => {\n if (!signal?.aborted && !isAbortLikeError(error)) {\n return undefined\n }\n\n const timedOut =\n getAbortName(signal?.reason) === \"TimeoutError\"\n || getAbortName(error) === \"TimeoutError\"\n const message =\n timedOut ?\n `Copilot upstream request timed out after ${Math.round(timeoutMs / 1000)}s.`\n : \"Client request cancelled before Copilot upstream completed.\"\n const code = timedOut ? \"upstream_timeout\" : \"request_cancelled\"\n\n return new HTTPError(\n message,\n new Response(JSON.stringify({ error: { message, code } }), {\n status: timedOut ? 504 : 499,\n headers: { \"content-type\": \"application/json\" },\n }),\n message,\n )\n}\n\nexport const readCopilotJson = async <T>(\n response: Response,\n signal: AbortSignal | undefined,\n timeoutMs = copilotRequestTimeoutMs,\n): Promise<T> => {\n try {\n return (await response.json()) as T\n } catch (error) {\n throw toCopilotAbortHTTPError(error, signal, timeoutMs) ?? error\n }\n}\n\nexport const readCopilotText = async (\n response: Response,\n signal: AbortSignal | undefined,\n timeoutMs = copilotRequestTimeoutMs,\n): Promise<string> => {\n try {\n return await response.text()\n } catch (error) {\n throw toCopilotAbortHTTPError(error, signal, timeoutMs) ?? error\n }\n}\n\nconst buildHeaders = (\n provider: CopilotProviderContext,\n init: CopilotRequestInit,\n options: FetchCopilotOptions,\n upstreamRequestId: string,\n): Record<string, string> => {\n const headers = new Headers(init.headers)\n\n headers.set(\"authorization\", `Bearer ${provider.token}`)\n headers.set(\"copilot-integration-id\", \"vscode-chat\")\n headers.set(\"editor-version\", `vscode/${provider.vsCodeVersion}`)\n headers.set(\"editor-plugin-version\", editorPluginVersion)\n headers.set(\"user-agent\", userAgent)\n headers.set(\"openai-intent\", \"conversation-panel\")\n headers.set(\"x-github-api-version\", apiVersion)\n headers.set(\"x-request-id\", upstreamRequestId)\n headers.set(\"x-vscode-user-agent-library-version\", \"electron-fetch\")\n\n if (options.vision) {\n headers.set(\"copilot-vision-request\", \"true\")\n }\n\n if (options.initiator) {\n headers.set(\"x-initiator\", options.initiator)\n }\n\n if (!headers.has(\"content-type\") && init.body !== undefined) {\n headers.set(\"content-type\", \"application/json\")\n }\n\n if (!headers.has(\"accept\")) {\n headers.set(\"accept\", \"application/json\")\n }\n\n return Object.fromEntries(headers.entries())\n}\n\nconst formatRequestId = (requestId: string | undefined): string =>\n requestId ? `request_id=${requestId} ` : \"\"\n\nconst logUpstreamLifecycle = (\n requestId: string | undefined,\n message: string,\n): void => {\n if (requestId) {\n log.info(`${formatRequestId(requestId)}${message}`)\n return\n }\n\n log.debug(message)\n}\n\nexport const fetchCopilot = async (\n provider: CopilotProviderContext,\n path: string,\n init: CopilotRequestInit,\n options: FetchCopilotOptions = {},\n) => {\n if (!provider.token) {\n throw new ProxyNotImplementedError(\n \"Copilot token is not configured for copilot-relay.\",\n )\n }\n\n const timeoutMs = options.timeoutMs ?? copilotRequestTimeoutMs\n const signal = createCopilotRequestSignal(options.signal, timeoutMs)\n let lastError: unknown\n\n for (let attempt = 1; attempt <= maxFetchAttempts; attempt++) {\n const upstreamRequestId = randomUUID()\n try {\n const started = performance.now()\n logUpstreamLifecycle(\n options.requestId,\n `send upstream method=${init.method ?? \"GET\"} path=${path} attempt=${attempt} upstream_request_id=${upstreamRequestId}`,\n )\n const response = await undiciFetch(`${provider.baseUrl}${path}`, {\n ...init,\n headers: buildHeaders(provider, init, options, upstreamRequestId),\n dispatcher: copilotDispatcher,\n signal,\n })\n const ms = Math.round(performance.now() - started)\n logUpstreamLifecycle(\n options.requestId,\n `return from upstream method=${init.method ?? \"GET\"} path=${path} status=${response.status} ms=${ms} attempt=${attempt} upstream_request_id=${upstreamRequestId}`,\n )\n log.debug(\n `${formatRequestId(options.requestId)}Copilot ${init.method ?? \"GET\"} ${path} -> ${response.status} ${ms}ms (attempt ${attempt}) upstream_request_id=${upstreamRequestId}`,\n )\n\n if (!shouldRetryResponse(response) || attempt === maxFetchAttempts) {\n return response\n }\n log.error(\n `${formatRequestId(options.requestId)}Copilot ${path} returned ${response.status}; retrying (${attempt}/${maxFetchAttempts}) upstream_request_id=${upstreamRequestId}`,\n )\n } catch (error) {\n const abortError = toCopilotAbortHTTPError(error, signal, timeoutMs)\n if (abortError) {\n logUpstreamLifecycle(\n options.requestId,\n `upstream failed method=${init.method ?? \"GET\"} path=${path} attempt=${attempt} upstream_request_id=${upstreamRequestId}`,\n )\n throw abortError\n }\n\n logUpstreamLifecycle(\n options.requestId,\n `upstream failed method=${init.method ?? \"GET\"} path=${path} attempt=${attempt} upstream_request_id=${upstreamRequestId}`,\n )\n lastError = error\n if (attempt === maxFetchAttempts) {\n log.error(\n `${formatRequestId(options.requestId)}Copilot ${path} request failed after ${attempt} attempts upstream_request_id=${upstreamRequestId}`,\n error,\n )\n throw error\n }\n log.error(\n `${formatRequestId(options.requestId)}Copilot ${path} request failed; retrying (${attempt}/${maxFetchAttempts}) upstream_request_id=${upstreamRequestId}`,\n error,\n )\n }\n }\n\n throw lastError\n}\n","// Internal conversion between Copilot Responses API payloads and chat-completion-like results.\nimport { createHash, randomUUID } from \"node:crypto\"\n\nimport type {\n ChatCompletionChunk,\n ChatCompletionResponse,\n ChatCompletionsPayload,\n ContentPart,\n Message,\n Tool,\n} from \"~/copilot/types\"\n\nimport { sanitizeUserIdentifier } from \"./chat\"\n\nexport interface ResponseStreamEventMessage {\n data?: string\n event?: string\n}\n\nexport interface ResponsesApiResponse {\n id: string\n created_at: number\n model: string\n output: Array<ResponsesOutputItem>\n reasoning?: ResponsesReasoningSummaryContainer | null\n usage?: {\n input_tokens: number\n input_tokens_details?: {\n cached_tokens?: number\n }\n output_tokens: number\n output_tokens_details?: {\n reasoning_tokens?: number\n }\n total_tokens: number\n }\n incomplete_details?: {\n reason?: string | null\n } | null\n}\n\nexport type ResponsesReasoningEffort =\n | \"none\"\n | \"low\"\n | \"medium\"\n | \"high\"\n | \"xhigh\"\n | \"max\"\n\ntype ResponsesInput = string | Array<ResponsesInputItem>\n\ntype ResponsesInputItem =\n | ResponsesMessageInput\n | ResponsesFunctionCallInput\n | ResponsesFunctionCallOutputInput\n\ntype ResponsesMessageInput = {\n role: \"user\" | \"assistant\" | \"system\" | \"developer\"\n content: string | Array<ResponsesInputContentPart>\n}\n\ntype ResponsesInputContentPart =\n | {\n type: \"input_text\"\n text: string\n }\n | {\n type: \"input_image\"\n image_url: string\n detail: \"low\" | \"high\" | \"auto\"\n }\n\ntype ResponsesFunctionCallInput = {\n type: \"function_call\"\n call_id: string\n name: string\n arguments: string\n}\n\ntype ResponsesFunctionCallOutputInput = {\n type: \"function_call_output\"\n call_id: string\n output: string\n}\n\ntype ResponsesToolChoice =\n | \"none\"\n | \"auto\"\n | \"required\"\n | { type: \"function\"; name: string }\n\nexport interface ResponsesRequestPayload {\n model: string\n input: ResponsesInput\n stream?: boolean | null\n max_output_tokens?: number | null\n temperature?: number | null\n top_p?: number | null\n user?: string | null\n prompt_cache_key?: string | null\n reasoning?: {\n effort: ResponsesReasoningEffort\n }\n tools?: Array<ResponsesTool>\n tool_choice?: ResponsesToolChoice | null\n text?: {\n format: {\n type: \"json_object\"\n }\n }\n}\n\ninterface ResponsesTool {\n type: \"function\"\n name: string\n description?: string\n parameters: Record<string, unknown>\n}\n\ntype ResponsesOutputItem =\n | ResponsesMessageOutputItem\n | ResponsesFunctionCallOutputItem\n | ResponsesReasoningOutputItem\n\ninterface ResponsesMessageOutputItem {\n type: \"message\"\n role: \"assistant\"\n content: Array<ResponsesMessageContentPart>\n}\n\ninterface ResponsesMessageContentPart {\n type: \"output_text\"\n text: string\n}\n\ninterface ResponsesFunctionCallOutputItem {\n type: \"function_call\"\n call_id: string\n name: string\n arguments: string\n}\n\ninterface ResponsesReasoningOutputItem {\n type: \"reasoning\"\n summary?: ResponsesReasoningSummary\n}\n\ntype ResponsesReasoningSummary =\n | string\n | Array<ResponsesReasoningSummaryPart>\n | null\n\ntype ResponsesReasoningSummaryPart = {\n type?: string\n text?: string\n}\n\ninterface ResponsesReasoningSummaryContainer {\n summary?: ResponsesReasoningSummary\n}\n\ninterface ResponsesStreamEnvelope {\n type: string\n response?: {\n id: string\n created_at: number\n model: string\n usage?: ResponsesApiResponse[\"usage\"]\n output?: Array<ResponsesOutputItem>\n reasoning?: ResponsesReasoningSummaryContainer | null\n incomplete_details?: ResponsesApiResponse[\"incomplete_details\"]\n }\n item?:\n | Partial<ResponsesMessageOutputItem>\n | Partial<ResponsesFunctionCallOutputItem>\n | Partial<ResponsesReasoningOutputItem>\n output_index?: number\n delta?: string\n text?: string\n arguments?: string\n}\n\ninterface ResponseTranslationState {\n responseId: string\n createdAt: number\n model: string\n started: boolean\n reasoningTextSent: boolean\n outputTextByIndex: Record<number, string>\n toolArgumentsByIndex: Record<number, string>\n toolStartedByIndex: Record<number, boolean>\n}\n\ninterface CreateChunkOptions {\n delta: ChatCompletionChunk[\"choices\"][0][\"delta\"]\n finishReason?: ChatCompletionChunk[\"choices\"][0][\"finish_reason\"]\n usage?: ChatCompletionChunk[\"usage\"]\n}\n\n// /models does not tell us which API surface a model requires, so keep the\n// Responses-only allowlist narrow and suffix-tolerant. gpt-5.5 and the gpt-5.6\n// family (luna/sol/terra) reject /chat/completions with unsupported_api_for_model\n// and must go straight to /responses.\nconst responsesOnlyModelPattern = /^(?:gpt-5\\.5|gpt-5\\.6)(?:-|$)/i\n\nexport function shouldUseResponsesApiForModel(model: string): boolean {\n return responsesOnlyModelPattern.test(model)\n}\n\nexport function buildResponsesRequestPayload(\n payload: ChatCompletionsPayload,\n reasoningEffort: ResponsesReasoningEffort | undefined,\n): ResponsesRequestPayload {\n // Responses API uses an `input` tree instead of chat `messages`, but the\n // rest of the bridge still reasons in chat-completion terms. Keep this as\n // the single boundary where chat payloads become Responses payloads.\n return {\n model: payload.model,\n input: translateMessagesToResponsesInput(payload.messages),\n stream: payload.stream,\n max_output_tokens: payload.max_tokens,\n temperature: payload.temperature,\n top_p: payload.top_p,\n user: sanitizeUserIdentifier(payload.user),\n // Copilot /responses only returns prompt cache hits when a stable\n // prompt_cache_key pins repeated requests to the same backend. Without it,\n // cached_tokens randomly drops to 0 across turns even for identical\n // prefixes (measured). Derive a per-conversation key so a Claude Code\n // session keeps hitting its own warm cache while staying isolated from\n // other sessions.\n prompt_cache_key: deriveResponsesCacheKey(payload),\n tools: translateTools(payload.tools),\n tool_choice: translateToolChoice(payload.tool_choice),\n reasoning: reasoningEffort ? { effort: reasoningEffort } : undefined,\n text:\n payload.response_format?.type === \"json_object\" ?\n { format: { type: \"json_object\" } }\n : undefined,\n }\n}\n\nfunction deriveResponsesCacheKey(\n payload: ChatCompletionsPayload,\n): string | undefined {\n // Prefer the client-supplied conversation id (Claude Code sends a stable\n // metadata.user_id per session). Fall back to a hash of the system prompt so\n // even clients without a user id still route a stable prefix to one cache.\n const user = sanitizeUserIdentifier(payload.user)\n if (user) {\n return `cr-${createHash(\"sha256\").update(user).digest(\"hex\").slice(0, 32)}`\n }\n\n const systemPrompt = payload.messages.find((message) => message.role === \"system\")\n const systemText =\n typeof systemPrompt?.content === \"string\" ? systemPrompt.content\n : Array.isArray(systemPrompt?.content) ?\n systemPrompt.content\n .map((part) => (part.type === \"text\" ? part.text : \"\"))\n .join(\"\")\n : \"\"\n\n if (!systemText) {\n return undefined\n }\n\n return `cr-sys-${createHash(\"sha256\").update(systemText).digest(\"hex\").slice(0, 32)}`\n}\n\nexport function translateResponsesToChatCompletion(\n response: ResponsesApiResponse,\n): ChatCompletionResponse {\n const assistantMessages = response.output.filter(\n (item): item is ResponsesMessageOutputItem => item.type === \"message\",\n )\n const functionCalls = response.output.filter(\n (item): item is ResponsesFunctionCallOutputItem =>\n item.type === \"function_call\",\n )\n\n const content = assistantMessages\n .flatMap((item) => item.content)\n .map((part) => part.text)\n .join(\"\")\n const reasoningText = getResponsesReasoningText(response)\n\n // Merge Responses output items back into one chat-completion choice so the\n // Claude translation layer can stay shared for /chat/completions and\n // /responses upstream calls.\n return {\n id: response.id,\n object: \"chat.completion\",\n created: response.created_at,\n model: response.model,\n choices: [\n {\n index: 0,\n message: {\n role: \"assistant\",\n content: content || null,\n ...(reasoningText && { reasoning_text: reasoningText }),\n ...(functionCalls.length > 0 && {\n tool_calls: functionCalls.map((toolCall) => ({\n id: toolCall.call_id,\n type: \"function\" as const,\n function: {\n name: toolCall.name,\n arguments: toolCall.arguments,\n },\n })),\n }),\n },\n logprobs: null,\n finish_reason: getFinishReason(response, functionCalls.length > 0),\n },\n ],\n usage: translateUsage(response.usage),\n }\n}\n\nexport async function* translateResponsesStreamToChatCompletionStream(\n responseStream: AsyncIterable<ResponseStreamEventMessage>,\n): AsyncGenerator<ResponseStreamEventMessage> {\n // Responses streams can send deltas, done snapshots, and a final completed\n // payload. Track emitted suffixes so chat clients do not receive duplicates.\n const state: ResponseTranslationState = {\n responseId: randomUUID(),\n createdAt: Math.floor(Date.now() / 1000),\n model: \"\",\n started: false,\n reasoningTextSent: false,\n outputTextByIndex: {},\n toolArgumentsByIndex: {},\n toolStartedByIndex: {},\n }\n\n for await (const rawEvent of responseStream) {\n if (!rawEvent.data || rawEvent.data === \"[DONE]\") {\n continue\n }\n\n const event = JSON.parse(rawEvent.data) as ResponsesStreamEnvelope\n\n if (event.response) {\n state.responseId = event.response.id\n state.createdAt = event.response.created_at\n state.model = event.response.model\n }\n\n if (event.type === \"response.output_item.added\") {\n const chunk = handleOutputItemAdded(state, event)\n if (chunk) {\n yield chunk\n }\n continue\n }\n\n if (event.type === \"response.output_item.done\") {\n for (const chunk of handleOutputItemDone(state, event)) {\n yield chunk\n }\n continue\n }\n\n if (event.type === \"response.reasoning_summary_text.delta\") {\n if (event.delta) {\n yield createRoleChunk(state)\n yield createChunk(state, { delta: { reasoning_text: event.delta } })\n state.reasoningTextSent = true\n }\n continue\n }\n\n if (event.type === \"response.output_text.delta\") {\n const outputIndex = event.output_index ?? 0\n state.outputTextByIndex[outputIndex] = `${state.outputTextByIndex[outputIndex] ?? \"\"}${event.delta ?? \"\"}`\n yield createRoleChunk(state)\n yield createChunk(state, { delta: { content: event.delta } })\n continue\n }\n\n if (event.type === \"response.output_text.done\") {\n const outputIndex = event.output_index ?? 0\n const content = getMissingSuffix(\n state.outputTextByIndex[outputIndex] ?? \"\",\n event.text,\n )\n if (content) {\n state.outputTextByIndex[outputIndex] = `${state.outputTextByIndex[outputIndex] ?? \"\"}${content}`\n yield createRoleChunk(state)\n yield createChunk(state, { delta: { content } })\n }\n continue\n }\n\n if (event.type === \"response.function_call_arguments.delta\") {\n if (event.output_index === undefined) {\n continue\n }\n\n state.toolArgumentsByIndex[event.output_index] = `${state.toolArgumentsByIndex[event.output_index] ?? \"\"}${event.delta ?? \"\"}`\n yield createRoleChunk(state)\n yield createChunk(state, {\n delta: {\n tool_calls: [\n {\n index: event.output_index,\n type: \"function\",\n function: {\n arguments: event.delta ?? \"\",\n },\n },\n ],\n },\n })\n continue\n }\n\n if (event.type === \"response.function_call_arguments.done\") {\n if (event.output_index === undefined) {\n continue\n }\n\n const content = getMissingSuffix(\n state.toolArgumentsByIndex[event.output_index] ?? \"\",\n event.arguments,\n )\n if (content) {\n state.toolArgumentsByIndex[event.output_index] = `${state.toolArgumentsByIndex[event.output_index] ?? \"\"}${content}`\n yield createRoleChunk(state)\n yield createChunk(state, {\n delta: {\n tool_calls: [\n {\n index: event.output_index,\n type: \"function\",\n function: { arguments: content },\n },\n ],\n },\n })\n }\n continue\n }\n\n if (event.type === \"response.completed\") {\n if (!event.response) {\n continue\n }\n\n const reasoningText = getResponsesReasoningText({\n output: event.response.output ?? [],\n reasoning: event.response.reasoning,\n })\n if (reasoningText && !state.reasoningTextSent) {\n yield createRoleChunk(state)\n yield createChunk(state, { delta: { reasoning_text: reasoningText } })\n state.reasoningTextSent = true\n }\n\n yield createChunk(\n {\n ...state,\n responseId: event.response.id,\n createdAt: event.response.created_at,\n model: event.response.model,\n },\n {\n delta: {},\n finishReason: getFinishReason(\n {\n output: event.response.output ?? [],\n incomplete_details: event.response.incomplete_details,\n },\n (event.response.output ?? []).some(\n (item) => item.type === \"function_call\",\n ),\n ),\n usage: translateUsage(event.response.usage),\n },\n )\n yield { data: \"[DONE]\" }\n return\n }\n }\n}\n\nfunction handleOutputItemAdded(\n state: ResponseTranslationState,\n event: ResponsesStreamEnvelope,\n): ResponseStreamEventMessage | undefined {\n if (event.item?.type === \"message\") {\n return createRoleChunk(state)\n }\n\n if (event.item?.type === \"reasoning\") {\n const reasoningText = getSummaryText(event.item.summary)\n if (!reasoningText) {\n return undefined\n }\n\n state.reasoningTextSent = true\n return createChunk(state, { delta: { reasoning_text: reasoningText } })\n }\n\n if (\n event.item?.type === \"function_call\"\n && event.output_index !== undefined\n ) {\n const initialArguments = event.item.arguments ?? \"\"\n state.started = true\n state.toolStartedByIndex[event.output_index] = true\n state.toolArgumentsByIndex[event.output_index] = initialArguments\n return createChunk(state, {\n delta: {\n role: \"assistant\",\n tool_calls: [\n {\n index: event.output_index,\n id: event.item.call_id,\n type: \"function\",\n function: {\n name: event.item.name,\n arguments: initialArguments,\n },\n },\n ],\n },\n })\n }\n\n return undefined\n}\n\nfunction handleOutputItemDone(\n state: ResponseTranslationState,\n event: ResponsesStreamEnvelope,\n): Array<ResponseStreamEventMessage> {\n if (event.item?.type === \"reasoning\") {\n const reasoningText = getSummaryText(event.item.summary)\n if (!reasoningText || state.reasoningTextSent) {\n return []\n }\n\n state.reasoningTextSent = true\n return [createChunk(state, { delta: { reasoning_text: reasoningText } })]\n }\n\n if (event.item?.type === \"message\") {\n const outputIndex = event.output_index ?? 0\n const fullText = getMessageOutputText(event.item.content)\n const content = getMissingSuffix(\n state.outputTextByIndex[outputIndex] ?? \"\",\n fullText,\n )\n if (!content) {\n return []\n }\n\n state.outputTextByIndex[outputIndex] = `${state.outputTextByIndex[outputIndex] ?? \"\"}${content}`\n return [createRoleChunk(state), createChunk(state, { delta: { content } })]\n }\n\n if (\n event.item?.type === \"function_call\"\n && event.output_index !== undefined\n ) {\n const outputIndex = event.output_index\n const chunks: Array<ResponseStreamEventMessage> = []\n\n if (!state.toolStartedByIndex[outputIndex]) {\n const initialArguments = event.item.arguments ?? \"\"\n state.started = true\n state.toolStartedByIndex[outputIndex] = true\n state.toolArgumentsByIndex[outputIndex] = initialArguments\n chunks.push(\n createChunk(state, {\n delta: {\n role: \"assistant\",\n tool_calls: [\n {\n index: outputIndex,\n id: event.item.call_id,\n type: \"function\",\n function: {\n name: event.item.name,\n arguments: initialArguments,\n },\n },\n ],\n },\n }),\n )\n return chunks\n }\n\n const content = getMissingSuffix(\n state.toolArgumentsByIndex[outputIndex] ?? \"\",\n event.item.arguments,\n )\n if (content) {\n state.toolArgumentsByIndex[outputIndex] = `${state.toolArgumentsByIndex[outputIndex] ?? \"\"}${content}`\n chunks.push(\n createRoleChunk(state),\n createChunk(state, {\n delta: {\n tool_calls: [\n {\n index: outputIndex,\n type: \"function\",\n function: { arguments: content },\n },\n ],\n },\n }),\n )\n }\n\n return chunks\n }\n\n return []\n}\n\nfunction createRoleChunk(\n state: ResponseTranslationState,\n): ResponseStreamEventMessage {\n if (state.started) {\n return { data: \"\" }\n }\n\n state.started = true\n return createChunk(state, { delta: { role: \"assistant\" } })\n}\n\nfunction createChunk(\n state: ResponseTranslationState,\n { delta, finishReason = null, usage }: CreateChunkOptions,\n): ResponseStreamEventMessage {\n return {\n data: JSON.stringify({\n id: state.responseId,\n object: \"chat.completion.chunk\",\n created: state.createdAt,\n model: state.model,\n choices: [\n {\n index: 0,\n delta,\n finish_reason: finishReason,\n logprobs: null,\n },\n ],\n usage,\n } satisfies ChatCompletionChunk),\n }\n}\n\nfunction translateMessagesToResponsesInput(\n messages: Array<Message>,\n): ResponsesInput {\n // Copilot accepts a bare string for the simplest single-user prompt, but\n // multi-turn, tool, or image conversations need structured input items.\n const items = messages.flatMap((message) => translateMessage(message))\n\n if (\n items.length === 1\n && \"role\" in items[0]\n && items[0].role === \"user\"\n && typeof items[0].content === \"string\"\n ) {\n return items[0].content\n }\n\n return items\n}\n\nfunction translateMessage(message: Message): Array<ResponsesInputItem> {\n if (message.role === \"tool\") {\n return [\n {\n type: \"function_call_output\",\n call_id: message.tool_call_id ?? \"\",\n output: stringifyToolOutput(message.content),\n },\n ]\n }\n\n const translated: Array<ResponsesInputItem> = []\n\n if (hasContent(message.content)) {\n translated.push({\n role: message.role,\n content: translateContent(message.content),\n })\n }\n\n if (message.role === \"assistant\" && message.tool_calls) {\n translated.push(\n ...message.tool_calls.map((toolCall) => ({\n type: \"function_call\" as const,\n call_id: toolCall.id,\n name: toolCall.function.name,\n arguments: toolCall.function.arguments,\n })),\n )\n }\n\n return translated\n}\n\nfunction hasContent(content: Message[\"content\"]): boolean {\n if (content === null) {\n return false\n }\n\n if (typeof content === \"string\") {\n return content.length > 0\n }\n\n return content.length > 0\n}\n\nfunction translateContent(\n content: Message[\"content\"],\n): ResponsesMessageInput[\"content\"] {\n if (typeof content === \"string\") {\n return content\n }\n\n if (!content || content.length === 0) {\n return \"\"\n }\n\n return content.map((part) => translateContentPart(part))\n}\n\nfunction translateContentPart(part: ContentPart): ResponsesInputContentPart {\n if (part.type === \"text\") {\n return {\n type: \"input_text\",\n text: part.text,\n }\n }\n\n return {\n type: \"input_image\",\n image_url: part.image_url.url,\n detail: part.image_url.detail ?? \"auto\",\n }\n}\n\nfunction stringifyToolOutput(content: Message[\"content\"]): string {\n if (typeof content === \"string\") {\n return content\n }\n\n if (!content) {\n return \"\"\n }\n\n const text = content\n .filter(\n (part): part is Extract<ContentPart, { type: \"text\" }> =>\n part.type === \"text\",\n )\n .map((part) => part.text)\n .join(\"\\n\\n\")\n\n return text || JSON.stringify(content)\n}\n\nfunction translateTools(\n tools: Array<Tool> | null | undefined,\n): Array<ResponsesTool> | undefined {\n if (!tools) {\n return undefined\n }\n\n return tools.map((tool) => ({\n type: \"function\",\n name: tool.function.name,\n description: tool.function.description,\n parameters: tool.function.parameters,\n }))\n}\n\nfunction translateToolChoice(\n toolChoice: ChatCompletionsPayload[\"tool_choice\"],\n): ResponsesToolChoice | undefined {\n if (!toolChoice) {\n return undefined\n }\n\n if (typeof toolChoice === \"string\") {\n return toolChoice\n }\n\n return {\n type: \"function\",\n name: toolChoice.function.name,\n }\n}\n\nfunction translateUsage(\n usage: ResponsesApiResponse[\"usage\"] | undefined,\n): ChatCompletionResponse[\"usage\"] | undefined {\n if (!usage) {\n return undefined\n }\n\n return {\n prompt_tokens: usage.input_tokens,\n completion_tokens: usage.output_tokens,\n total_tokens: usage.total_tokens,\n ...(usage.input_tokens_details?.cached_tokens !== undefined && {\n prompt_tokens_details: {\n cached_tokens: usage.input_tokens_details.cached_tokens,\n },\n }),\n }\n}\n\nfunction getMessageOutputText(\n content: ResponsesMessageOutputItem[\"content\"] | undefined,\n): string | undefined {\n const text = content\n ?.filter((part) => part.type === \"output_text\")\n .map((part) => part.text)\n .join(\"\")\n\n return text || undefined\n}\n\nfunction getMissingSuffix(\n alreadySent: string,\n finalValue: string | undefined,\n): string | undefined {\n // Responses \"done\" events often repeat the full text/arguments after deltas;\n // emit only the suffix that has not already been forwarded to the chat stream.\n if (!finalValue) {\n return undefined\n }\n\n if (!alreadySent) {\n return finalValue\n }\n\n if (!finalValue.startsWith(alreadySent)) {\n return undefined\n }\n\n const suffix = finalValue.slice(alreadySent.length)\n return suffix || undefined\n}\n\nfunction getResponsesReasoningText(\n response: Pick<ResponsesApiResponse, \"output\" | \"reasoning\">,\n): string | undefined {\n const parts = [\n getSummaryText(response.reasoning?.summary),\n ...response.output\n .filter((item): item is ResponsesReasoningOutputItem => item.type === \"reasoning\")\n .map((item) => getSummaryText(item.summary)),\n ].filter((part): part is string => Boolean(part))\n\n return parts.length > 0 ? parts.join(\"\\n\\n\") : undefined\n}\n\nfunction getSummaryText(summary: ResponsesReasoningSummary | undefined): string | undefined {\n if (typeof summary === \"string\") {\n return summary || undefined\n }\n\n if (!Array.isArray(summary)) {\n return undefined\n }\n\n const text = summary\n .map((part) => part.text)\n .filter((part): part is string => Boolean(part))\n .join(\"\\n\\n\")\n\n return text || undefined\n}\n\nfunction getFinishReason(\n response: Pick<ResponsesApiResponse, \"output\" | \"incomplete_details\">,\n hasFunctionCalls: boolean,\n): \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" {\n if (hasFunctionCalls) {\n return \"tool_calls\"\n }\n\n if (response.incomplete_details?.reason?.includes(\"max_output_tokens\")) {\n return \"length\"\n }\n\n return \"stop\"\n}\n","// Internal Copilot chat API wrapper used by the Claude route and startup preflight.\nimport { events } from \"fetch-event-stream\"\n\nimport type { ProxyConfig } from \"~/lib/config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { log } from \"~/lib/log\"\nimport { defaultReasoningEffort } from \"~/lib/models\"\nimport { routeModelId } from \"~/lib/models\"\nimport { runtimeState } from \"~/lib/state\"\nimport {\n createCopilotRequestSignal,\n fetchCopilot,\n getCopilotProviderContext,\n readCopilotJson,\n readCopilotText,\n} from \"~/copilot/client\"\nimport type {\n ChatCompletionResponse,\n ChatCompletionsPayload,\n} from \"~/copilot/types\"\n\nimport {\n buildResponsesRequestPayload,\n shouldUseResponsesApiForModel,\n translateResponsesStreamToChatCompletionStream,\n translateResponsesToChatCompletion,\n type ResponsesApiResponse,\n type ResponsesReasoningEffort,\n type ResponsesRequestPayload,\n} from \"./responses\"\n\nconst usesMaxCompletionTokens = (modelId: string): boolean =>\n modelId.startsWith(\"gpt-5\")\n\nconst continuePrefillPrompt =\n \"Continue the assistant response from the previous assistant message.\"\n\ntype ClientKind = \"claude\" | \"generic\"\n\ninterface CreateChatCompletionsOptions {\n client?: ClientKind\n requestId?: string\n requestedModel?: string\n requestedThinkEffort?: string\n requestedThinking?: string\n signal?: AbortSignal\n timeoutMs?: number\n}\n\nconst maxUserLength = 64\n\nexport const sanitizeReasoningEffortForModel = (\n _modelId: string,\n reasoningEffort: ChatCompletionsPayload[\"reasoning_effort\"],\n): ChatCompletionsPayload[\"reasoning_effort\"] => {\n return reasoningEffort ?? undefined\n}\n\nconst getRequestedReasoningEffort = (\n payload: ChatCompletionsPayload,\n): ChatCompletionsPayload[\"reasoning_effort\"] => {\n // Configured think effort wins over client input so startup preflight and\n // actual Claude Code traffic exercise the same upstream behavior.\n return sanitizeReasoningEffortForModel(\n payload.model,\n runtimeState.thinkEffort ?? defaultReasoningEffort,\n )\n}\n\nexport const sanitizeUserIdentifier = (\n user: string | null | undefined,\n): string | undefined => {\n if (!user) {\n return undefined\n }\n\n return user.slice(0, maxUserLength)\n}\n\ntype ChatCompletionsRequestPayload = Omit<\n ChatCompletionsPayload,\n \"max_tokens\"\n> & {\n max_tokens?: number | null\n max_completion_tokens?: number | null\n}\n\nconst buildRequestPayload = (\n payload: ChatCompletionsPayload,\n): ChatCompletionsRequestPayload => {\n const requestedReasoningEffort = getRequestedReasoningEffort(payload)\n\n if (\n !usesMaxCompletionTokens(payload.model)\n || payload.max_tokens === null\n || payload.max_tokens === undefined\n ) {\n const sanitizedPayload = {\n ...payload,\n reasoning_effort: requestedReasoningEffort,\n user: sanitizeUserIdentifier(payload.user),\n }\n\n return sanitizedPayload\n }\n\n // GPT-5-class Copilot endpoints reject max_tokens and require the newer\n // max_completion_tokens field; older models still use max_tokens.\n return {\n ...payload,\n max_tokens: undefined,\n max_completion_tokens: payload.max_tokens,\n reasoning_effort: requestedReasoningEffort,\n user: sanitizeUserIdentifier(payload.user),\n }\n}\n\nconst normalizeFinalAssistantPrefill = (\n payload: ChatCompletionsPayload,\n): ChatCompletionsPayload => {\n const lastMessage = payload.messages.at(-1)\n if (lastMessage?.role !== \"assistant\") {\n return payload\n }\n\n const messages = [...payload.messages]\n if (typeof lastMessage.content !== \"string\") {\n messages.pop()\n return { ...payload, messages }\n }\n\n const content = lastMessage.content.trimEnd()\n if (!content) {\n messages.pop()\n return { ...payload, messages }\n }\n\n messages[messages.length - 1] = {\n ...lastMessage,\n content,\n }\n messages.push({ role: \"user\", content: continuePrefillPrompt })\n return { ...payload, messages }\n}\n\nconst isAgentInitiator = (\n messages: ChatCompletionsPayload[\"messages\"],\n): \"agent\" | \"user\" =>\n messages.some((msg) => msg.role === \"assistant\" || msg.role === \"tool\") ?\n \"agent\"\n : \"user\"\n\nconst messagesIncludeImage = (\n messages: ChatCompletionsPayload[\"messages\"],\n): boolean =>\n messages.some(\n (msg) =>\n typeof msg.content !== \"string\"\n && msg.content?.some((part) => part.type === \"image_url\"),\n )\n\nexport const createChatCompletions = async (\n config: ProxyConfig,\n payload: ChatCompletionsPayload,\n options: CreateChatCompletionsOptions = {},\n) => {\n const client = options.client ?? \"generic\"\n const requestedModel = options.requestedModel ?? payload.model\n const requestedThinkEffort =\n options.requestedThinkEffort ?? payload.reasoning_effort ?? \"none\"\n const requestedThinking = options.requestedThinking ?? \"none\"\n const signal = createCopilotRequestSignal(options.signal, options.timeoutMs)\n const upstreamModelId = routeModelId(payload.model)\n const upstreamPayload =\n upstreamModelId === payload.model ? payload : { ...payload, model: upstreamModelId }\n const useResponsesApi = shouldUseResponsesApiForModel(upstreamPayload.model)\n const compatiblePayload =\n useResponsesApi ? upstreamPayload : normalizeFinalAssistantPrefill(upstreamPayload)\n const provider = getCopilotProviderContext(config)\n const enableVision = messagesIncludeImage(compatiblePayload.messages)\n const initiator = isAgentInitiator(compatiblePayload.messages)\n const requestPayload = buildRequestPayload(compatiblePayload)\n log.debug(\n [\n \"Model request\",\n `client=${client}`,\n `requested_model=${requestedModel}`,\n ...(options.requestId ? [`request_id=${options.requestId}`] : []),\n `upstream_model=${compatiblePayload.model}`,\n `requested_think_effort=${requestedThinkEffort}`,\n `requested_thinking=${requestedThinking}`,\n `effective_think_effort=${requestPayload.reasoning_effort ?? \"none\"}`,\n ].join(\" \"),\n )\n log.debug(\"Full request payload\", {\n payload: requestPayload,\n })\n // Choose the Copilot API surface after model routing, because aliases can\n // resolve to a Responses-only upstream model even when the client asked for a\n // generic Claude model name.\n if (useResponsesApi) {\n return createResponses(provider, compatiblePayload, {\n vision: enableVision,\n initiator,\n requestId: options.requestId,\n signal,\n timeoutMs: options.timeoutMs,\n })\n }\n\n const response = await fetchCopilot(\n provider,\n \"/chat/completions\",\n {\n method: \"POST\",\n headers: {\n accept: compatiblePayload.stream ? \"text/event-stream\" : \"application/json\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(requestPayload),\n },\n {\n vision: enableVision,\n initiator,\n requestId: options.requestId,\n signal,\n timeoutMs: options.timeoutMs,\n },\n )\n\n if (!response.ok) {\n if (await shouldRetryWithResponses(response, signal, options.timeoutMs)) {\n return createResponses(provider, compatiblePayload, {\n vision: enableVision,\n initiator,\n requestId: options.requestId,\n signal,\n timeoutMs: options.timeoutMs,\n })\n }\n\n const detail = await logUpstreamError(\"Failed to create chat completions\", response, {\n model: payload.model,\n request: requestPayload,\n route: \"/chat/completions\",\n requestId: options.requestId,\n }, signal, options.timeoutMs)\n throw new HTTPError(\n \"Failed to create chat completions\",\n response,\n detail,\n )\n }\n\n if (compatiblePayload.stream) {\n return events(response)\n }\n\n return readCopilotJson<ChatCompletionResponse>(\n response,\n signal,\n options.timeoutMs,\n )\n}\n\nasync function createResponses(\n provider: ReturnType<typeof getCopilotProviderContext>,\n payload: ChatCompletionsPayload,\n options: {\n vision: boolean\n initiator: \"agent\" | \"user\"\n requestId?: string\n signal?: AbortSignal\n timeoutMs?: number\n },\n) {\n const reasoningEffort = getRequestedReasoningEffort(\n payload,\n ) as ResponsesReasoningEffort | undefined\n const requestPayload = buildResponsesRequestPayload(payload, reasoningEffort)\n\n const response = await fetchCopilot(\n provider,\n \"/responses\",\n {\n method: \"POST\",\n headers: {\n accept: payload.stream ? \"text/event-stream\" : \"application/json\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(requestPayload),\n },\n {\n vision: options.vision,\n initiator: options.initiator,\n requestId: options.requestId,\n signal: options.signal,\n timeoutMs: options.timeoutMs,\n },\n )\n\n if (!response.ok) {\n const detail = await logUpstreamError(\"Failed to create responses\", response, {\n model: payload.model,\n request: requestPayload,\n route: \"/responses\",\n requestId: options.requestId,\n }, options.signal, options.timeoutMs)\n throw new HTTPError(\n \"Failed to create responses\",\n response,\n detail,\n )\n }\n\n if (payload.stream) {\n return translateResponsesStreamToChatCompletionStream(events(response))\n }\n\n return translateResponsesToChatCompletion(\n await readCopilotJson<ResponsesApiResponse>(\n response,\n options.signal,\n options.timeoutMs,\n ),\n )\n}\n\nasync function logUpstreamError(\n message: string,\n response: Response,\n context: {\n model: string\n request?: ChatCompletionsRequestPayload | ResponsesRequestPayload\n route: string\n requestId?: string\n },\n signal?: AbortSignal,\n timeoutMs?: number,\n): Promise<string | undefined> {\n const errorBody = await readCopilotText(\n response.clone(),\n signal,\n timeoutMs,\n ).catch(() => \"\")\n const detail = getUpstreamErrorDetail(response, errorBody)\n\n log.error(`${message}: route=${context.route} model=${context.model} status=${response.status}${context.requestId ? ` request_id=${context.requestId}` : \"\"}`, {\n message,\n route: context.route,\n model: context.model,\n requestId: context.requestId,\n request: context.request,\n response: {\n status: response.status,\n statusText: response.statusText || undefined,\n url: response.url || undefined,\n headers: Object.fromEntries(response.headers.entries()),\n body: errorBody || undefined,\n },\n })\n\n return detail\n}\n\nfunction getUpstreamErrorDetail(\n response: Response,\n body: string,\n): string | undefined {\n if (!body) {\n return response.statusText || undefined\n }\n\n try {\n const payload = JSON.parse(body) as {\n error?: {\n code?: string\n message?: string\n }\n }\n return payload.error?.message ?? payload.error?.code ?? body.slice(0, 240)\n } catch {\n return body.slice(0, 240)\n }\n}\n\nasync function shouldRetryWithResponses(\n response: Response,\n signal?: AbortSignal,\n timeoutMs?: number,\n): Promise<boolean> {\n // Copilot can list a model but reject the chat endpoint for it; only this\n // explicit upstream code is treated as a signal to retry via /responses.\n try {\n const errorBody = await readCopilotJson<{\n error?: {\n code?: string\n }\n }>(response.clone(), signal, timeoutMs)\n return errorBody.error?.code === \"unsupported_api_for_model\"\n } catch {\n return false\n }\n}\n","// Startup preflight: fail fast if configured models or think effort cannot be used upstream.\nimport type { ProxyConfig } from \"~/lib/config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { log } from \"~/lib/log\"\nimport type { ReasoningEffort } from \"~/lib/models\"\nimport { getExposedModelIds } from \"~/lib/models\"\nimport {\n createCopilotRequestSignal,\n fetchCopilot,\n getCopilotProviderContext,\n readCopilotJson,\n} from \"~/copilot/client\"\nimport type { ChatCompletionsPayload } from \"~/copilot/types\"\nimport { createChatCompletions } from \"~/copilot/chat\"\n\ninterface CopilotModelsResponse {\n data?: Array<{ id?: string }>\n}\n\nconst getUpstreamModelIds = async (config: ProxyConfig): Promise<Set<string>> => {\n const provider = getCopilotProviderContext(config)\n const signal = createCopilotRequestSignal(undefined, config.upstreamTimeoutMs)\n const response = await fetchCopilot(provider, \"/models\", {\n method: \"GET\",\n headers: { accept: \"application/json\" },\n }, { signal, timeoutMs: config.upstreamTimeoutMs })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to validate upstream models\", response)\n }\n\n const payload = await readCopilotJson<CopilotModelsResponse>(\n response,\n signal,\n config.upstreamTimeoutMs,\n )\n return new Set(\n (payload.data ?? [])\n .map((model) => model.id)\n .filter((id): id is string => typeof id === \"string\" && id.length > 0),\n )\n}\n\nconst ensureRequiredModels = async (config: ProxyConfig): Promise<void> => {\n const upstreamModels = await getUpstreamModelIds(config)\n const requiredModels = getExposedModelIds()\n const missingModels = requiredModels.filter((model) => !upstreamModels.has(model))\n\n if (missingModels.length > 0) {\n throw new Error(\n `Required Copilot model(s) unavailable upstream: ${missingModels.join(\", \")}`,\n )\n }\n\n log.info(`Upstream models available: ${requiredModels.join(\", \")}`)\n}\n\nconst createProbePayload = (model: string): ChatCompletionsPayload => ({\n model,\n max_tokens: 16,\n stream: false,\n messages: [\n {\n role: \"user\",\n content: \"Reply with OK only.\",\n },\n ],\n})\n\nconst validateModelRequest = async (\n config: ProxyConfig,\n model: string,\n thinkEffort: ReasoningEffort,\n): Promise<void> => {\n try {\n // Probe through the same internal chat path as real requests so routing,\n // token headers, think effort, and /responses fallback are validated together.\n const response = await createChatCompletions(\n config,\n createProbePayload(model),\n {\n client: \"generic\",\n requestedModel: model,\n timeoutMs: config.upstreamTimeoutMs,\n },\n )\n\n if (typeof response !== \"object\" || response === null || !(\"choices\" in response)) {\n throw new Error(`Preflight request for ${model} unexpectedly streamed`)\n }\n\n log.info(`Preflight OK: model=${model} think_effort=${thinkEffort}`)\n } catch (error) {\n if (error instanceof HTTPError) {\n const text = await error.response.text().catch(() => \"\")\n throw new Error(\n `Preflight failed for model=${model} think_effort=${thinkEffort}: ${error.response.status} ${error.response.statusText}${text ? ` ${text}` : \"\"}`,\n )\n }\n throw error\n }\n}\n\nexport const validateUpstream = async (\n config: ProxyConfig,\n thinkEffort: ReasoningEffort,\n): Promise<void> => {\n log.info(\"Running upstream preflight\")\n await ensureRequiredModels(config)\n\n for (const model of getExposedModelIds()) {\n await validateModelRequest(config, model, thinkEffort)\n }\n}\n","// Reads package.json version from either source or bundled dist layouts.\nimport { readFileSync } from \"node:fs\"\nimport { dirname, resolve } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\ninterface PackageJson {\n name?: string\n version?: string\n}\n\nconst packageName = \"copilot-relay\"\n\nconst readPackageVersion = (): string => {\n let currentDir = dirname(fileURLToPath(import.meta.url))\n\n while (true) {\n try {\n const packageJsonPath = resolve(currentDir, \"package.json\")\n const packageJson = JSON.parse(\n readFileSync(packageJsonPath, \"utf8\"),\n ) as PackageJson\n\n if (\n packageJson.name === packageName\n && typeof packageJson.version === \"string\"\n ) {\n return packageJson.version\n }\n } catch {\n // Keep walking upward; source and dist builds sit at different depths.\n }\n\n const parentDir = dirname(currentDir)\n if (parentDir === currentDir) {\n return \"unknown\"\n }\n\n currentDir = parentDir\n }\n}\n\nexport const appVersion = readPackageVersion()\n","// Small Claude protocol helpers shared by streaming and non-streaming translators.\nimport type { ClaudeResponse } from \"~/claude/types\"\n\nexport function mapOpenAIStopReasonToClaude(\n finishReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null,\n): ClaudeResponse[\"stop_reason\"] {\n if (finishReason === null) {\n return null\n }\n\n const stopReasonMap = {\n stop: \"end_turn\",\n length: \"max_tokens\",\n tool_calls: \"tool_use\",\n content_filter: \"end_turn\",\n } as const\n\n return stopReasonMap[finishReason]\n}\n","// Maps Claude tool names to Copilot-compatible tool names and back.\nimport { createHash } from \"node:crypto\"\n\nimport type { ClaudeTool } from \"~/claude/types\"\n\nconst strictToolNameCharsPattern = /^[A-Za-z0-9_-]+$/\nconst dottedToolNameCharsPattern = /^[A-Za-z0-9_.-]+$/\nconst defaultToolNameMaxLength = 64\nconst extendedToolNameMaxLength = 128\nconst hashLength = 10\n\nexport interface ClaudeToolNameMapper {\n toClaude(name: string): string\n toOpenAI(name: string): string\n}\n\ninterface ToolNameMapperOptions {\n allowDots?: boolean\n maxNameLength?: number\n}\n\nexport const getToolNameMapperOptionsForModel = (\n modelId: string,\n): Required<ToolNameMapperOptions> => {\n const normalized = modelId\n .trim()\n .toLowerCase()\n .replace(/\\[1m\\]$/, \"-1m\")\n .replace(/[._]/g, \"-\")\n\n if (normalized.startsWith(\"gpt-\")) {\n return { allowDots: false, maxNameLength: extendedToolNameMaxLength }\n }\n\n return { allowDots: false, maxNameLength: defaultToolNameMaxLength }\n}\n\nexport const getClaudeToolNameMaxLength = (modelId: string): number =>\n getToolNameMapperOptionsForModel(modelId).maxNameLength\n\nconst makeHash = (value: string): string =>\n createHash(\"sha1\").update(value).digest(\"hex\").slice(0, hashLength)\n\nconst getAllowedNamePattern = (allowDots: boolean): RegExp =>\n allowDots ? dottedToolNameCharsPattern : strictToolNameCharsPattern\n\nconst cleanToolName = (name: string, allowDots: boolean): string => {\n const invalidCharsPattern = allowDots ? /[^A-Za-z0-9_.-]/g : /[^A-Za-z0-9_-]/g\n const cleaned = name.replace(invalidCharsPattern, \"_\").replace(/_+/g, \"_\")\n return cleaned.replace(/^_+|_+$/g, \"\") || \"tool\"\n}\n\nconst isValidToolName = (\n name: string,\n maxNameLength: number,\n allowDots: boolean,\n): boolean =>\n name.length > 0\n && name.length <= maxNameLength\n && getAllowedNamePattern(allowDots).test(name)\n\nconst makeValidToolName = (\n name: string,\n maxNameLength: number,\n allowDots: boolean,\n): string => {\n if (isValidToolName(name, maxNameLength, allowDots)) {\n return name\n }\n\n const cleaned = cleanToolName(name, allowDots)\n if (cleaned.length <= maxNameLength) {\n return cleaned\n }\n\n const hash = makeHash(name)\n const prefixLength = maxNameLength - hash.length - 1\n return `${cleaned.slice(0, prefixLength)}_${hash}`\n}\n\nconst makeUniqueToolName = (\n name: string,\n used: Set<string>,\n maxNameLength: number,\n allowDots: boolean,\n): string => {\n const candidate = makeValidToolName(name, maxNameLength, allowDots)\n if (!used.has(candidate)) {\n return candidate\n }\n\n for (let index = 2; ; index++) {\n const suffix = `_${makeHash(`${name}:${index}`)}`\n const prefixLength = maxNameLength - suffix.length\n const next = `${cleanToolName(name, allowDots).slice(0, prefixLength)}${suffix}`\n if (!used.has(next)) {\n return next\n }\n }\n}\n\nexport const createClaudeToolNameMapper = (\n tools: Array<ClaudeTool> | undefined,\n options: ToolNameMapperOptions = {},\n): ClaudeToolNameMapper => {\n const maxNameLength = options.maxNameLength ?? defaultToolNameMaxLength\n const allowDots = options.allowDots ?? false\n const claudeToOpenAI = new Map<string, string>()\n const openAIToClaude = new Map<string, string>()\n const used = new Set<string>()\n\n for (const tool of tools ?? []) {\n if (claudeToOpenAI.has(tool.name)) {\n continue\n }\n\n const openAIName = makeUniqueToolName(\n tool.name,\n used,\n maxNameLength,\n allowDots,\n )\n used.add(openAIName)\n claudeToOpenAI.set(tool.name, openAIName)\n openAIToClaude.set(openAIName, tool.name)\n }\n\n return {\n toClaude: (name) => openAIToClaude.get(name) ?? name,\n toOpenAI: (name) =>\n claudeToOpenAI.get(name)\n ?? makeValidToolName(name, maxNameLength, allowDots),\n }\n}\n","// Non-streaming protocol translation between Claude Messages and Copilot chat completions.\nimport { defaultReasoningEffort } from \"~/lib/models\"\nimport { routeModelId } from \"~/lib/models\"\nimport { runtimeState } from \"~/lib/state\"\nimport type {\n ChatCompletionResponse,\n ChatCompletionsPayload,\n ContentPart,\n Message,\n TextPart,\n Tool,\n ToolCall,\n} from \"~/copilot/types\"\n\nimport {\n type ClaudeAssistantContentBlock,\n type ClaudeAssistantMessage,\n type ClaudeMessage,\n type ClaudeMessagesPayload,\n type ClaudeResponse,\n type ClaudeTextBlock,\n type ClaudeThinkingBlock,\n type ClaudeTool,\n type ClaudeToolResultBlock,\n type ClaudeToolUseBlock,\n type ClaudeUserContentBlock,\n type ClaudeUserMessage,\n} from \"~/claude/types\"\nimport { mapOpenAIStopReasonToClaude } from \"~/claude/utils\"\nimport {\n createClaudeToolNameMapper,\n getToolNameMapperOptionsForModel,\n type ClaudeToolNameMapper,\n} from \"~/claude/tool-names\"\n\nexport function translateModelName(model: string): string {\n return routeModelId(model)\n}\n\nexport function translateToOpenAI(\n payload: ClaudeMessagesPayload,\n _settings?: undefined,\n toolNameMapper?: ClaudeToolNameMapper,\n): ChatCompletionsPayload {\n const model = translateModelName(payload.model)\n const mapper = toolNameMapper ?? createClaudeToolNameMapper(payload.tools, {\n ...getToolNameMapperOptionsForModel(model),\n })\n const tools = translateClaudeToolsToOpenAI(payload.tools, mapper)\n const messages = translateClaudeMessagesToOpenAI(\n payload.messages,\n payload.system,\n mapper,\n )\n\n return {\n model,\n messages: normalizeFinalAssistantPrefill(messages),\n max_tokens: payload.max_tokens,\n stop: payload.stop_sequences,\n stream: payload.stream,\n temperature: payload.temperature,\n top_p: payload.top_p,\n reasoning_effort: runtimeState.thinkEffort ?? defaultReasoningEffort,\n user: payload.metadata?.user_id,\n tools,\n tool_choice:\n tools && tools.length > 0 ?\n translateClaudeToolChoiceToOpenAI(payload.tool_choice, mapper)\n : undefined,\n }\n}\n\nfunction translateClaudeMessagesToOpenAI(\n claudeMessages: Array<ClaudeMessage>,\n system: string | Array<ClaudeTextBlock> | undefined,\n toolNameMapper: ClaudeToolNameMapper,\n): Array<Message> {\n const systemMessages = handleSystemPrompt(system)\n const otherMessages = claudeMessages.flatMap((message) =>\n message.role === \"user\" ? handleUserMessage(message) : handleAssistantMessage(message, toolNameMapper),\n )\n return [...systemMessages, ...otherMessages]\n}\n\nfunction handleSystemPrompt(\n system: string | Array<ClaudeTextBlock> | undefined,\n): Array<Message> {\n if (!system) {\n return []\n }\n\n if (typeof system === \"string\") {\n return [{ role: \"system\", content: system }]\n }\n\n // Claude accepts multiple system text blocks; Copilot chat expects one\n // system message, so preserve block boundaries with blank lines.\n return [{ role: \"system\", content: system.map((block) => block.text).join(\"\\n\\n\") }]\n}\n\nfunction handleUserMessage(message: ClaudeUserMessage): Array<Message> {\n const newMessages: Array<Message> = []\n\n if (Array.isArray(message.content)) {\n const toolResultBlocks = message.content.filter(\n (block): block is ClaudeToolResultBlock => block.type === \"tool_result\",\n )\n const otherBlocks = message.content.filter((block) => block.type !== \"tool_result\")\n\n // Tool results must become standalone OpenAI tool messages before any\n // remaining user content, otherwise upstream cannot associate them with\n // prior assistant tool calls.\n for (const block of toolResultBlocks) {\n newMessages.push({\n role: \"tool\",\n tool_call_id: block.tool_use_id,\n content: mapContent(block.content),\n })\n }\n\n if (otherBlocks.length > 0) {\n newMessages.push({\n role: \"user\",\n content: mapContent(otherBlocks),\n })\n }\n } else {\n newMessages.push({\n role: \"user\",\n content: mapContent(message.content),\n })\n }\n\n return newMessages\n}\n\nfunction handleAssistantMessage(\n message: ClaudeAssistantMessage,\n toolNameMapper: ClaudeToolNameMapper,\n): Array<Message> {\n if (!Array.isArray(message.content)) {\n return [{ role: \"assistant\", content: mapContent(message.content) }]\n }\n\n const toolUseBlocks = message.content.filter(\n (block): block is ClaudeToolUseBlock => block.type === \"tool_use\",\n )\n const textBlocks = message.content.filter(\n (block): block is ClaudeTextBlock => block.type === \"text\",\n )\n const thinkingBlocks = message.content.filter(\n (block): block is ClaudeThinkingBlock => block.type === \"thinking\",\n )\n\n const allTextContent = [\n ...textBlocks.map((b) => b.text),\n ...thinkingBlocks.map((b) => b.thinking),\n ].join(\"\\n\\n\")\n\n // Assistant tool_use blocks bridge to OpenAI tool_calls; plain text and\n // thinking content stay on the assistant message as context for those calls.\n return toolUseBlocks.length > 0\n ? [\n {\n role: \"assistant\",\n content: allTextContent || null,\n tool_calls: toolUseBlocks.map((toolUse) => ({\n id: toolUse.id,\n type: \"function\",\n function: {\n name: toolNameMapper.toOpenAI(toolUse.name),\n arguments: JSON.stringify(toolUse.input),\n },\n })),\n },\n ]\n : [{ role: \"assistant\", content: mapContent(message.content) }]\n}\n\nconst continuePrefillPrompt =\n \"Continue the assistant response from the previous assistant message.\"\n\nconst normalizeFinalAssistantPrefill = (\n messages: Array<Message>,\n): Array<Message> => {\n let lastAssistantIndex = -1\n for (let index = messages.length - 1; index >= 0; index--) {\n if (messages[index]?.role === \"assistant\") {\n lastAssistantIndex = index\n break\n }\n }\n if (lastAssistantIndex < 0) {\n return messages\n }\n if (lastAssistantIndex !== messages.length - 1) {\n return messages\n }\n\n const lastAssistant = messages[lastAssistantIndex]\n if (typeof lastAssistant.content !== \"string\") {\n return messages.slice(0, -1)\n }\n\n const trimmedContent = lastAssistant.content.trimEnd()\n // Claude Messages allows a final assistant message as a prefill prefix.\n // Copilot rejects that shape, so keep the prefix as context and append a\n // minimal user turn that asks upstream to continue from it.\n const nextMessages = [...messages]\n if (trimmedContent) {\n nextMessages[lastAssistantIndex] = {\n ...lastAssistant,\n content: trimmedContent,\n }\n nextMessages.push({ role: \"user\", content: continuePrefillPrompt })\n } else {\n nextMessages.pop()\n }\n return nextMessages\n}\n\nfunction mapContent(\n content:\n | string\n | Array<ClaudeUserContentBlock | ClaudeAssistantContentBlock>,\n): string | Array<ContentPart> | null {\n if (typeof content === \"string\") {\n return content\n }\n\n if (!Array.isArray(content)) {\n return null\n }\n\n const hasImage = content.some((block) => block.type === \"image\")\n if (!hasImage) {\n // Without images the OpenAI-compatible chat surface accepts plain strings;\n // image messages must use content parts instead.\n return content\n .filter(\n (block): block is ClaudeTextBlock | ClaudeThinkingBlock =>\n block.type === \"text\" || block.type === \"thinking\",\n )\n .map((block) => (block.type === \"text\" ? block.text : block.thinking))\n .join(\"\\n\\n\")\n }\n\n const contentParts: Array<ContentPart> = []\n for (const block of content) {\n switch (block.type) {\n case \"text\": {\n contentParts.push({ type: \"text\", text: block.text })\n break\n }\n case \"thinking\": {\n contentParts.push({ type: \"text\", text: block.thinking })\n break\n }\n case \"image\": {\n contentParts.push({\n type: \"image_url\",\n image_url: {\n url: `data:${block.source.media_type};base64,${block.source.data}`,\n },\n })\n break\n }\n }\n }\n\n return contentParts\n}\n\nfunction translateClaudeToolsToOpenAI(\n claudeTools: Array<ClaudeTool> | undefined,\n toolNameMapper: ClaudeToolNameMapper,\n): Array<Tool> | undefined {\n if (!claudeTools || claudeTools.length === 0) {\n return undefined\n }\n\n const tools = claudeTools.flatMap((tool) => {\n if (!tool.input_schema) {\n return []\n }\n\n return [{\n type: \"function\" as const,\n function: {\n name: toolNameMapper.toOpenAI(tool.name),\n description: tool.description,\n parameters: tool.input_schema,\n },\n }]\n })\n\n return tools.length > 0 ? tools : undefined\n}\n\nfunction translateClaudeToolChoiceToOpenAI(\n claudeToolChoice: ClaudeMessagesPayload[\"tool_choice\"],\n toolNameMapper: ClaudeToolNameMapper,\n): ChatCompletionsPayload[\"tool_choice\"] {\n if (!claudeToolChoice) {\n return undefined\n }\n\n switch (claudeToolChoice.type) {\n case \"auto\": {\n return \"auto\"\n }\n case \"any\": {\n return \"required\"\n }\n case \"tool\": {\n if (claudeToolChoice.name) {\n return {\n type: \"function\",\n function: { name: toolNameMapper.toOpenAI(claudeToolChoice.name) },\n }\n }\n return undefined\n }\n case \"none\": {\n return \"none\"\n }\n default: {\n return undefined\n }\n }\n}\n\nexport function translateToClaude(\n response: ChatCompletionResponse,\n toolNameMapper: ClaudeToolNameMapper = createClaudeToolNameMapper(\n undefined,\n ),\n): ClaudeResponse {\n const allThinkingBlocks: Array<ClaudeThinkingBlock> = []\n const allTextBlocks: Array<ClaudeTextBlock> = []\n const allToolUseBlocks: Array<ClaudeToolUseBlock> = []\n let stopReason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null = null\n\n stopReason = response.choices[0]?.finish_reason ?? stopReason\n\n // Multiple choices can mix text and tool calls. Claude has one stop_reason,\n // so prefer tool_calls when present while preserving a normal stop result.\n for (const choice of response.choices) {\n allThinkingBlocks.push(\n ...getClaudeThinkingBlocks(\n choice.message.reasoning_text ?? choice.message.reasoning_content,\n ),\n )\n allTextBlocks.push(...getClaudeTextBlocks(choice.message.content))\n allToolUseBlocks.push(\n ...getClaudeToolUseBlocks(choice.message.tool_calls, toolNameMapper),\n )\n\n if (choice.finish_reason === \"tool_calls\" || stopReason === \"stop\") {\n stopReason = choice.finish_reason\n }\n }\n\n return {\n id: response.id,\n type: \"message\",\n role: \"assistant\",\n model: response.model,\n content: [...allThinkingBlocks, ...allTextBlocks, ...allToolUseBlocks],\n stop_reason: mapOpenAIStopReasonToClaude(stopReason),\n stop_sequence: null,\n usage: {\n input_tokens:\n (response.usage?.prompt_tokens ?? 0)\n - (response.usage?.prompt_tokens_details?.cached_tokens ?? 0),\n output_tokens: response.usage?.completion_tokens ?? 0,\n ...(response.usage?.prompt_tokens_details?.cached_tokens !== undefined && {\n cache_read_input_tokens: response.usage.prompt_tokens_details.cached_tokens,\n }),\n },\n }\n}\n\nfunction getClaudeThinkingBlocks(\n reasoningContent: string | null | undefined,\n): Array<ClaudeThinkingBlock> {\n if (!reasoningContent) {\n return []\n }\n\n return [{ type: \"thinking\", thinking: reasoningContent }]\n}\n\nfunction getClaudeTextBlocks(\n messageContent: Message[\"content\"],\n): Array<ClaudeTextBlock> {\n if (typeof messageContent === \"string\") {\n return [{ type: \"text\", text: messageContent }]\n }\n\n if (Array.isArray(messageContent)) {\n return messageContent\n .filter((part): part is TextPart => part.type === \"text\")\n .map((part) => ({ type: \"text\", text: part.text }))\n }\n\n return []\n}\n\nfunction getClaudeToolUseBlocks(\n toolCalls: Array<ToolCall> | undefined,\n toolNameMapper: ClaudeToolNameMapper,\n): Array<ClaudeToolUseBlock> {\n if (!toolCalls) {\n return []\n }\n\n return toolCalls.map((toolCall) => ({\n type: \"tool_use\",\n id: toolCall.id,\n name: toolNameMapper.toClaude(toolCall.function.name),\n input: safeJsonParse(toolCall.function.arguments),\n }))\n}\n\nfunction safeJsonParse(input: string): Record<string, unknown> {\n try {\n return JSON.parse(input) as Record<string, unknown>\n } catch {\n return { raw: input }\n }\n}\n","// Stateful streaming adapter from Copilot chat completion chunks to Claude SSE events.\nimport type {\n ClaudeStreamEventData,\n ClaudeStreamState,\n} from \"~/claude/types\"\nimport {\n createClaudeToolNameMapper,\n type ClaudeToolNameMapper,\n} from \"~/claude/tool-names\"\nimport { mapOpenAIStopReasonToClaude } from \"~/claude/utils\"\nimport type { ChatCompletionChunk } from \"~/copilot/types\"\n\nfunction isToolBlockOpen(state: ClaudeStreamState): boolean {\n if (!state.contentBlockOpen) {\n return false\n }\n\n return Object.values(state.toolCalls).some(\n (tc) => tc.claudeBlockIndex === state.contentBlockIndex,\n )\n}\n\nconst closeOpenContentBlock = (\n events: Array<ClaudeStreamEventData>,\n state: ClaudeStreamState,\n): void => {\n if (!state.contentBlockOpen) {\n return\n }\n\n events.push({\n type: \"content_block_stop\",\n index: state.contentBlockIndex,\n })\n state.contentBlockIndex++\n state.contentBlockOpen = false\n state.thinkingBlockOpen = false\n}\n\nexport function translateChunkToClaudeEvents(\n chunk: ChatCompletionChunk,\n state: ClaudeStreamState,\n toolNameMapper: ClaudeToolNameMapper = createClaudeToolNameMapper(\n undefined,\n ),\n): Array<ClaudeStreamEventData> {\n // This is a stateful adapter from Copilot's OpenAI-style deltas to Claude's\n // stricter SSE protocol. Claude requires every thinking/text/tool block to\n // be explicitly opened, filled with deltas, and then closed in order.\n const events: Array<ClaudeStreamEventData> = []\n\n if (chunk.choices.length === 0) {\n return events\n }\n\n const choice = chunk.choices[0]\n const { delta } = choice\n const reasoningContent = delta.reasoning_text ?? delta.reasoning_content\n\n if (!state.messageStartSent) {\n events.push({\n type: \"message_start\",\n message: {\n id: chunk.id,\n type: \"message\",\n role: \"assistant\",\n content: [],\n model: chunk.model,\n stop_reason: null,\n stop_sequence: null,\n usage: {\n input_tokens:\n (chunk.usage?.prompt_tokens ?? 0)\n - (chunk.usage?.prompt_tokens_details?.cached_tokens ?? 0),\n output_tokens: 0,\n ...(chunk.usage?.prompt_tokens_details?.cached_tokens !== undefined && {\n cache_read_input_tokens: chunk.usage.prompt_tokens_details.cached_tokens,\n }),\n },\n },\n })\n state.messageStartSent = true\n }\n\n if (reasoningContent) {\n // Claude allows only one open content block at a time. Switching from text\n // or tool output into thinking must close the previous block first.\n if (state.contentBlockOpen && !state.thinkingBlockOpen) {\n closeOpenContentBlock(events, state)\n }\n\n if (!state.contentBlockOpen) {\n events.push({\n type: \"content_block_start\",\n index: state.contentBlockIndex,\n content_block: {\n type: \"thinking\",\n thinking: \"\",\n },\n })\n state.contentBlockOpen = true\n state.thinkingBlockOpen = true\n }\n\n events.push({\n type: \"content_block_delta\",\n index: state.contentBlockIndex,\n delta: {\n type: \"thinking_delta\",\n thinking: reasoningContent,\n },\n })\n }\n\n if (delta.content) {\n // Text deltas cannot be appended to an open thinking or tool_use block, so\n // close whichever block is active before starting/resuming text output.\n if (state.thinkingBlockOpen || isToolBlockOpen(state)) {\n closeOpenContentBlock(events, state)\n }\n\n if (!state.contentBlockOpen) {\n events.push({\n type: \"content_block_start\",\n index: state.contentBlockIndex,\n content_block: {\n type: \"text\",\n text: \"\",\n },\n })\n state.contentBlockOpen = true\n }\n\n events.push({\n type: \"content_block_delta\",\n index: state.contentBlockIndex,\n delta: {\n type: \"text_delta\",\n text: delta.content,\n },\n })\n }\n\n if (delta.tool_calls) {\n for (const toolCall of delta.tool_calls) {\n if (toolCall.id && toolCall.function?.name) {\n // The first tool delta opens a Claude tool_use block; later argument\n // deltas are routed back to this block by Copilot's tool call index.\n if (state.contentBlockOpen) {\n closeOpenContentBlock(events, state)\n }\n\n const toolName = toolNameMapper.toClaude(toolCall.function.name)\n const claudeBlockIndex = state.contentBlockIndex\n state.toolCalls[toolCall.index] = {\n id: toolCall.id,\n name: toolName,\n claudeBlockIndex,\n }\n\n events.push({\n type: \"content_block_start\",\n index: claudeBlockIndex,\n content_block: {\n type: \"tool_use\",\n id: toolCall.id,\n name: toolName,\n input: {},\n },\n })\n state.contentBlockOpen = true\n }\n\n if (toolCall.function?.arguments) {\n const toolCallInfo = state.toolCalls[toolCall.index]\n if (toolCallInfo) {\n events.push({\n type: \"content_block_delta\",\n index: toolCallInfo.claudeBlockIndex,\n delta: {\n type: \"input_json_delta\",\n partial_json: toolCall.function.arguments,\n },\n })\n }\n }\n }\n }\n\n if (choice.finish_reason) {\n if (state.contentBlockOpen) {\n closeOpenContentBlock(events, state)\n }\n\n events.push(\n {\n type: \"message_delta\",\n delta: {\n stop_reason: mapOpenAIStopReasonToClaude(choice.finish_reason),\n stop_sequence: null,\n },\n usage: {\n input_tokens:\n (chunk.usage?.prompt_tokens ?? 0)\n - (chunk.usage?.prompt_tokens_details?.cached_tokens ?? 0),\n output_tokens: chunk.usage?.completion_tokens ?? 0,\n ...(chunk.usage?.prompt_tokens_details?.cached_tokens !== undefined && {\n cache_read_input_tokens: chunk.usage.prompt_tokens_details.cached_tokens,\n }),\n },\n },\n {\n type: \"message_stop\",\n },\n )\n }\n\n return events\n}\n\nexport function translateErrorToClaudeErrorEvent(): ClaudeStreamEventData {\n return {\n type: \"error\",\n error: {\n type: \"api_error\",\n message: \"An unexpected error occurred during streaming.\",\n },\n }\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type {\n ClaudeAssistantContentBlock,\n ClaudeMessage,\n ClaudeMessagesPayload,\n ClaudeResponse,\n ClaudeTextBlock,\n ClaudeTool,\n ClaudeWebSearchResultBlock,\n} from \"~/claude/types\"\nimport type { ClaudeToolNameMapper } from \"~/claude/tool-names\"\nimport {\n createCopilotRequestSignal,\n fetchCopilot,\n getCopilotProviderContext,\n readCopilotJson,\n readCopilotText,\n} from \"~/copilot/client\"\nimport type {\n ChatCompletionResponse,\n ChatCompletionsPayload,\n Message,\n ToolCall,\n} from \"~/copilot/types\"\nimport type { ProxyConfig } from \"~/lib/config\"\nimport { getModelRouting } from \"~/lib/models\"\n\nconst anthropicWebSearchToolPattern = /^web_search_\\d{8}$/\nconst claudeCodeWebSearchToolName = \"WebSearch\"\nconst searchResultLimit = 8\n\nconst webSearchInputSchema = {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description: \"The web search query.\",\n },\n },\n required: [\"query\"],\n additionalProperties: false,\n}\n\ninterface ResponsesWebSearchResponse {\n id: string\n created_at: number\n model: string\n output?: Array<ResponsesOutputItem>\n usage?: {\n input_tokens?: number\n output_tokens?: number\n }\n}\n\ntype ResponsesOutputItem =\n | {\n type: \"web_search_call\"\n action?: {\n query?: string\n queries?: Array<string>\n }\n }\n | {\n type: \"message\"\n content?: Array<{\n type?: string\n text?: string\n }>\n }\n | Record<string, unknown>\n\nexport interface WebSearchResult {\n title: string\n url: string\n}\n\nexport interface WebSearchExecutionResult {\n id: string\n inputTokens: number\n model: string\n outputTokens: number\n query: string\n results: Array<WebSearchResult>\n text: string\n}\n\nexport interface ClaudeWebSearchToolCall {\n query: string\n toolCall: ToolCall\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value)\n\nconst isAnthropicNativeWebSearchTool = (tool: ClaudeTool): boolean =>\n tool.name === \"web_search\"\n && typeof tool.type === \"string\"\n && anthropicWebSearchToolPattern.test(tool.type)\n\nconst isClaudeCodeWebSearchTool = (tool: ClaudeTool): boolean =>\n tool.name === claudeCodeWebSearchToolName\n\nexport const isClaudeWebSearchTool = (tool: ClaudeTool): boolean =>\n isAnthropicNativeWebSearchTool(tool) || isClaudeCodeWebSearchTool(tool)\n\nexport const hasClaudeWebSearch = (payload: ClaudeMessagesPayload): boolean =>\n payload.tools?.some(isClaudeWebSearchTool) ?? false\n\nconst isClaudeWebSearchToolName = (name: string): boolean =>\n name === \"web_search\" || name === claudeCodeWebSearchToolName\n\nexport const getWebSearchBackendModel = (config: ProxyConfig): string =>\n config.webSearchBackend?.trim() || getModelRouting().gptModel\n\nexport const prepareClaudeWebSearchDecisionPayload = (\n payload: ClaudeMessagesPayload,\n): ClaudeMessagesPayload => {\n if (!hasClaudeWebSearch(payload)) {\n return payload\n }\n\n return {\n ...payload,\n tools: payload.tools?.map((tool) =>\n isClaudeWebSearchTool(tool) ?\n {\n ...tool,\n input_schema: tool.input_schema ?? webSearchInputSchema,\n }\n : tool,\n ),\n }\n}\n\nconst textFromMessageContent = (content: ClaudeMessage[\"content\"]): string => {\n if (typeof content === \"string\") {\n return content\n }\n\n return content\n .flatMap((block) => {\n if (block.type === \"text\") return [block.text]\n if (block.type === \"tool_result\") return [block.content]\n return []\n })\n .join(\"\\n\\n\")\n}\n\nconst getRequestedQuery = (payload: ClaudeMessagesPayload): string => {\n const lastUserMessage = [...payload.messages]\n .reverse()\n .find((message) => message.role === \"user\")\n const rawText = lastUserMessage ? textFromMessageContent(lastUserMessage.content) : \"\"\n const cleaned = rawText\n .replace(/<system-reminder>[\\s\\S]*?<\\/system-reminder>/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim()\n const searchMatch = cleaned.match(/\\bsearch(?:\\s+the\\s+web)?(?:\\s+for)?\\s+(.+)$/i)\n return searchMatch?.[1]?.trim() || cleaned || \"web search\"\n}\n\nconst getQueryFromToolArguments = (value: string): string | undefined => {\n const trimmed = value.trim()\n if (!trimmed) {\n return undefined\n }\n\n try {\n const parsed = JSON.parse(trimmed) as unknown\n if (\n isRecord(parsed)\n && typeof parsed.query === \"string\"\n && parsed.query.trim()\n ) {\n return parsed.query.trim()\n }\n } catch {\n return trimmed\n }\n\n return trimmed\n}\n\nexport const getClaudeWebSearchToolCallFromChatResponse = (\n response: ChatCompletionResponse,\n toolNameMapper: ClaudeToolNameMapper,\n): ClaudeWebSearchToolCall | undefined => {\n const toolCall = response.choices\n .flatMap((choice) => choice.message.tool_calls ?? [])\n .find((call) =>\n isClaudeWebSearchToolName(\n toolNameMapper.toClaude(call.function.name),\n ),\n )\n\n if (!toolCall) {\n return undefined\n }\n\n const query = getQueryFromToolArguments(toolCall.function.arguments)\n return query ? { query, toolCall } : undefined\n}\n\nconst buildSearchInput = (\n payload: ClaudeMessagesPayload,\n requestedQuery: string,\n): string => {\n const systemText =\n typeof payload.system === \"string\" ? payload.system\n : Array.isArray(payload.system) ?\n payload.system.map((block: ClaudeTextBlock) => block.text).join(\"\\n\\n\")\n : \"\"\n const messages = payload.messages\n .map((message) => `${message.role}: ${textFromMessageContent(message.content)}`)\n .join(\"\\n\\n\")\n\n return [\n \"You are fulfilling an Anthropic web_search server tool request for Claude Code.\",\n \"Search the web using the provided web_search_preview tool.\",\n `Requested web search query: ${requestedQuery}`,\n \"Return useful search results as plain text lines in this exact shape:\",\n \"1. Title - https://example.com/page\",\n \"Include only real source URLs from the search results.\",\n systemText ? `System context:\\n${systemText}` : \"\",\n `Conversation:\\n${messages}`,\n ]\n .filter(Boolean)\n .join(\"\\n\\n\")\n}\n\nconst buildWebSearchRequestPayload = (\n payload: ClaudeMessagesPayload,\n requestedQuery: string,\n model: string,\n) => ({\n model,\n input: buildSearchInput(payload, requestedQuery),\n tools: [{ type: \"web_search_preview\" }],\n max_output_tokens: Math.max(256, Math.min(payload.max_tokens ?? 1024, 1200)),\n temperature: payload.temperature,\n top_p: payload.top_p,\n})\n\nconst getSearchQuery = (\n response: ResponsesWebSearchResponse,\n requestedQuery: string,\n): string => {\n for (const item of response.output ?? []) {\n if (item.type !== \"web_search_call\") continue\n const action = isRecord(item.action) ? item.action : undefined\n const queries = Array.isArray(action?.queries) ? action.queries : []\n const query =\n typeof action?.query === \"string\" ? action.query\n : typeof queries[0] === \"string\" ? queries[0]\n : undefined\n if (query) return query\n }\n\n return requestedQuery.slice(0, 200)\n}\n\nconst getResponseText = (response: ResponsesWebSearchResponse): string =>\n (response.output ?? [])\n .flatMap((item) => {\n if (item.type !== \"message\") return []\n const content = Array.isArray(item.content) ? item.content : []\n return content.flatMap((part) =>\n isRecord(part)\n && part.type === \"output_text\"\n && typeof part.text === \"string\" ?\n [part.text]\n : [],\n )\n })\n .join(\"\\n\")\n .trim()\n\nconst cleanTitle = (line: string, url: string): string => {\n const beforeUrl = line.slice(0, line.indexOf(url))\n const cleaned = beforeUrl\n .replace(/^\\s*(?:[-*]|\\d+[.)])\\s*/, \"\")\n .replace(/\\s*(?:[-:|])\\s*$/, \"\")\n .trim()\n return cleaned || new URL(url).hostname\n}\n\nconst parseSearchResults = (text: string): Array<WebSearchResult> => {\n const results: Array<WebSearchResult> = []\n const seenUrls = new Set<string>()\n\n for (const line of text.split(/\\r?\\n/)) {\n const markdownMatch = line.match(/\\[([^\\]]+)]\\((https?:\\/\\/[^)\\s]+)\\)/)\n const url = markdownMatch?.[2] ?? line.match(/https?:\\/\\/[^\\s)]+/)?.[0]\n if (!url || seenUrls.has(url)) {\n continue\n }\n\n seenUrls.add(url)\n results.push({\n title: markdownMatch?.[1]?.trim() || cleanTitle(line, url),\n url,\n })\n\n if (results.length >= searchResultLimit) {\n break\n }\n }\n\n return results\n}\n\nconst createFailedSearchExecution = (\n payload: ClaudeMessagesPayload,\n requestedQuery: string,\n model: string,\n message: string,\n): WebSearchExecutionResult => ({\n id: `msg_${randomUUID().replaceAll(\"-\", \"\")}`,\n inputTokens: 0,\n model,\n outputTokens: 0,\n query: requestedQuery || getRequestedQuery(payload),\n results: [],\n text: message,\n})\n\nexport const createClaudeWebSearchExecution = async (\n config: ProxyConfig,\n payload: ClaudeMessagesPayload,\n requestedQuery: string,\n options: { requestId?: string; signal?: AbortSignal; timeoutMs?: number } = {},\n): Promise<WebSearchExecutionResult> => {\n const backendModel = getWebSearchBackendModel(config)\n const signal = createCopilotRequestSignal(options.signal, options.timeoutMs)\n const response = await fetchCopilot(\n getCopilotProviderContext(config),\n \"/responses\",\n {\n method: \"POST\",\n headers: {\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(\n buildWebSearchRequestPayload(payload, requestedQuery, backendModel),\n ),\n },\n {\n initiator: \"agent\",\n requestId: options.requestId,\n signal,\n timeoutMs: options.timeoutMs,\n },\n )\n\n if (!response.ok) {\n const detail = await readCopilotText(\n response,\n signal,\n options.timeoutMs,\n ).catch(() => \"\")\n return createFailedSearchExecution(\n payload,\n requestedQuery,\n backendModel,\n [\n `Copilot web search is not available for model ${backendModel}.`,\n detail ? `Upstream response: ${detail}` : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n )\n }\n\n const upstream = await readCopilotJson<ResponsesWebSearchResponse>(\n response,\n signal,\n options.timeoutMs,\n )\n const text = getResponseText(upstream)\n const query = getSearchQuery(upstream, requestedQuery)\n const results = parseSearchResults(text)\n\n if (results.length === 0 && !text.trim()) {\n return createFailedSearchExecution(\n payload,\n requestedQuery,\n upstream.model,\n \"Copilot web search did not return search results.\",\n )\n }\n\n return {\n id: upstream.id,\n inputTokens: upstream.usage?.input_tokens ?? 0,\n model: upstream.model,\n outputTokens: upstream.usage?.output_tokens ?? 0,\n query,\n results,\n text,\n }\n}\n\nconst buildSearchResultBlock = (\n toolUseId: string,\n results: Array<WebSearchResult>,\n): ClaudeWebSearchResultBlock => ({\n type: \"web_search_tool_result\",\n tool_use_id: toolUseId,\n content:\n results.length > 0 ?\n results.map((result) => ({\n type: \"web_search_result\" as const,\n title: result.title,\n url: result.url,\n encrypted_content: \"\",\n page_age: null,\n }))\n : {\n type: \"web_search_tool_result_error\",\n error_code: \"unavailable\",\n },\n})\n\nexport const createClaudeWebSearchResponse = (\n search: WebSearchExecutionResult,\n): ClaudeResponse => {\n const toolUseId = `srvtoolu_${randomUUID().replaceAll(\"-\", \"\")}`\n const content: Array<ClaudeAssistantContentBlock> = [\n {\n type: \"server_tool_use\",\n id: toolUseId,\n name: \"web_search\",\n input: { query: search.query },\n },\n buildSearchResultBlock(toolUseId, search.results),\n ]\n\n if (search.text) {\n content.push({ type: \"text\", text: search.text })\n }\n\n return {\n id: search.id,\n type: \"message\",\n role: \"assistant\",\n content,\n model: search.model,\n stop_reason: \"end_turn\",\n stop_sequence: null,\n usage: {\n input_tokens: search.inputTokens,\n output_tokens: search.outputTokens,\n server_tool_use: { web_search_requests: 1 },\n },\n }\n}\n\nconst getWebSearchResultText = (search: WebSearchExecutionResult): string => {\n if (search.results.length === 0) {\n return search.text || \"Web search did not return search results.\"\n }\n\n return [\n `Web search results for query: \"${search.query}\"`,\n \"\",\n ...search.results.map((result, index) =>\n `${index + 1}. ${result.title} - ${result.url}`,\n ),\n ].join(\"\\n\")\n}\n\nconst createWebSearchResultContextMessage = (\n search: WebSearchExecutionResult,\n): Message => ({\n role: \"system\",\n content: [\n \"Trusted bridge retrieval context: the assistant selected web_search, and copilot-relay executed it.\",\n \"Use this context for the final answer. Do not describe it as user-provided or injected. Do not call web_search again.\",\n \"If the user requested a specific output format, answer using only matching information from this context.\",\n \"If the user asked for a URL only, output only that URL with no surrounding text.\",\n \"\",\n `Query: ${search.query}`,\n \"\",\n getWebSearchResultText(search),\n ].join(\"\\n\"),\n})\n\nexport const createFinalWebSearchPayload = (\n payload: ChatCompletionsPayload,\n search: WebSearchExecutionResult,\n): ChatCompletionsPayload => {\n const messages = payload.messages.flatMap<Message>((message) => {\n if (message.role === \"tool\") {\n return [\n {\n role: \"developer\",\n content: [\n \"Prior local tool result from the conversation:\",\n String(message.content ?? \"\"),\n ].join(\"\\n\"),\n },\n ]\n }\n\n if (message.tool_calls && message.tool_calls.length > 0) {\n return message.content ? [{ ...message, tool_calls: undefined }] : []\n }\n\n return [message]\n })\n\n return {\n ...payload,\n stream: false,\n tools: undefined,\n tool_choice: undefined,\n messages: [\n ...messages,\n createWebSearchResultContextMessage(search),\n ],\n }\n}\n\nexport const mergeWebSearchAndFinalResponse = (\n searchResponse: ClaudeResponse,\n finalResponse: ClaudeResponse,\n): ClaudeResponse => ({\n ...finalResponse,\n content: [...searchResponse.content.slice(0, 2), ...finalResponse.content],\n usage: {\n ...finalResponse.usage,\n input_tokens:\n searchResponse.usage.input_tokens + finalResponse.usage.input_tokens,\n output_tokens:\n searchResponse.usage.output_tokens + finalResponse.usage.output_tokens,\n server_tool_use: { web_search_requests: 1 },\n },\n})\n","// Token estimator for Claude Code's /v1/messages/count_tokens endpoint.\nimport type {\n ChatCompletionsPayload,\n ContentPart,\n Message,\n Tool,\n ToolCall,\n} from \"~/copilot/types\"\n\nexport interface TokenizerModel {\n capabilities: {\n tokenizer: string\n }\n id: string\n}\n\nconst encodingMap = {\n o200k_base: () => import(\"gpt-tokenizer/encoding/o200k_base\"),\n cl100k_base: () => import(\"gpt-tokenizer/encoding/cl100k_base\"),\n p50k_base: () => import(\"gpt-tokenizer/encoding/p50k_base\"),\n p50k_edit: () => import(\"gpt-tokenizer/encoding/p50k_edit\"),\n r50k_base: () => import(\"gpt-tokenizer/encoding/r50k_base\"),\n} as const\n\ntype SupportedEncoding = keyof typeof encodingMap\n\ninterface Encoder {\n encode: (text: string) => Array<number>\n}\n\nconst encodingCache = new Map<string, Encoder>()\n\nconst calculateToolCallsTokens = (\n toolCalls: Array<ToolCall>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = 0\n for (const toolCall of toolCalls) {\n tokens += constants.funcInit\n tokens += encoder.encode(JSON.stringify(toolCall)).length\n }\n tokens += constants.funcEnd\n return tokens\n}\n\nconst calculateContentPartsTokens = (\n contentParts: Array<ContentPart>,\n encoder: Encoder,\n): number => {\n let tokens = 0\n for (const part of contentParts) {\n if (part.type === \"image_url\") {\n // Claude Code needs a fast local estimate, not exact upstream billing.\n // Use a fixed image overhead plus URL token count to avoid severe\n // under-counting when screenshots are present.\n tokens += encoder.encode(part.image_url.url).length + 85\n } else if (part.text) {\n tokens += encoder.encode(part.text).length\n }\n }\n return tokens\n}\n\nconst calculateMessageTokens = (\n message: Message,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n // Mirrors OpenAI chat formatting heuristics closely enough for UI budgeting;\n // /count_tokens is advisory and should not call real Copilot services.\n const tokensPerMessage = 3\n const tokensPerName = 1\n let tokens = tokensPerMessage\n for (const [key, value] of Object.entries(message)) {\n if (typeof value === \"string\") {\n tokens += encoder.encode(value).length\n }\n if (key === \"name\") tokens += tokensPerName\n if (key === \"tool_calls\") {\n tokens += calculateToolCallsTokens(\n value as Array<ToolCall>,\n encoder,\n constants,\n )\n }\n if (key === \"content\" && Array.isArray(value)) {\n tokens += calculateContentPartsTokens(\n value as Array<ContentPart>,\n encoder,\n )\n }\n }\n return tokens\n}\n\nconst calculateTokens = (\n messages: Array<Message>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (messages.length === 0) return 0\n let numTokens = 0\n for (const message of messages) {\n numTokens += calculateMessageTokens(message, encoder, constants)\n }\n numTokens += 3\n return numTokens\n}\n\nconst getEncodeChatFunction = async (encoding: string): Promise<Encoder> => {\n if (encodingCache.has(encoding)) {\n const cached = encodingCache.get(encoding)\n if (cached) return cached\n }\n\n const supported = encoding as SupportedEncoding\n if (!(supported in encodingMap)) {\n const fallback = (await encodingMap.o200k_base()) as Encoder\n encodingCache.set(encoding, fallback)\n return fallback\n }\n\n const mod = (await encodingMap[supported]()) as Encoder\n encodingCache.set(encoding, mod)\n return mod\n}\n\nexport const getTokenizerFromModel = (model: TokenizerModel): string =>\n model.capabilities.tokenizer || \"o200k_base\"\n\nconst getModelConstants = (model: TokenizerModel) =>\n // Tool/function overhead differs by tokenizer family. Keep these constants\n // small and explicit so count_tokens remains deterministic in tests.\n model.id === \"gpt-3.5-turbo\" || model.id === \"gpt-4\"\n ? {\n funcInit: 10,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n : {\n funcInit: 7,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n\nconst calculateParameterTokens = (\n key: string,\n prop: unknown,\n context: {\n encoder: Encoder\n constants: ReturnType<typeof getModelConstants>\n },\n): number => {\n const { encoder, constants } = context\n let tokens = constants.propKey\n\n if (typeof prop !== \"object\" || prop === null) return tokens\n\n const param = prop as {\n type?: string\n description?: string\n enum?: Array<unknown>\n [key: string]: unknown\n }\n\n const paramName = key\n const paramType = param.type || \"string\"\n let paramDesc = param.description || \"\"\n\n if (param.enum && Array.isArray(param.enum)) {\n tokens += constants.enumInit\n for (const item of param.enum) {\n tokens += constants.enumItem\n tokens += encoder.encode(String(item)).length\n }\n }\n\n if (paramDesc.endsWith(\".\")) paramDesc = paramDesc.slice(0, -1)\n\n const line = `${paramName}:${paramType}:${paramDesc}`\n tokens += encoder.encode(line).length\n\n const excludedKeys = new Set([\"type\", \"description\", \"enum\"])\n for (const propertyName of Object.keys(param)) {\n if (excludedKeys.has(propertyName)) continue\n const propertyValue = param[propertyName]\n const propertyText =\n typeof propertyValue === \"string\" ? propertyValue : JSON.stringify(propertyValue)\n tokens += encoder.encode(`${propertyName}:${propertyText}`).length\n }\n\n return tokens\n}\n\nconst calculateParametersTokens = (\n parameters: unknown,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (!parameters || typeof parameters !== \"object\") return 0\n\n const params = parameters as Record<string, unknown>\n let tokens = 0\n\n for (const [key, value] of Object.entries(params)) {\n if (key === \"properties\") {\n const properties = value as Record<string, unknown>\n if (Object.keys(properties).length > 0) {\n tokens += constants.propInit\n for (const propKey of Object.keys(properties)) {\n tokens += calculateParameterTokens(propKey, properties[propKey], {\n encoder,\n constants,\n })\n }\n }\n } else {\n const paramText =\n typeof value === \"string\" ? value : JSON.stringify(value)\n tokens += encoder.encode(`${key}:${paramText}`).length\n }\n }\n\n return tokens\n}\n\nconst calculateToolTokens = (\n tool: Tool,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = constants.funcInit\n const func = tool.function\n const fName = func.name\n let fDesc = func.description || \"\"\n if (fDesc.endsWith(\".\")) fDesc = fDesc.slice(0, -1)\n tokens += encoder.encode(`${fName}:${fDesc}`).length\n if (typeof func.parameters === \"object\" && func.parameters !== null) {\n tokens += calculateParametersTokens(func.parameters, encoder, constants)\n }\n return tokens\n}\n\nexport const numTokensForTools = (\n tools: Array<Tool>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let funcTokenCount = 0\n for (const tool of tools) {\n funcTokenCount += calculateToolTokens(tool, encoder, constants)\n }\n funcTokenCount += constants.funcEnd\n return funcTokenCount\n}\n\nexport const getTokenCount = async (\n payload: ChatCompletionsPayload,\n model: TokenizerModel,\n): Promise<{ input: number; output: number }> => {\n const tokenizer = getTokenizerFromModel(model)\n const encoder = await getEncodeChatFunction(tokenizer)\n\n const inputMessages = payload.messages.filter((msg) => msg.role !== \"assistant\")\n const outputMessages = payload.messages.filter((msg) => msg.role === \"assistant\")\n\n const constants = getModelConstants(model)\n let inputTokens = calculateTokens(inputMessages, encoder, constants)\n if (payload.tools && payload.tools.length > 0) {\n inputTokens += numTokensForTools(payload.tools, encoder, constants)\n }\n const outputTokens = calculateTokens(outputMessages, encoder, constants)\n\n return { input: inputTokens, output: outputTokens }\n}\n","// Claude Code route surface: /v1/messages, /v1/messages/count_tokens, and /v1/models.\nimport { Hono } from \"hono\"\nimport { streamSSE } from \"hono/streaming\"\n\nimport {\n type ClaudeAssistantContentBlock,\n type ClaudeMessagesPayload,\n type ClaudeResponse,\n type ClaudeStreamEventData,\n type ClaudeStreamState,\n} from \"~/claude/types\"\nimport {\n translateModelName,\n translateToClaude,\n translateToOpenAI,\n} from \"~/claude/translate\"\nimport {\n translateChunkToClaudeEvents,\n translateErrorToClaudeErrorEvent,\n} from \"~/claude/stream\"\nimport {\n createClaudeToolNameMapper,\n getToolNameMapperOptionsForModel,\n} from \"~/claude/tool-names\"\nimport {\n createClaudeWebSearchExecution,\n createClaudeWebSearchResponse,\n createFinalWebSearchPayload,\n getClaudeWebSearchToolCallFromChatResponse,\n hasClaudeWebSearch,\n mergeWebSearchAndFinalResponse,\n prepareClaudeWebSearchDecisionPayload,\n} from \"~/claude/web-search\"\nimport type { ProxyEnv } from \"~/lib/config\"\nimport { HTTPError, ProxyNotImplementedError } from \"~/lib/error\"\nimport { log } from \"~/lib/log\"\nimport { getExposedModelIds } from \"~/lib/models\"\nimport { getTokenCount, type TokenizerModel } from \"~/lib/tokenizer\"\nimport type { ChatCompletionChunk, ChatCompletionResponse } from \"~/copilot/types\"\nimport { createChatCompletions } from \"~/copilot/chat\"\nimport { createCopilotRequestSignal } from \"~/copilot/client\"\n\nexport const claudeRoutes = new Hono<ProxyEnv>()\n\nconst createTokenCountModel = (modelId: string): TokenizerModel => ({\n capabilities: { tokenizer: \"o200k_base\" },\n id: modelId,\n})\n\nconst isNonStreamingResponse = (\n response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse =>\n typeof response === \"object\"\n && response !== null\n && Object.hasOwn(response, \"choices\")\n\nconst getClaudeRequestedThinkEffort = (\n payload: ClaudeMessagesPayload,\n): string => payload.reasoning_effort ?? \"none\"\n\nconst getClaudeRequestedThinking = (\n payload: ClaudeMessagesPayload,\n): string => {\n if (!payload.thinking) {\n return \"none\"\n }\n\n return [\n `type:${payload.thinking.type}`,\n `budget:${payload.thinking.budget_tokens ?? \"none\"}`,\n ].join(\",\")\n}\n\nconst eventsFromClaudeResponse = (\n response: ClaudeResponse,\n): Array<ClaudeStreamEventData> => {\n // When Claude Code asks for streaming but Copilot returned a completed JSON\n // response, synthesize the minimal Claude SSE sequence so client bookkeeping\n // remains identical to a real streaming response.\n const events: Array<ClaudeStreamEventData> = [\n {\n type: \"message_start\",\n message: {\n id: response.id,\n type: response.type,\n role: response.role,\n content: [],\n model: response.model,\n stop_reason: null,\n stop_sequence: null,\n usage: response.usage,\n },\n },\n ]\n\n response.content.forEach((block: ClaudeAssistantContentBlock, index) => {\n events.push({\n type: \"content_block_start\",\n index,\n content_block: block,\n })\n\n if (block.type === \"text\") {\n events.push({\n type: \"content_block_delta\",\n index,\n delta: { type: \"text_delta\", text: block.text },\n })\n } else if (block.type === \"thinking\") {\n events.push({\n type: \"content_block_delta\",\n index,\n delta: { type: \"thinking_delta\", thinking: block.thinking },\n })\n } else if (block.type === \"tool_use\" || block.type === \"server_tool_use\") {\n events.push({\n type: \"content_block_delta\",\n index,\n delta: {\n type: \"input_json_delta\",\n partial_json: JSON.stringify(block.input),\n },\n })\n }\n\n events.push({ type: \"content_block_stop\", index })\n })\n\n events.push({\n type: \"message_delta\",\n delta: {\n stop_reason: response.stop_reason,\n stop_sequence: response.stop_sequence,\n },\n usage: { output_tokens: response.usage.output_tokens },\n })\n events.push({ type: \"message_stop\" })\n return events\n}\n\ntype ClaudeStreamEventWriter = (\n event: ClaudeStreamEventData,\n) => Promise<void>\n\nconst createQueuedClaudeStreamWriter = (\n write: ClaudeStreamEventWriter,\n): ClaudeStreamEventWriter => {\n let pending = Promise.resolve()\n\n return (event) => {\n pending = pending.then(() => write(event))\n return pending\n }\n}\n\nconst writeClaudeStreamEvents = async (\n events: Array<ClaudeStreamEventData>,\n writeEvent: ClaudeStreamEventWriter,\n): Promise<void> => {\n for (const event of events) {\n await writeEvent(event)\n }\n}\n\nconst handleClaudeMessageRequest = async (\n config: ProxyEnv[\"Variables\"][\"config\"],\n claudePayload: ClaudeMessagesPayload,\n requestSignal: AbortSignal | undefined,\n requestId: string,\n writeEvent?: ClaudeStreamEventWriter,\n): Promise<ClaudeResponse | undefined> => {\n const upstreamModel = translateModelName(claudePayload.model)\n const shouldLetModelDecideWebSearch = hasClaudeWebSearch(claudePayload)\n const decisionPayload =\n shouldLetModelDecideWebSearch ?\n prepareClaudeWebSearchDecisionPayload(claudePayload)\n : claudePayload\n const toolNameMapper = createClaudeToolNameMapper(decisionPayload.tools, {\n ...getToolNameMapperOptionsForModel(upstreamModel),\n })\n const openAIPayload = translateToOpenAI(\n decisionPayload,\n undefined,\n toolNameMapper,\n )\n if (shouldLetModelDecideWebSearch) {\n openAIPayload.stream = false\n }\n const response = await createChatCompletions(config, openAIPayload, {\n client: \"claude\",\n requestedModel: claudePayload.model,\n requestedThinkEffort: getClaudeRequestedThinkEffort(claudePayload),\n requestedThinking: getClaudeRequestedThinking(claudePayload),\n requestId,\n signal: requestSignal,\n timeoutMs: config.upstreamTimeoutMs,\n })\n\n if (isNonStreamingResponse(response)) {\n const webSearchToolCall = shouldLetModelDecideWebSearch ?\n getClaudeWebSearchToolCallFromChatResponse(response, toolNameMapper)\n : undefined\n let claudeResponse: ClaudeResponse\n\n if (webSearchToolCall) {\n const search = await createClaudeWebSearchExecution(\n config,\n claudePayload,\n webSearchToolCall.query,\n { requestId, signal: requestSignal, timeoutMs: config.upstreamTimeoutMs },\n )\n const searchResponse = createClaudeWebSearchResponse(search)\n\n if (search.results.length === 0) {\n claudeResponse = searchResponse\n } else {\n const finalResponse = await createChatCompletions(\n config,\n createFinalWebSearchPayload(openAIPayload, search),\n {\n client: \"claude\",\n requestedModel: claudePayload.model,\n requestedThinkEffort: getClaudeRequestedThinkEffort(claudePayload),\n requestedThinking: getClaudeRequestedThinking(claudePayload),\n requestId,\n signal: requestSignal,\n timeoutMs: config.upstreamTimeoutMs,\n },\n )\n\n if (!isNonStreamingResponse(finalResponse)) {\n throw new HTTPError(\n \"Claude web search final answer request unexpectedly streamed\",\n new Response(\"Claude web search final answer request unexpectedly streamed\", {\n status: 502,\n headers: { \"content-type\": \"text/plain\" },\n }),\n )\n }\n\n claudeResponse = mergeWebSearchAndFinalResponse(\n searchResponse,\n translateToClaude(finalResponse, toolNameMapper),\n )\n }\n } else {\n claudeResponse = translateToClaude(response, toolNameMapper)\n }\n\n if (writeEvent) {\n await writeClaudeStreamEvents(\n eventsFromClaudeResponse(claudeResponse),\n writeEvent,\n )\n return undefined\n }\n\n return claudeResponse\n }\n\n if (shouldLetModelDecideWebSearch) {\n throw new HTTPError(\n \"Claude web search model-decision request unexpectedly streamed\",\n new Response(\"Claude web search model-decision request unexpectedly streamed\", {\n status: 502,\n headers: { \"content-type\": \"text/plain\" },\n }),\n )\n }\n\n if (!writeEvent) {\n throw new HTTPError(\n \"Claude non-streaming request unexpectedly streamed\",\n new Response(\"Claude non-streaming request unexpectedly streamed\", {\n status: 502,\n headers: { \"content-type\": \"text/plain\" },\n }),\n )\n }\n\n const streamState: ClaudeStreamState = {\n messageStartSent: false,\n contentBlockIndex: 0,\n contentBlockOpen: false,\n thinkingBlockOpen: false,\n toolCalls: {},\n }\n\n for await (const rawEvent of response) {\n if (rawEvent.data === \"[DONE]\") {\n break\n }\n if (!rawEvent.data) {\n continue\n }\n\n let chunk: ChatCompletionChunk\n try {\n chunk = JSON.parse(rawEvent.data) as ChatCompletionChunk\n } catch {\n continue\n }\n\n await writeClaudeStreamEvents(\n translateChunkToClaudeEvents(\n chunk,\n streamState,\n toolNameMapper,\n ),\n writeEvent,\n )\n }\n\n return undefined\n}\n\nclaudeRoutes.get(\"/models\", (c) =>\n c.json({\n object: \"list\",\n data: getExposedModelIds().map((id) => ({\n id,\n object: \"model\",\n created: 0,\n owned_by: \"github-copilot\",\n })),\n }),\n)\n\nclaudeRoutes.post(\"/messages\", async (c) => {\n const config = c.get(\"config\")\n const requestId = c.get(\"requestId\")\n const claudePayload = await c.req.json<ClaudeMessagesPayload>()\n const requestSignal = createCopilotRequestSignal(\n c.req.raw.signal,\n config.upstreamTimeoutMs,\n )\n log.debug(\"Full Claude request payload\", { payload: claudePayload })\n\n if (claudePayload.stream) {\n return streamSSE(c, async (stream) => {\n const streamStarted = performance.now()\n const writeEvent = createQueuedClaudeStreamWriter((event) =>\n stream.writeSSE({\n event: event.type,\n data: JSON.stringify(event),\n }),\n )\n\n try {\n await handleClaudeMessageRequest(\n config,\n claudePayload,\n requestSignal,\n requestId,\n writeEvent,\n )\n } catch (error) {\n log.error(\"Error during Claude stream request:\", error)\n const errorEvent = translateErrorToClaudeErrorEvent()\n await writeEvent(errorEvent)\n } finally {\n log.info(\n `request_id=${requestId} stream completed ${Math.round(performance.now() - streamStarted)}ms`,\n )\n }\n })\n }\n\n try {\n return c.json(await handleClaudeMessageRequest(\n config,\n claudePayload,\n requestSignal,\n requestId,\n ))\n } catch (error) {\n if (error instanceof ProxyNotImplementedError) {\n c.set(\"requestErrorMessage\", error.message)\n return c.json(\n { error: { type: error.name, message: error.message } },\n 501,\n )\n }\n\n if (error instanceof HTTPError) {\n const text = await error.response.text().catch(() => \"\")\n c.set(\"requestErrorMessage\", error.detail ?? text.slice(0, 240))\n return new Response(text, {\n status: error.response.status,\n headers: {\n \"content-type\":\n error.response.headers.get(\"content-type\") ?? \"application/json\",\n },\n })\n }\n\n throw error\n }\n})\n\nclaudeRoutes.post(\"/messages/count_tokens\", async (c) => {\n try {\n const claudeBeta = c.req.header(\"claude-beta\")\n const claudePayload = await c.req.json<ClaudeMessagesPayload>()\n const openAIPayload = translateToOpenAI(claudePayload)\n const exposedModels = getExposedModelIds()\n const selectedModel = createTokenCountModel(\n openAIPayload.model === exposedModels[1] ? exposedModels[1] : exposedModels[0],\n )\n\n const tokenCount = await getTokenCount(openAIPayload, selectedModel)\n const effectiveModelId = selectedModel.id\n\n // Claude Code already accounts for MCP tool payloads differently. For\n // non-MCP local tools, add a small Claude-family overhead to avoid\n // under-reporting context use in the UI.\n if (claudePayload.tools && claudePayload.tools.length > 0) {\n let mcpToolExist = false\n if (claudeBeta?.startsWith(\"claude-code\")) {\n mcpToolExist = claudePayload.tools.some((tool) =>\n tool.name.startsWith(\"mcp__\"),\n )\n }\n if (!mcpToolExist && effectiveModelId.startsWith(\"claude\")) {\n tokenCount.input += 346\n }\n }\n\n const multiplier = effectiveModelId.startsWith(\"claude\") ? 1.15 : 1\n const finalTokenCount = Math.round(\n (tokenCount.input + tokenCount.output) * multiplier,\n )\n\n return c.json({ input_tokens: Math.max(1, finalTokenCount) })\n } catch (error) {\n log.error(\"Error counting tokens:\", error)\n return c.json({ input_tokens: 1 })\n }\n})\n","// HTTP server assembly: exposes only Claude Code-compatible public routes.\nimport { randomUUID } from \"node:crypto\"\n\nimport { createAdaptorServer, type ServerType } from \"@hono/node-server\"\nimport { Hono } from \"hono\"\nimport { cors } from \"hono/cors\"\n\nimport type { ProxyConfig, ProxyEnv } from \"~/lib/config\"\nimport { log } from \"~/lib/log\"\nimport { claudeRoutes } from \"~/routes/claude\"\n\nconst loggedRequestHeaders = [\n \"anthropic-beta\",\n \"anthropic-version\",\n \"claude-beta\",\n \"content-type\",\n]\n\nconst readRequestPayloadForLog = async (request: Request): Promise<unknown> => {\n const text = await request.clone().text().catch(() => \"\")\n if (!text) {\n return undefined\n }\n\n try {\n return JSON.parse(text) as unknown\n } catch {\n return text\n }\n}\n\nconst getLoggedHeaders = (request: Request): Record<string, string> =>\n Object.fromEntries(\n loggedRequestHeaders.flatMap((name) => {\n const value = request.headers.get(name)\n return value ? [[name, value]] : []\n }),\n )\n\nconst formatStatusLog = (\n requestId: string,\n method: string,\n path: string,\n status: number,\n ms: number,\n errorMessage: string | undefined,\n): string => {\n const base = `request_id=${requestId} ${method} ${path} -> ${status} ${ms}ms`\n return status >= 400 && errorMessage ? `${base} error=${JSON.stringify(errorMessage)}` : base\n}\n\nexport const createServer = (config: ProxyConfig) => {\n const app = new Hono<ProxyEnv>()\n\n app.use(\"*\", async (c, next) => {\n const requestId = randomUUID()\n c.set(\"config\", config)\n c.set(\"requestId\", requestId)\n c.header(\"x-copilot-relay-request-id\", requestId)\n log.info(`request_id=${requestId} request received method=${c.req.method} path=${c.req.path}`)\n\n const started = performance.now()\n try {\n await next()\n } finally {\n const ms = Math.round(performance.now() - started)\n // Emit exactly one info-level request summary even when downstream route\n // handling throws; deeper diagnostics belong to debug/error logs.\n log.info(formatStatusLog(\n requestId,\n c.req.method,\n c.req.path,\n c.res.status,\n ms,\n c.get(\"requestErrorMessage\"),\n ))\n }\n })\n app.use(\"*\", cors())\n\n app.onError((error, c) => {\n c.set(\"requestErrorMessage\", error.message)\n log.error(\"Unhandled Claude API request error\", {\n method: c.req.method,\n path: c.req.path,\n requestId: c.get(\"requestId\"),\n error,\n })\n return c.json({ error: { message: \"Internal server error\" } }, 500)\n })\n\n app.get(\"/\", (c) =>\n c.json({\n name: \"copilot-relay\",\n status: \"ok\",\n }),\n )\n\n app.get(\"/healthz\", (c) => c.json({ ok: true }))\n app.route(\"/v1\", claudeRoutes)\n app.notFound(async (c) => {\n const message = \"Unsupported Claude API route\"\n c.set(\"requestErrorMessage\", message)\n log.error(\"Unsupported Claude API request\", {\n method: c.req.method,\n path: c.req.path,\n requestId: c.get(\"requestId\"),\n headers: getLoggedHeaders(c.req.raw),\n payload: await readRequestPayloadForLog(c.req.raw),\n })\n return c.json({ error: { message } }, 500)\n })\n\n return app\n}\n\nexport const startServer = (config: ProxyConfig): Promise<ServerType> =>\n new Promise((resolve, reject) => {\n const server = createAdaptorServer({\n fetch: createServer(config).fetch,\n hostname: config.host,\n port: config.port,\n })\n\n const onError = (error: Error) => {\n server.off(\"listening\", onListening)\n reject(error)\n }\n const onListening = () => {\n server.off(\"error\", onError)\n resolve(server)\n }\n\n server.once(\"error\", onError)\n server.once(\"listening\", onListening)\n server.listen(config.port, config.host)\n })\n","// `copilot-relay start`: loads config, validates upstream access, and starts the local Claude Code proxy.\nimport { defineCommand } from \"citty\"\n\nimport { setupProxyAuth } from \"~/lib/auth\"\nimport { readAppConfig, watchAppConfig, type AppConfig } from \"~/lib/app-config\"\nimport { applyClaudeConfig } from \"~/lib/claude-settings\"\nimport { readProxyConfig } from \"~/lib/config\"\nimport { claudeConfigPath as defaultClaudeConfigPath } from \"~/lib/defaults\"\nimport { clearRelayPidFile, writeRelayPidFile } from \"~/lib/lifecycle\"\nimport { cleanupLogs, log, setLogLevel } from \"~/lib/log\"\nimport { getExposedModelIds } from \"~/lib/models\"\nimport { validateUpstream } from \"~/lib/preflight\"\nimport { runtimeState } from \"~/lib/state\"\nimport { appVersion } from \"~/lib/version\"\nimport { startServer } from \"~/server\"\n\nexport async function startRelay(appConfig?: AppConfig): Promise<void> {\n appConfig ??= await readAppConfig()\n setLogLevel(appConfig.logLevel)\n await cleanupLogs(appConfig.logRetentionDays)\n\n const claudeConfigPath = defaultClaudeConfigPath\n const config = readProxyConfig(appConfig)\n const applyRuntimeConfig = (nextConfig: AppConfig) => {\n // Hot reload updates behavior for future requests; it intentionally does\n // not rebind the already-listening socket when host or port changes.\n setLogLevel(nextConfig.logLevel)\n void cleanupLogs(nextConfig.logRetentionDays)\n runtimeState.debug = nextConfig.logLevel === \"debug\"\n runtimeState.thinkEffort = nextConfig.thinkEffort\n config.copilotBaseUrl = nextConfig.copilotBaseUrl\n config.host = nextConfig.host\n config.port = nextConfig.port\n config.upstreamTimeoutMs = nextConfig.upstreamTimeoutSeconds * 1000\n config.webSearchBackend = nextConfig.webSearchBackend\n runtimeState.modelRouting = {\n gptModel: nextConfig.gptModel,\n opusModel: nextConfig.opusModel,\n }\n }\n applyRuntimeConfig(appConfig)\n\n log.info(`Log level: ${appConfig.logLevel}`)\n log.info(`Think effort: ${appConfig.thinkEffort}`)\n log.info(`Upstream timeout: ${appConfig.upstreamTimeoutSeconds}s`)\n log.info(`Exposed models: ${getExposedModelIds().join(\", \")}`)\n\n const authSession = await setupProxyAuth(config)\n\n try {\n await validateUpstream(config, appConfig.thinkEffort)\n } catch (error) {\n log.error(\"Startup preflight failed:\", error)\n process.exit(1)\n }\n\n const server = await startServer(config)\n await writeRelayPidFile(config)\n\n log.info(`copilot-relay version: ${appVersion}`)\n if (authSession.githubLogin) {\n log.info(`GitHub user: ${authSession.githubLogin}`)\n } else {\n log.error(\"GitHub user: unavailable\")\n }\n\n log.info(\n `copilot-relay listening on http://${config.host}:${config.port}`,\n )\n log.info(`copilot base url: ${config.copilotBaseUrl}`)\n\n const baseUrl = `http://${config.host}:${config.port}`\n if (appConfig.claudeSetup) {\n try {\n const claudeResult = await applyClaudeConfig({\n baseUrl,\n configPath: claudeConfigPath,\n })\n if (claudeResult.changed) {\n log.info(\n `claude settings ${claudeResult.created ? \"created\" : \"updated\"}: ${claudeResult.configPath}`,\n )\n if (\n claudeResult.previousBaseUrl\n && claudeResult.previousBaseUrl !== baseUrl\n ) {\n log.info(\n `ANTHROPIC_BASE_URL: ${claudeResult.previousBaseUrl} → ${baseUrl}`,\n )\n }\n } else {\n log.info(\n `claude settings already up to date: ${claudeResult.configPath}`,\n )\n }\n } catch (error) {\n log.error(\n `Could not update claude settings (${claudeConfigPath}):`,\n error,\n )\n }\n }\n watchAppConfig((nextConfig) => {\n applyRuntimeConfig(nextConfig)\n log.info(\n `Config reloaded: logLevel=${nextConfig.logLevel} thinkEffort=${nextConfig.thinkEffort} upstreamTimeoutSeconds=${nextConfig.upstreamTimeoutSeconds}`,\n )\n })\n\n const shutdown = (signal: NodeJS.Signals) => {\n log.info(`Received ${signal}; shutting down copilot-relay`)\n server.close((error) => {\n if (error) {\n log.error(\"Error while shutting down copilot-relay:\", error)\n process.exitCode = 1\n }\n })\n }\n process.once(\"SIGINT\", shutdown)\n process.once(\"SIGTERM\", shutdown)\n\n try {\n await new Promise<void>((resolve, reject) => {\n server.on(\"close\", resolve)\n server.on(\"error\", reject)\n })\n } finally {\n process.off(\"SIGINT\", shutdown)\n process.off(\"SIGTERM\", shutdown)\n await clearRelayPidFile()\n }\n}\n\nexport const start = defineCommand({\n meta: {\n name: \"start\",\n description: \"Start the copilot-relay HTTP server.\",\n },\n async run() {\n await startRelay()\n },\n})\n","// `copilot-relay restart`: stop stale local relay processes, then start normally.\nimport { defineCommand } from \"citty\"\n\nimport { readAppConfig } from \"~/lib/app-config\"\nimport { readProxyConfig } from \"~/lib/config\"\nimport { cleanupLogs, log, setLogLevel } from \"~/lib/log\"\nimport { stopExistingRelay } from \"~/lib/lifecycle\"\nimport { startRelay } from \"./start\"\n\nexport const restart = defineCommand({\n meta: {\n name: \"restart\",\n description: \"Stop any existing copilot-relay instance and start a new one.\",\n },\n async run() {\n const appConfig = await readAppConfig()\n setLogLevel(appConfig.logLevel)\n await cleanupLogs(appConfig.logRetentionDays)\n\n const stopped = await stopExistingRelay(readProxyConfig(appConfig))\n if (stopped.length > 0) {\n log.info(`Stopped copilot-relay pid(s): ${stopped.join(\", \")}`)\n }\n log.info(\"Starting copilot-relay\")\n\n await startRelay(appConfig)\n },\n})\n","// `copilot-relay stop`: terminate all detected local relay server instances.\nimport { defineCommand } from \"citty\"\n\nimport { readAppConfig } from \"~/lib/app-config\"\nimport { readProxyConfig } from \"~/lib/config\"\nimport { cleanupLogs, log, setLogLevel } from \"~/lib/log\"\nimport { stopExistingRelay } from \"~/lib/lifecycle\"\n\nexport const stop = defineCommand({\n meta: {\n name: \"stop\",\n description: \"Stop all detected copilot-relay server instances.\",\n },\n async run() {\n const appConfig = await readAppConfig()\n setLogLevel(appConfig.logLevel)\n await cleanupLogs(appConfig.logRetentionDays)\n\n const stopped = await stopExistingRelay(readProxyConfig(appConfig))\n if (stopped.length > 0) {\n log.info(`Stopped copilot-relay pid(s): ${stopped.join(\", \")}`)\n }\n },\n})\n","#!/usr/bin/env node\n\n// CLI entrypoint: wires top-level commands without owning runtime behavior.\nimport { defineCommand, runMain } from \"citty\"\n\nimport { auth } from \"./auth\"\nimport { restart } from \"./restart\"\nimport { start } from \"./start\"\nimport { stop } from \"./stop\"\n\nconst main = defineCommand({\n meta: {\n name: \"copilot-relay\",\n description:\n \"Yet, just another relay for Claude Code to use a GitHub Copilot subscription.\",\n },\n subCommands: { auth, restart, start, stop },\n})\n\nawait runMain(main)\n"],"mappings":"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"}