ai-sdk-codex-subscription-provider
v0.0.1
Published
Experimental AI SDK provider for local Codex subscription access
Readme
AI SDK Codex Subscription Provider
Experimental Vercel AI SDK v7 provider for using a local Codex subscription instead of OpenAI API billing.
The provider wraps @ai-sdk/openai and adapts its Responses API and image generation requests for the Codex subscription endpoint.
Warning: This is an experimental project meant for local development. It is a community provider and not an official OpenAI or Vercel product. You are responsible for complying with all applicable terms and ensuring safe and allowed usage.
Unlike ai-sdk-provider-codex-cli, this provider does not use the Codex CLI and therefore the Codex harness. Instead it uses the Codex subscription for API calls but you build the agent/harness with AI SDK.
Basic usage
import { generateText, streamText } from 'ai'
import { createCodex } from 'ai-sdk-codex-subscription-provider'
const codex = createCodex()
codex('gpt-5.4') // Responses language model
codex.responses('gpt-5.4') // Responses language model
codex.image('gpt-image-2') // Image generation model
codex.imageModel('gpt-image-2') // Image generation model
const generated = await generateText({
model: codex('gpt-5.4'),
prompt: 'Explain this repository.',
})
const streamed = streamText({
model: codex('gpt-5.4'),
prompt: 'Suggest one focused improvement.',
})
for await (const chunk of streamed.textStream) {
process.stdout.write(chunk)
}OpenAI-specific model options remain under providerOptions.openai because request conversion is provided by @ai-sdk/openai. Pass authStore or fetch to createCodex({ authStore, fetch }) when you need custom authentication storage or transport.
Authentication
The provider reads OAuth credentials from a credential store. By default createCodex() uses the built-in file store at:
$CODEX_HOME/ai-sdk.auth.jsonWhen CODEX_HOME is unset the path is ~/.codex/ai-sdk.auth.json.
CLI login
Use the CLI for the normal local-development login flow:
npx ai-sdk-codex loginOpen the printed URL and complete the browser login. Credentials are stored separately from the Codex CLI.
Custom stores
Use createFileCodexCredentialStore() to customize the built-in file store location:
import { createCodex, createFileCodexCredentialStore } from 'ai-sdk-codex-subscription-provider'
const authStore = createFileCodexCredentialStore({
authPath: '/secure/path/ai-sdk.auth.json',
})
const codex = createCodex({ authStore })Custom stores can persist credentials anywhere:
type CodexCredentialStore = {
get: () => Promise<CodexCredentials | null>
set: (credentials: CodexCredentials | null) => Promise<void>
}set(null) clears credentials. Custom stores are responsible for safe persistence. The built-in file store uses private file permissions, atomic writes and refresh locking.
Advanced auth API
Apps can build their own login UX with the flat auth helper API. Use local auth when the browser and agent run on the same machine.
import { auth } from 'ai-sdk-codex-subscription-provider'
// Must be one of OpenAI's allow-listed Codex callback URLs, for example http://localhost:1455/auth/callback.
const request = auth.createAuthorizationRequest({ redirectUri })
const credentials = await auth.exchangeAuthorizationCode({
code,
codeVerifier: request.codeVerifier,
redirectUri,
})
await authStore.set(credentials)For remote agents, for example if you are running it on your LAN box, use device auth:
const device = await auth.createDeviceAuthorization()
// Show device.verificationUri and device.userCode to the user.
const credentials = await auth.pollDeviceAuthorization(device)
await authStore.set(credentials)auth.refreshAccessToken({ credentials }) is also exported for custom integrations. Normal provider requests refresh automatically.
Auth errors
The provider throws CodexAuthRequiredError when credentials are missing or rejected. App code can map it to HTTP 401, a device auth screen or another UX.
More detail:
Image generation
Use AI SDK generateImage with codex.image(...):
import { writeFile } from 'node:fs/promises'
import { generateImage } from 'ai'
import { createCodex } from 'ai-sdk-codex-subscription-provider'
const codex = createCodex()
const { image } = await generateImage({
model: codex.image('gpt-image-2'),
prompt: 'A tiny red square icon. No text.',
size: '1024x1024',
providerOptions: {
openai: {
quality: 'low',
outputFormat: 'png',
},
},
})
await writeFile('image.png', image.uint8Array)Image edits are also supported by passing images in the prompt:
const source = (await generateImage({ model: codex.image('gpt-image-2'), prompt: 'A red square.' }))
.image.uint8Array
const { image: edited } = await generateImage({
model: codex.image('gpt-image-2'),
prompt: {
text: 'Turn the red square blue.',
images: [source],
},
size: '1024x1024',
})
await writeFile('edited.png', edited.uint8Array)For inpainting pass prompt.mask. OpenAI-specific edit options like quality, outputFormat and inputFidelity remain under providerOptions.openai.
Image input
Models that support vision can receive AI SDK file parts with image media types:
const result = await generateText({
model: codex('gpt-5.4'),
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'Describe this image.' },
{ type: 'file', data: imageBytes, mediaType: 'image/png' },
],
},
],
})The wrapped OpenAI Responses model also advertises remote http and https image URL support to the AI SDK. This is image input only. For image generation use codex.image(...).
Live smoke tests
The live contract tests are disabled during normal test runs. Give them a dedicated login because the tests force a token refresh:
CODEX_HOME=/path/to/smoke-auth node dist/cli.js login
CODEX_HOME=/path/to/smoke-auth npm run test:smoke
CODEX_HOME=/path/to/smoke-auth npm run test:imageNever copy normal credentials into the smoke-test directory. Log in there directly so refresh token rotation cannot invalidate the normal login.
Status
This package relies on the Codex ChatGPT backend rather than the public OpenAI API. That protocol can change without notice. The current implementation supports the Responses API, text-to-image generation and image edits. It does not expose embeddings, speech or transcription.
