/** * `openai-codex` wire family — the ChatGPT-backend Responses API. * * This is the transport used by "Sign in with ChatGPT" (OAuth) credentials. * It speaks the OpenAI **Responses** wire format (NOT chat/completions) and * targets `https://chatgpt.com/backend-api/codex/responses`, authenticating * with the OAuth access token + `chatgpt-account-id` header. It deliberately * leaves the API-key `openai` family (api.openai.com/chat/completions) * untouched — the two coexist as separate providers. * * Token lifecycle: the access token is short-lived. This adapter refreshes it * transparently — before a request when it is near expiry, and once more on a * 401 — using the stored refresh token, then invokes `onRefresh` so the CLI * can persist the rotated tokens back to the vault. * * The refresh endpoint + client id used to be duplicated here, with a comment * explaining that `providers` must not depend on `cli`. The layering was right; * the conclusion was not — the constants now live in `./oauth/codex-protocol.js`, * below both, so the CLI login flow, the headless WebUI flow, and this refresh * path share one definition instead of three that had to be kept in step by hand. */ import { type Capabilities, ProviderError, type ReasoningEffort, type Request, type StreamEvent } from '@wrongstack/core/types'; import { type HeadersLike } from './error-parse.js'; import { type CodexTokens } from './oauth/codex-protocol.js'; import type { BuildBodyContext } from './model-output-limits.js'; import { WireAdapter, type WireAdapterStreamOptions } from './wire-adapter.js'; /** * Token shape returned by a refresh. Structurally the shared * {@link CodexTokens}; kept as a named alias because it is part of this * package's published surface. */ export type CodexOAuthTokens = CodexTokens; /** * Refresh an expired Codex access token using its refresh token. * * Thin alias over the shared {@link refreshCodexTokens} — the endpoint, client * id, body shape, and response validation are defined once in * `./oauth/codex-protocol.js`. The name is kept because it is exported from * this package's index and wired as the adapter's default `refreshFn`. */ export declare function refreshCodexAccessToken(refreshToken: string, signal?: AbortSignal): Promise; export { extractAccountId } from './openai-codex-account.js'; export interface CodexCredentials { /** The OAuth access token (a JWT). */ accessToken: string; /** The refresh token, used to mint a new access token before/at expiry. */ refreshToken?: string | undefined; /** Access-token expiry, epoch ms. When absent, refresh only fires on 401. */ expiresAt?: number | undefined; /** Cached ChatGPT account id. Re-derived from the live token when missing. */ accountId?: string | undefined; } /** * Decide what happens to a caller's `req.maxTokens` on the Codex wire. * * ChatGPT's subscription-backed `/backend-api/codex/responses` surface rejects * `max_output_tokens` with HTTP 400, even though the public Responses API * accepts it. Always omit the field and let the backend apply the selected * model's own output policy. * * Kept as an exported compatibility helper for existing callers. */ export declare function codexOutputCap(_maxTokens: number | undefined): undefined; export interface OpenAICodexProviderOptions { credentials: CodexCredentials; baseUrl?: string | undefined; id?: string | undefined; fetchImpl?: typeof fetch | undefined; capabilities?: Partial | undefined; streamOpts?: WireAdapterStreamOptions | undefined; /** * Persist rotated tokens after a successful refresh. The CLI wires this to * write back to the encrypted config so the new access/refresh pair survive * the session. */ onRefresh?: ((creds: { accessToken: string; refreshToken: string; expiresAt: number; accountId: string | undefined; }) => void) | undefined; /** Override the refresh call (tests). */ refreshFn?: ((refreshToken: string, signal?: AbortSignal) => Promise) | undefined; /** * Reasoning effort for the Codex (gpt-5.x) reasoning models. Sent as * `reasoning.effort` with `summary: 'auto'` so chain-of-thought streams back * as thinking deltas. Request-level reasoning settings override this default. * Default 'medium'. Set 'none' to omit reasoning entirely. */ reasoningEffort?: ReasoningEffort | undefined; } export declare class OpenAICodexProvider extends WireAdapter { readonly id: string; readonly capabilities: Capabilities; private access; private refresh; private accountId; private readonly refreshFn; /** Shared OAuth refresh machinery — see packages/providers/src/oauth-refresh-coordinator.ts */ private readonly refreshCoordinator; private readonly reasoningEffort; private contextLimits; private contextLimitsEtag; private contextLimitsRefresh; private contextLimitsRetryAfter; constructor(opts: OpenAICodexProviderOptions); /** * Re-check the ChatGPT Codex model catalog at request boundaries. The * official Codex client uses the same authenticated `/models` endpoint; its * `context_window` can drop far below the public API catalog when a * subscription is throttled (e.g. 272000 for gpt-5.6-sol while the public * model advertises 1M). The catalog value is the TOTAL window, so the * returned `maxContext` is the derived SEND ceiling — `context_window` * minus the transport's output budget (see {@link codexSendCeiling}) — * making preflight compaction trigger before the backend rejects with * "Your input exceeds the context window of this model". A conditional GET * runs before every request so a changed ETag is observed before the * provider call. */ refreshContextLimit(model: string, opts: { signal: AbortSignal; }): Promise<{ maxContext: number; source: 'provider'; } | undefined>; private fetchContextLimits; stream(req: Request, opts: { signal: AbortSignal; }): AsyncIterable; private ensureFreshToken; private doRefresh; protected buildUrl(_req: Request): string; protected buildHeaders(_req: Request): Record; protected buildBody(req: Request, ctx: BuildBodyContext): Record; protected parseStream(body: ReadableStream | NodeJS.ReadableStream | null, fallbackModel: string): AsyncIterable; protected translateError(status: number, text: string, headers?: HeadersLike): ProviderError; } /** Normalize a base URL to the `/codex/responses` endpoint. */ export declare function resolveCodexUrl(baseUrl: string | undefined): string; /** Resolve the authenticated Codex model-catalog endpoint beside `/responses`. */ export declare function resolveCodexModelsUrl(baseUrl: string | undefined): string; export declare function parseOpenAIResponsesStream(body: ReadableStream | NodeJS.ReadableStream | null, fallbackModel: string, providerId?: string): AsyncIterable; //# sourceMappingURL=openai-codex.d.ts.map