PAIPAI
API Reference@pai/openai-codex

@pai/openai-codex

Run Responses language models with an explicitly authorized ChatGPT subscription credential.

@pai/openai-codex is an experimental, server-only Vercel AI SDK provider for local or personal PAI agents. It uses a ChatGPT subscription credential rather than an OpenAI Platform API key.

The package delegates the Responses protocol to @ai-sdk/openai. PAI owns the OAuth credential lifecycle, exact Codex endpoint, account pinning, and the small set of stateless request invariants the subscription endpoint requires. The backend requires streamed Responses, so both generateText and streamText use the upstream stream parser. Generate calls collect the normalized AI SDK stream into a standard generate result. The optional raw response.body is unavailable for generated results because the HTTP body is an SSE sequence rather than one JSON document. Normalized content, headers, response metadata, provider metadata, and usage are retained.

Install And Authenticate

pnpm add @pai/openai-codex ai zod
pnpm exec pai-openai-codex login

Use device authorization on a headless machine:

pnpm exec pai-openai-codex login --device

The default credential is plaintext at .pai/openai-codex/auth.json in the current user's home directory, protected with owner-only permissions on Unix. Treat it as a password. Windows mode bits are best effort; inject a keychain-backed store when stronger at-rest protection is required.

Create A Provider

Authentication and model creation are deliberately explicit:

import {
  createOpenAICodex,
  createOpenAICodexAuth,
} from "@pai/openai-codex";
import { defineAgent } from "@pai/core";

const auth = createOpenAICodexAuth();
const openaiCodex = createOpenAICodex({ auth });

export const agent = defineAgent({
  name: "coding-agent",
  model: ({ threadId }) => ({
    model: openaiCodex("gpt-5.6-sol"),
    providerOptions: {
      openai: { promptCacheKey: threadId },
    },
  }),
  instructions: "Help with the user's coding task.",
});

Provider and model construction perform no filesystem, browser, listener, or network work. The first model request pins the ChatGPT account. If another login replaces the credential with a different account, existing providers fail with account_changed; construct a new provider before continuing.

Model Discovery

listOpenAICodexModels reads the models the signed-in ChatGPT account may use through Codex, so a host can offer real choices instead of free-text entry:

import { listOpenAICodexModels } from "@pai/openai-codex";

const models = await listOpenAICodexModels(auth);

Each entry carries its id, the displayName ChatGPT shows, a description, and a contextLength. Only models the backend marks as listable are returned: the rest are internal entries such as auto-review helpers, which an account can name but which are not choices to put in front of a person.

The catalogue endpoint reveals a model only to a client at or above the minimal_client_version that model declares. This package sends a deliberate pin — the newest catalogue version it was verified against, with every model returned confirmed to run over this Responses transport. The pin moves when that verification is repeated, not with a release, so a new model the backend gates behind a newer client appears here only once it has been checked.

The authenticated transport reaches exactly two destinations: the Responses call and this catalogue. Any other URL, or either one with the wrong method, fails with unsupported_request before a credential is read.

Provider Options

Use the upstream openai namespace, matching @ai-sdk/openai metadata and tool conventions:

import type { OpenAICodexProviderOptions } from "@pai/openai-codex";

const selection = {
  model: openaiCodex("gpt-5.6-sol"),
  providerOptions: {
    openai: {
      reasoningEffort: "high",
      reasoningSummary: "auto",
    } satisfies OpenAICodexProviderOptions,
  },
};

Prompt caching

The subscription backend reused an exact 2,816-token user-message prefix in live conformance testing when promptCacheKey was stable. Use the PAI thread ID rather than a random value per request. Cache reads appear in usage.inputTokenDetails.cacheReadTokens. PAI does not populate this provider-specific option automatically.

The provider example above uses PAI's existing model resolver boundary to derive this key directly from threadId. Add other OpenAI provider options to that same openai object.

The same key is also sent as the session-id header. The Codex CLI sets both from one session identity, and the ChatGPT backend uses the header to pick the cache-affine route, so a body key alone can land on a node that does not hold the prefix. Keep the key visible ASCII of at most 512 characters; a key that is not still reaches the body but is not mirrored, and the call carries a warning saying so.

The provider deliberately rejects the Platform API's promptCacheOptions and promptCacheRetention controls. The subscription endpoint rejected promptCacheOptions in live conformance testing; retention policy support was not probed. Repeated top-level instructions did not produce a cache hit; structure reusable context as stable message prefixes when prompt caching matters.

The provider owns these settings:

  • System messages become top-level Responses instructions.
  • store is always false and encrypted reasoning is requested for stateless multi-turn continuation.
  • forceReasoning is enabled so newly available Codex model IDs retain encrypted reasoning even before the pinned AI SDK recognizes them.
  • conversation, previousResponseId, caller-supplied instructions, and systemMessageMode are rejected.
  • Platform-only promptCacheOptions and promptCacheRetention controls are rejected; promptCacheKey remains supported.
  • maxOutputTokens is omitted and reported as an AI SDK unsupported-setting warning.

Normal AI SDK function tools and structured output remain supported. The package does not expose the upstream provider-native tool collection because the subscription endpoint has not been verified for every OpenAI service.

Auth API

createOpenAICodexAuth() returns one manager that owns login, status, logout, refresh serialization, and 401 recovery for a credential slot.

const auth = createOpenAICodexAuth();

await auth.login();
const status = await auth.status();
await auth.logout();

For custom storage, implement OpenAICodexCredentialStore. Its Uint8Array value is an opaque versioned secret envelope; do not parse, log, or expose it. Reuse one store and auth manager within the process.

const auth = createOpenAICodexAuth({
  credentialStore: mySecretStore,
  fetch: trustedNetworkFetch,
});

The optional fetch is a privileged seam that observes access and refresh tokens. Never provide a function controlled by an agent, plugin, or tenant.

Every request carries ChatGPT-Account-Id from the token and, when the token declares a chatgpt_compute_residency constraint, the x-openai-internal-codex-residency header, so a residency-bound account is routed as its own Codex CLI would route it. Both are derived from the credential in use and cannot be supplied by a caller. Function tools are registered with strict: false unless the tool sets its own strictness, matching the Codex CLI, so schemas with optional fields or from MCP servers load rather than failing the request.

Errors

Recognizable local failures use OpenAICodexError and a safe code, including not_logged_in, refresh_rejected, account_changed, credentials_corrupt, and unsupported_option. Messages do not include raw OAuth responses, tokens, codes, or request headers. Upstream model API errors remain the standard AI SDK errors produced by @ai-sdk/openai.

Scope And Limitations

This release supports one local/personal ChatGPT account and one Node process mutating a credential file. It is not a multi-tenant broker and must not pool or proxy one operator's subscription across users. It never imports or shares the Codex CLI credential file.

Only Responses language models are supported. Required AI SDK ProviderV4 embedding and image lookups throw NoSuchModelError before reading credentials; speech and transcription are also unsupported. HTTP is the only transport.

Model availability, subscription quotas, terms, and the non-public Codex backend can change independently of PAI. For stable production API terms or other OpenAI capabilities, use @ai-sdk/openai with an OpenAI Platform API key.

On this page