import { randomUUID } from "crypto"; import { setUserAgentHeader } from "../executors/base.ts"; /** * Header keys that are forwarded from the client to the upstream provider. * Used by both OpencodeExecutor and DefaultExecutor. */ const OPENCODE_HEADER_KEYS = [ "x-opencode-session", "x-opencode-request", "x-opencode-project", "x-opencode-client", ] as const; /** * Case-insensitive lookup for a header in a headers record. */ function findHeader(headers: Record, name: string): string | undefined { return Object.entries(headers).find(([key]) => key.toLowerCase() === name.toLowerCase())?.[1]; } /** * Forward OpenCode client request metadata headers to the upstream provider. * * Shared logic used by OpencodeExecutor and DefaultExecutor: * 1. Forwards User-Agent from clientHeaders via `setUserAgentHeader()` * 2. Forwards x-opencode-session, x-opencode-request, x-opencode-project, * x-opencode-client headers (case-insensitive match) * * @param headers - The outbound headers record to mutate * @param clientHeaders - The client-provided headers to forward from * @param options.synthesizeRequestId - When true (OpencodeExecutor only), maps * x-session-affinity / x-session-id to x-opencode-session when the latter is * missing, and synthesizes a UUID for x-opencode-request if also missing. */ export function forwardOpencodeClientHeaders( headers: Record, clientHeaders: Record, options?: { synthesizeRequestId?: boolean } ): void { // 1. Forward User-Agent const clientUA = clientHeaders["User-Agent"] || clientHeaders["user-agent"]; if (clientUA) { setUserAgentHeader(headers, clientUA); } // 2. Forward x-opencode-* metadata headers for (const headerName of OPENCODE_HEADER_KEYS) { const value = findHeader(clientHeaders, headerName); if (value) { headers[headerName] = value; } } // 3. OpencodeExecutor-only: synthesize session/request id from fallback headers if (options?.synthesizeRequestId && !headers["x-opencode-session"]) { const sessionAffinity = findHeader(clientHeaders, "x-session-affinity") || findHeader(clientHeaders, "x-session-id"); if (sessionAffinity) { headers["x-opencode-session"] = sessionAffinity; if (!headers["x-opencode-request"]) { headers["x-opencode-request"] = randomUUID(); } } } }