import { buildCodexHeaders, isJsonObject, isOpenAICodexModel, mergeFeatureHeader, resolveCodexResponsesUrl, type Model, } from "./native-compaction.js"; export function isNativeCompactionModel(model: unknown): model is Model { return isOpenAICodexModel(model) || ( isJsonObject(model) && model.provider === "sub-api" && model.api === "openai-responses" ); } export function buildNativeCompactionTransport(params: { model: Pick, "provider" | "api" | "baseUrl">; apiKey?: string; headers?: Record; sessionId: string; }): { url: string; headers: Headers } { if (isOpenAICodexModel(params.model)) { if (!params.apiKey) throw new Error("Codex native compaction authentication requires an API key."); return { url: resolveCodexResponsesUrl(params.model.baseUrl), headers: buildCodexHeaders({ ...params, apiKey: params.apiKey }), }; } if (!isNativeCompactionModel(params.model)) { throw new Error("Native compaction is not supported for this provider and API."); } if (!params.model.baseUrl?.trim()) { throw new Error("SubAPI native compaction requires an explicit baseUrl."); } let url: URL; try { url = new URL(params.model.baseUrl.trim()); } catch { throw new Error("SubAPI native compaction requires a valid HTTP(S) baseUrl."); } if (!["https:", "http:"].includes(url.protocol) || url.username || url.password || url.hash) { throw new Error("SubAPI native compaction requires an HTTP(S) baseUrl without credentials or a fragment."); } const path = url.pathname.replace(/\/+$/, ""); url.pathname = path.endsWith("/responses") ? path : `${path}/responses`; // Sub2API accepts native compaction v2 through its public Responses endpoint. // The gateway owns upstream Codex credentials; honor the client's resolved authentication. const headers = new Headers(params.headers); if (!headers.get("authorization")?.trim()) { if (params.apiKey?.trim()) { headers.set("authorization", `Bearer ${params.apiKey}`); } else if (!headers.get("cf-aig-authorization")?.trim()) { throw new Error("SubAPI native compaction authentication requires an API key or a non-empty Authorization or cf-aig-authorization header."); } } headers.set("content-type", "application/json"); headers.set("accept", "text/event-stream"); headers.set("OpenAI-Beta", "responses=experimental"); headers.set("originator", "pi"); headers.set("user-agent", "pi-compaction"); headers.set("session-id", params.sessionId); headers.set("x-client-request-id", params.sessionId); headers.set("x-codex-beta-features", mergeFeatureHeader(headers.get("x-codex-beta-features"))); return { url: url.toString(), headers }; }