copilot-relay 0.0.2 → 0.0.4

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>","copilotVersion","editorPluginVersion","userAgent","copilotTokenRefreshTimer: ReturnType<typeof setTimeout> | undefined","resolve","payload: StoredCopilotToken","refreshIn","refreshIn: number","runtimeState: RuntimeState","defaultReasoningEffort: ReasoningEffort","defaultModelRouting: ModelRoutingConfig","defaultConfig: AppConfig","config: Record<string, unknown>","logRetentionDays","config: AppConfig","configPath","parsed: Record<string, unknown>","env: Record<string, unknown>","next: Record<string, unknown>","lastError: unknown","path","path","state: ResponseTranslationState","chunks: Array<ResponseStreamEventMessage>","translated: Array<ResponsesInputItem>","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","events: Array<ClaudeStreamEventData>","events","streamState: ClaudeStreamState","chunk: ChatCompletionChunk","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/claude-settings.ts","../src/lib/defaults.ts","../src/copilot/client.ts","../src/lib/upstream-diagnostics.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/lib/tokenizer.ts","../src/routes/claude.ts","../src/server.ts","../src/start.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 response: Response\n\n constructor(message: string, response: Response) {\n super(message)\n this.name = \"HTTPError\"\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\")\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}\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 silent: -Infinity,\n error: 0,\n warn: 1,\n info: 3,\n debug: 4,\n trace: 5,\n}\n\nexport const setLogLevel = (level: LogLevelName): void => {\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 void writeLogFile(level, args).catch(() => undefined)\n return fn(...args)\n }) as T\n\nconsola.error = wrapFileLog(\"error\", consola.error.bind(consola))\nconsola.warn = wrapFileLog(\"warn\", consola.warn.bind(consola))\nconsola.info = wrapFileLog(\"info\", consola.info.bind(consola))\nconsola.success = wrapFileLog(\"success\", consola.success.bind(consola))\nconsola.debug = wrapFileLog(\"debug\", consola.debug.bind(consola))\nconsola.trace = wrapFileLog(\"trace\", consola.trace.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.debug(`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.success(`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.warn(\"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.debug(\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.debug(\"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.debug(`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.warn(\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.success(`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 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 = [\"silent\", \"error\", \"warn\", \"info\", \"debug\", \"trace\"] 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}\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}\n\nexport const isLogLevelName = (value: unknown): value is LogLevelName =>\n typeof value === \"string\"\n && logLevels.includes(value.toLowerCase() as LogLevelName)\n\nconst normalizeLogLevel = (value: unknown): LogLevelName | undefined =>\n isLogLevelName(value) ? (value.toLowerCase() as LogLevelName) : undefined\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\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 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 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 \"# silent - no logs\",\n \"# error - startup/preflight/request failures only\",\n \"# warn - error logs plus recoverable warnings\",\n \"# info - warn logs plus startup status, preflight status, HTTP requests,\",\n \"# and model routing summaries\",\n \"# debug - info logs plus Copilot upstream timings, token refresh scheduling,\",\n \"# and upstream error request summaries\",\n \"# trace - debug logs plus full Claude request payloads and full upstream\",\n \"# Copilot request payloads without redaction\",\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 \"# 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\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 }\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 // Keep the active config if the file is temporarily invalid.\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 vsCodeVersion: string\n}\n\nexport interface ProxyEnv {\n Variables: {\n config: ProxyConfig\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 vsCodeVersion: vscodeVersion,\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.success(\"copilot-relay auth completed\")\n },\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 ended up being a\n * silent third source of truth alongside `~/.claude/settings.json`, which\n * caused subtle port-mismatch bugs. copilot-relay now relies on these defaults\n * plus 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 type { ProxyConfig } from \"~/lib/config\"\nimport { 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\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}\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\nconst buildHeaders = (\n provider: CopilotProviderContext,\n init: RequestInit,\n options: FetchCopilotOptions,\n): Headers => {\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\", randomUUID())\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 headers\n}\n\nexport const fetchCopilot = async (\n provider: CopilotProviderContext,\n path: string,\n init: RequestInit,\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 let lastError: unknown\n\n for (let attempt = 1; attempt <= maxFetchAttempts; attempt++) {\n try {\n const started = performance.now()\n const response = await fetch(`${provider.baseUrl}${path}`, {\n ...init,\n headers: buildHeaders(provider, init, options),\n })\n const ms = Math.round(performance.now() - started)\n log.debug(\n `Copilot ${init.method ?? \"GET\"} ${path} -> ${response.status} ${ms}ms (attempt ${attempt})`,\n )\n\n if (!shouldRetryResponse(response) || attempt === maxFetchAttempts) {\n return response\n }\n log.warn(\n `Copilot ${path} returned ${response.status}; retrying (${attempt}/${maxFetchAttempts})`,\n )\n } catch (error) {\n lastError = error\n if (attempt === maxFetchAttempts) {\n throw error\n }\n log.warn(\n `Copilot ${path} request failed; retrying (${attempt}/${maxFetchAttempts})`,\n error,\n )\n }\n }\n\n throw lastError\n}\n","const openaiToolNamePattern = /^[A-Za-z0-9_-]{1,64}$/\nconst toolSchemaSuspectKeys = new Set([\n \"$defs\",\n \"allOf\",\n \"definitions\",\n \"dependentRequired\",\n \"dependentSchemas\",\n \"else\",\n \"if\",\n \"not\",\n \"oneOf\",\n \"patternProperties\",\n \"then\",\n])\nconst maxDiagnosticItems = 8\n\n// Reduces upstream tool-schema details into safe diagnostics for debug logs.\nexport type ToolDiagnostics = {\n count: number\n invalidNames?: Array<string>\n suspiciousSchemas?: Array<{\n keys: Array<string>\n name: string\n }>\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value)\n\nconst getToolName = (tool: unknown): string => {\n if (!isRecord(tool)) {\n return \"\"\n }\n\n const functionValue = tool.function\n if (isRecord(functionValue) && typeof functionValue.name === \"string\") {\n return functionValue.name\n }\n\n return typeof tool.name === \"string\" ? tool.name : \"\"\n}\n\nconst getToolParameters = (tool: unknown): unknown => {\n if (!isRecord(tool)) {\n return undefined\n }\n\n const functionValue = tool.function\n if (isRecord(functionValue) && \"parameters\" in functionValue) {\n return functionValue.parameters\n }\n\n return tool.parameters\n}\n\nconst collectSuspiciousSchemaKeys = (\n value: unknown,\n path = \"$\",\n keys: Array<string> = [],\n): Array<string> => {\n if (keys.length >= maxDiagnosticItems) {\n return keys\n }\n\n if (Array.isArray(value)) {\n for (const [index, item] of value.entries()) {\n collectSuspiciousSchemaKeys(item, `${path}[${index}]`, keys)\n if (keys.length >= maxDiagnosticItems) {\n break\n }\n }\n return keys\n }\n\n if (!isRecord(value)) {\n return keys\n }\n\n for (const [key, nestedValue] of Object.entries(value)) {\n const nextPath = `${path}.${key}`\n if (toolSchemaSuspectKeys.has(key)) {\n if (!keys.includes(nextPath)) {\n keys.push(nextPath)\n }\n if (keys.length >= maxDiagnosticItems) {\n break\n }\n }\n collectSuspiciousSchemaKeys(nestedValue, nextPath, keys)\n if (keys.length >= maxDiagnosticItems) {\n break\n }\n }\n\n return keys\n}\n\nexport const summarizeToolsForDiagnostics = (\n tools: unknown,\n): ToolDiagnostics | undefined => {\n if (!Array.isArray(tools) || tools.length === 0) {\n return undefined\n }\n\n const invalidNames = tools\n .map((tool) => getToolName(tool))\n .filter((name) => !openaiToolNamePattern.test(name))\n .slice(0, maxDiagnosticItems)\n\n const suspiciousSchemas = tools.flatMap((tool) => {\n const name = getToolName(tool) || \"<missing>\"\n const keys = collectSuspiciousSchemaKeys(getToolParameters(tool))\n return keys.length > 0 ?\n [\n {\n keys,\n name,\n },\n ]\n : []\n }).slice(0, maxDiagnosticItems)\n\n return {\n count: tools.length,\n ...(invalidNames.length > 0 ? { invalidNames } : {}),\n ...(suspiciousSchemas.length > 0 ? { suspiciousSchemas } : {}),\n }\n}\n","// Internal conversion between Copilot Responses API payloads and chat-completion-like results.\nimport { 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 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 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 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\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 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 summarizeToolsForDiagnostics,\n type ToolDiagnostics,\n} from \"~/lib/upstream-diagnostics\"\nimport { fetchCopilot, getCopilotProviderContext } 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} from \"./responses\"\n\nconst usesMaxCompletionTokens = (modelId: string): boolean =>\n modelId.startsWith(\"gpt-5\")\n\ntype ClientKind = \"claude\" | \"generic\"\n\ninterface CreateChatCompletionsOptions {\n client?: ClientKind\n requestedModel?: string\n requestedThinkEffort?: string\n requestedThinking?: string\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\ntype RequestDiagnostics = {\n max_completion_tokens?: number | null\n max_tokens?: number | null\n message_count: number\n output_config_effort?: unknown\n reasoning_effort?: unknown\n stream?: boolean\n tool_choice?: unknown\n tools?: ToolDiagnostics\n}\n\nconst summarizeRequestForDiagnostics = (\n payload: ChatCompletionsRequestPayload,\n): RequestDiagnostics => ({\n max_completion_tokens: payload.max_completion_tokens,\n max_tokens: payload.max_tokens,\n message_count: payload.messages.length,\n output_config_effort: payload.output_config?.effort,\n reasoning_effort: payload.reasoning_effort,\n stream: payload.stream ?? undefined,\n tool_choice: payload.tool_choice,\n tools: summarizeToolsForDiagnostics(payload.tools),\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 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 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 upstreamModelId = routeModelId(payload.model)\n const upstreamPayload =\n upstreamModelId === payload.model ? payload : { ...payload, model: upstreamModelId }\n const provider = getCopilotProviderContext(config)\n const enableVision = messagesIncludeImage(upstreamPayload.messages)\n const initiator = isAgentInitiator(upstreamPayload.messages)\n const requestPayload = buildRequestPayload(upstreamPayload)\n log.info(\n [\n \"Model request\",\n `client=${client}`,\n `requested_model=${requestedModel}`,\n `upstream_model=${upstreamPayload.model}`,\n `requested_think_effort=${requestedThinkEffort}`,\n `requested_thinking=${requestedThinking}`,\n `effective_think_effort=${requestPayload.reasoning_effort ?? \"none\"}`,\n ].join(\" \"),\n )\n log.trace(\"Full request payload\", {\n payload: requestPayload,\n })\n if (shouldUseResponsesApiForModel(upstreamPayload.model)) {\n return createResponses(provider, upstreamPayload, {\n vision: enableVision,\n initiator,\n })\n }\n\n const response = await fetchCopilot(\n provider,\n \"/chat/completions\",\n {\n method: \"POST\",\n headers: {\n accept: upstreamPayload.stream ? \"text/event-stream\" : \"application/json\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(requestPayload),\n },\n { vision: enableVision, initiator },\n )\n\n if (!response.ok) {\n if (await shouldRetryWithResponses(response)) {\n return createResponses(provider, upstreamPayload, {\n vision: enableVision,\n initiator,\n })\n }\n\n await logUpstreamError(\"Failed to create chat completions\", response, {\n model: payload.model,\n request: requestPayload,\n route: \"/chat/completions\",\n })\n throw new HTTPError(\"Failed to create chat completions\", response)\n }\n\n if (upstreamPayload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ChatCompletionResponse\n}\n\nasync function createResponses(\n provider: ReturnType<typeof getCopilotProviderContext>,\n payload: ChatCompletionsPayload,\n options: { vision: boolean; initiator: \"agent\" | \"user\" },\n) {\n const reasoningEffort = getRequestedReasoningEffort(\n payload,\n ) as ResponsesReasoningEffort | undefined\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(\n buildResponsesRequestPayload(payload, reasoningEffort),\n ),\n },\n { vision: options.vision, initiator: options.initiator },\n )\n\n if (!response.ok) {\n await logUpstreamError(\"Failed to create responses\", response, {\n model: payload.model,\n route: \"/responses\",\n })\n throw new HTTPError(\"Failed to create responses\", response)\n }\n\n if (payload.stream) {\n return translateResponsesStreamToChatCompletionStream(events(response))\n }\n\n return translateResponsesToChatCompletion(\n (await response.json()) as ResponsesApiResponse,\n )\n}\n\nasync function logUpstreamError(\n message: string,\n response: Response,\n context: {\n model: string\n request?: ChatCompletionsRequestPayload\n route: string\n },\n): Promise<void> {\n const errorBody = await response.clone().text().catch(() => \"\")\n\n log.error(message, {\n route: context.route,\n model: context.model,\n status: response.status,\n statusText: response.statusText,\n body: errorBody || undefined,\n request:\n runtimeState.debug && context.request ?\n JSON.stringify(summarizeRequestForDiagnostics(context.request))\n : undefined,\n })\n}\n\nasync function shouldRetryWithResponses(response: Response): 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 response.clone().json()) as {\n error?: {\n code?: string\n }\n }\n\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 fetchCopilot,\n getCopilotProviderContext,\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 response = await fetchCopilot(provider, \"/models\", {\n method: \"GET\",\n headers: { accept: \"application/json\" },\n })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to validate upstream models\", response)\n }\n\n const payload = (await response.json()) as CopilotModelsResponse\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 { client: \"generic\", requestedModel: model },\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\n return {\n model,\n messages: translateClaudeMessagesToOpenAI(\n payload.messages,\n payload.system,\n mapper,\n ),\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 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 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 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\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 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 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","// 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 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 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 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 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\"\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\") {\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\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 claudePayload = await c.req.json<ClaudeMessagesPayload>()\n log.trace(\"Full Claude request payload\", { payload: claudePayload })\n\n try {\n const upstreamModel = translateModelName(claudePayload.model)\n const toolNameMapper = createClaudeToolNameMapper(claudePayload.tools, {\n ...getToolNameMapperOptionsForModel(upstreamModel),\n })\n const openAIPayload = translateToOpenAI(\n claudePayload,\n undefined,\n toolNameMapper,\n )\n const response = await createChatCompletions(config, openAIPayload, {\n client: \"claude\",\n requestedModel: claudePayload.model,\n requestedThinkEffort: getClaudeRequestedThinkEffort(claudePayload),\n requestedThinking: getClaudeRequestedThinking(claudePayload),\n })\n\n if (isNonStreamingResponse(response)) {\n const claudeResponse = translateToClaude(response, toolNameMapper)\n if (!claudePayload.stream) {\n return c.json(claudeResponse)\n }\n\n return streamSSE(c, async (stream) => {\n for (const event of eventsFromClaudeResponse(claudeResponse)) {\n await stream.writeSSE({\n event: event.type,\n data: JSON.stringify(event),\n })\n }\n })\n }\n\n return streamSSE(c, async (stream) => {\n const streamState: ClaudeStreamState = {\n messageStartSent: false,\n contentBlockIndex: 0,\n contentBlockOpen: false,\n thinkingBlockOpen: false,\n toolCalls: {},\n }\n\n try {\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 for (const event of translateChunkToClaudeEvents(\n chunk,\n streamState,\n toolNameMapper,\n )) {\n await stream.writeSSE({\n event: event.type,\n data: JSON.stringify(event),\n })\n }\n }\n } catch (error) {\n log.error(\"Error during Claude stream translation:\", error)\n const errorEvent = translateErrorToClaudeErrorEvent()\n await stream.writeSSE({\n event: errorEvent.type,\n data: JSON.stringify(errorEvent),\n })\n }\n })\n } catch (error) {\n if (error instanceof ProxyNotImplementedError) {\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 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 { serve } 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\nexport const createServer = (config: ProxyConfig) => {\n const app = new Hono<ProxyEnv>()\n\n app.use(\"*\", cors())\n app.use(\"*\", async (c, next) => {\n c.set(\"config\", config)\n const started = performance.now()\n try {\n await next()\n } finally {\n const ms = Math.round(performance.now() - started)\n log.info(`${c.req.method} ${c.req.path} -> ${c.res.status} ${ms}ms`)\n }\n })\n\n app.onError((error, c) => {\n log.error(`${c.req.method} ${c.req.path} failed`, error)\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\n return app\n}\n\nexport const startServer = (config: ProxyConfig) =>\n serve({\n fetch: createServer(config).fetch,\n hostname: config.host,\n port: config.port,\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 { 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 const start = defineCommand({\n meta: {\n name: \"start\",\n description: \"Start the copilot-relay HTTP server.\",\n },\n async run() {\n const 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\" || nextConfig.logLevel === \"trace\"\n runtimeState.thinkEffort = nextConfig.thinkEffort\n config.copilotBaseUrl = nextConfig.copilotBaseUrl\n config.host = nextConfig.host\n config.port = nextConfig.port\n runtimeState.modelRouting = {\n gptModel: nextConfig.gptModel,\n opusModel: nextConfig.opusModel,\n }\n }\n applyRuntimeConfig(appConfig)\n\n if (runtimeState.debug) {\n log.info(\"Debug diagnostics enabled; upstream errors include request summaries\")\n }\n log.info(`Log level: ${appConfig.logLevel}`)\n log.info(`Think effort: ${appConfig.thinkEffort}`)\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 = startServer(config)\n\n log.info(`copilot-relay version: ${appVersion}`)\n if (authSession.githubLogin) {\n log.info(`GitHub user: ${authSession.githubLogin}`)\n } else {\n log.warn(\"GitHub user: unavailable\")\n }\n\n log.success(\n `copilot-relay listening on http://${config.host}:${config.port}`,\n )\n log.debug(`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.success(\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.warn(\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}`,\n )\n })\n\n await new Promise<void>((resolve, reject) => {\n server.on(\"close\", resolve)\n server.on(\"error\", reject)\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 { start } from \"./start\"\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, start },\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","resolve","payload: StoredCopilotToken","refreshIn","refreshIn: number","runtimeState: RuntimeState","defaultReasoningEffort: ReasoningEffort","defaultModelRouting: ModelRoutingConfig","defaultConfig: AppConfig","config: Record<string, unknown>","logRetentionDays","config: AppConfig","configPath","parsed: Record<string, unknown>","env: Record<string, unknown>","next: Record<string, unknown>","lastError: unknown","path","state: ResponseTranslationState","chunks: Array<ResponseStreamEventMessage>","translated: Array<ResponsesInputItem>","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","events: Array<ClaudeStreamEventData>","events","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/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/lib/tokenizer.ts","../src/routes/claude.ts","../src/server.ts","../src/start.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\")\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}\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\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 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 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}\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}\n\nexport const isLogLevelName = (value: unknown): value is LogLevelName =>\n typeof value === \"string\"\n && logLevels.includes(value.toLowerCase() as LogLevelName)\n\nconst 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\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 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 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 \"# token refresh scheduling, request payloads, and upstream error details\",\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 \"# 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\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 }\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 // Keep the active config if the file is temporarily invalid.\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 vsCodeVersion: string\n}\n\nexport interface ProxyEnv {\n Variables: {\n config: ProxyConfig\n requestErrorMessage?: 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 vsCodeVersion: vscodeVersion,\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","// 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 ended up being a\n * silent third source of truth alongside `~/.claude/settings.json`, which\n * caused subtle port-mismatch bugs. copilot-relay now relies on these defaults\n * plus 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 type { ProxyConfig } from \"~/lib/config\"\nimport { 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\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}\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\nconst buildHeaders = (\n provider: CopilotProviderContext,\n init: RequestInit,\n options: FetchCopilotOptions,\n): Headers => {\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\", randomUUID())\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 headers\n}\n\nexport const fetchCopilot = async (\n provider: CopilotProviderContext,\n path: string,\n init: RequestInit,\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 let lastError: unknown\n\n for (let attempt = 1; attempt <= maxFetchAttempts; attempt++) {\n try {\n const started = performance.now()\n const response = await fetch(`${provider.baseUrl}${path}`, {\n ...init,\n headers: buildHeaders(provider, init, options),\n })\n const ms = Math.round(performance.now() - started)\n log.debug(\n `Copilot ${init.method ?? \"GET\"} ${path} -> ${response.status} ${ms}ms (attempt ${attempt})`,\n )\n\n if (!shouldRetryResponse(response) || attempt === maxFetchAttempts) {\n return response\n }\n log.error(\n `Copilot ${path} returned ${response.status}; retrying (${attempt}/${maxFetchAttempts})`,\n )\n } catch (error) {\n lastError = error\n if (attempt === maxFetchAttempts) {\n throw error\n }\n log.error(\n `Copilot ${path} request failed; retrying (${attempt}/${maxFetchAttempts})`,\n error,\n )\n }\n }\n\n throw lastError\n}\n","// Internal conversion between Copilot Responses API payloads and chat-completion-like results.\nimport { 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 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 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 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\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 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 { fetchCopilot, getCopilotProviderContext } 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\ntype ClientKind = \"claude\" | \"generic\"\n\ninterface CreateChatCompletionsOptions {\n client?: ClientKind\n requestedModel?: string\n requestedThinkEffort?: string\n requestedThinking?: string\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 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 upstreamModelId = routeModelId(payload.model)\n const upstreamPayload =\n upstreamModelId === payload.model ? payload : { ...payload, model: upstreamModelId }\n const provider = getCopilotProviderContext(config)\n const enableVision = messagesIncludeImage(upstreamPayload.messages)\n const initiator = isAgentInitiator(upstreamPayload.messages)\n const requestPayload = buildRequestPayload(upstreamPayload)\n log.debug(\n [\n \"Model request\",\n `client=${client}`,\n `requested_model=${requestedModel}`,\n `upstream_model=${upstreamPayload.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 (shouldUseResponsesApiForModel(upstreamPayload.model)) {\n return createResponses(provider, upstreamPayload, {\n vision: enableVision,\n initiator,\n })\n }\n\n const response = await fetchCopilot(\n provider,\n \"/chat/completions\",\n {\n method: \"POST\",\n headers: {\n accept: upstreamPayload.stream ? \"text/event-stream\" : \"application/json\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(requestPayload),\n },\n { vision: enableVision, initiator },\n )\n\n if (!response.ok) {\n if (await shouldRetryWithResponses(response)) {\n return createResponses(provider, upstreamPayload, {\n vision: enableVision,\n initiator,\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 })\n throw new HTTPError(\n \"Failed to create chat completions\",\n response,\n detail,\n )\n }\n\n if (upstreamPayload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ChatCompletionResponse\n}\n\nasync function createResponses(\n provider: ReturnType<typeof getCopilotProviderContext>,\n payload: ChatCompletionsPayload,\n options: { vision: boolean; initiator: \"agent\" | \"user\" },\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 { vision: options.vision, initiator: options.initiator },\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 })\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 response.json()) as ResponsesApiResponse,\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 },\n): Promise<string | undefined> {\n const errorBody = await response.clone().text().catch(() => \"\")\n const detail = getUpstreamErrorDetail(response, errorBody)\n\n log.error(`${message}: route=${context.route} model=${context.model} status=${response.status}`, {\n message,\n route: context.route,\n model: context.model,\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(response: Response): 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 response.clone().json()) as {\n error?: {\n code?: string\n }\n }\n\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 fetchCopilot,\n getCopilotProviderContext,\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 response = await fetchCopilot(provider, \"/models\", {\n method: \"GET\",\n headers: { accept: \"application/json\" },\n })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to validate upstream models\", response)\n }\n\n const payload = (await response.json()) as CopilotModelsResponse\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 { client: \"generic\", requestedModel: model },\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","// 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 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 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 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 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\"\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\") {\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\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 claudePayload = await c.req.json<ClaudeMessagesPayload>()\n log.debug(\"Full Claude request payload\", { payload: claudePayload })\n\n try {\n const upstreamModel = translateModelName(claudePayload.model)\n const toolNameMapper = createClaudeToolNameMapper(claudePayload.tools, {\n ...getToolNameMapperOptionsForModel(upstreamModel),\n })\n const openAIPayload = translateToOpenAI(\n claudePayload,\n undefined,\n toolNameMapper,\n )\n const response = await createChatCompletions(config, openAIPayload, {\n client: \"claude\",\n requestedModel: claudePayload.model,\n requestedThinkEffort: getClaudeRequestedThinkEffort(claudePayload),\n requestedThinking: getClaudeRequestedThinking(claudePayload),\n })\n\n if (isNonStreamingResponse(response)) {\n const claudeResponse = translateToClaude(response, toolNameMapper)\n if (!claudePayload.stream) {\n return c.json(claudeResponse)\n }\n\n return streamSSE(c, async (stream) => {\n for (const event of eventsFromClaudeResponse(claudeResponse)) {\n await stream.writeSSE({\n event: event.type,\n data: JSON.stringify(event),\n })\n }\n })\n }\n\n return streamSSE(c, async (stream) => {\n const streamState: ClaudeStreamState = {\n messageStartSent: false,\n contentBlockIndex: 0,\n contentBlockOpen: false,\n thinkingBlockOpen: false,\n toolCalls: {},\n }\n\n try {\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 for (const event of translateChunkToClaudeEvents(\n chunk,\n streamState,\n toolNameMapper,\n )) {\n await stream.writeSSE({\n event: event.type,\n data: JSON.stringify(event),\n })\n }\n }\n } catch (error) {\n log.error(\"Error during Claude stream translation:\", error)\n const errorEvent = translateErrorToClaudeErrorEvent()\n await stream.writeSSE({\n event: errorEvent.type,\n data: JSON.stringify(errorEvent),\n })\n }\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 { serve } 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 formatStatusLog = (\n method: string,\n path: string,\n status: number,\n ms: number,\n errorMessage: string | undefined,\n): string => {\n const base = `${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(\"*\", cors())\n app.use(\"*\", async (c, next) => {\n c.set(\"config\", config)\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 c.req.method,\n c.req.path,\n c.res.status,\n ms,\n c.get(\"requestErrorMessage\"),\n ))\n }\n })\n\n app.onError((error, c) => {\n c.set(\"requestErrorMessage\", error.message)\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\n return app\n}\n\nexport const startServer = (config: ProxyConfig) =>\n serve({\n fetch: createServer(config).fetch,\n hostname: config.host,\n port: config.port,\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 { 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 const start = defineCommand({\n meta: {\n name: \"start\",\n description: \"Start the copilot-relay HTTP server.\",\n },\n async run() {\n const 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 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(`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 = startServer(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}`,\n )\n })\n\n await new Promise<void>((resolve, reject) => {\n server.on(\"close\", resolve)\n server.on(\"error\", reject)\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 { start } from \"./start\"\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, start },\n})\n\nawait runMain(main)\n"],"mappings":"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"}