UNPKG

ai-sdk-provider-codex-cli

Version:

AI SDK v7 provider for OpenAI Codex CLI (use ChatGPT Plus/Pro subscription)

570 lines (433 loc) • 26.6 kB
# AI SDK Provider for Codex CLI [![npm version](https://img.shields.io/npm/v/ai-sdk-provider-codex-cli.svg)](https://www.npmjs.com/package/ai-sdk-provider-codex-cli) [![npm downloads](https://img.shields.io/npm/dm/ai-sdk-provider-codex-cli.svg)](https://www.npmjs.com/package/ai-sdk-provider-codex-cli) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) ![Node >= 22](https://img.shields.io/badge/node-%3E%3D22-43853d?logo=node.js&logoColor=white) ![AI SDK v7](https://img.shields.io/badge/AI%20SDK-v7-000?logo=vercel&logoColor=white) ![Modules: ESM only](https://img.shields.io/badge/modules-ESM%20only-3178c6) ![TypeScript](https://img.shields.io/badge/TypeScript-blue) [![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/ben-vargas/ai-sdk-provider-codex-cli/issues) [![Latest Release](https://img.shields.io/github/v/release/ben-vargas/ai-sdk-provider-codex-cli?display_name=tag)](https://github.com/ben-vargas/ai-sdk-provider-codex-cli/releases/latest) A community provider for Vercel AI SDK v7 that integrates OpenAI's Codex CLI (for example `gpt-6-astra`) using your ChatGPT Plus/Pro subscription. Available model slugs follow whatever your installed Codex CLI exposes — use `listModels()` / `provider.listModels()` to discover them. This package ships two provider modes: - `codexExec`: non-interactive `codex exec` (spawn a new process per call) - `codexAppServer`: persistent `codex app-server` JSON-RPC client (shared process, true delta streaming, optional stateful threads) - Works with `generateText`, `streamText`, and `generateObject` - Uses ChatGPT OAuth from `codex login` (tokens in `~/.codex/auth.json`) or `OPENAI_API_KEY` - Node-only (spawns a local process); supports CI and local dev - Requires Node.js >= 22; published as an ESM-only package - **v2.0.0**: AI SDK v7 migration with the native LanguageModelV4 provider spec (package line 2.x) - **v1.0.0**: AI SDK v6 migration with the LanguageModelV3 interface (now on the `ai-sdk-v6` tag) ## Version Compatibility | Package line | AI SDK | npm tag | Git branch | Status | | ----------------- | ------ | --------------------- | ----------- | ---------------------------- | | 2.x | v7 | `latest`, `ai-sdk-v7` | `main` | Active development | | 1.x | v6 | `ai-sdk-v6` | `ai-sdk-v6` | Maintenance | | 0.7.x | v5 | `ai-sdk-v5` | `ai-sdk-v5` | Maintenance / critical fixes | | `0.1.0-ai-sdk-v4` | v4 | `ai-sdk-v4` | `ai-sdk-v4` | Frozen | ## Installation ### For AI SDK v7 (default) 1. Install and authenticate Codex CLI ```bash npm i -g @openai/codex codex login # or set OPENAI_API_KEY ``` 2. Install provider and AI SDK v7 ```bash npm i ai ai-sdk-provider-codex-cli ``` > **Requirements:** Node.js >= 22. This package is ESM-only (no CommonJS build); load it with `import` (or dynamic `import()` from CJS). ### For AI SDK v6 ```bash npm i ai@^6 ai-sdk-provider-codex-cli@ai-sdk-v6 ``` ### For AI SDK v5 ```bash npm i ai@^5.0.0 ai-sdk-provider-codex-cli@ai-sdk-v5 ``` > **⚠️ Codex CLI Version**: Requires the current stable Codex CLI **0.156.x** for full support of both provider modes (`codexExec` and `codexAppServer`). This package pins its optional `@openai/codex` dependency to `^0.156.1`, the latest non-alpha release line validated for this release line. `gpt-6-sol` (used by the examples) is rejected by older CLIs (< 0.155.0) with "model is not supported when using Codex with a ChatGPT account". If you supply your own Codex CLI (global install or custom `codexPath`), check it with `codex --version` and upgrade if needed. > > ```bash > npm i -g @openai/codex@latest > ``` ## Quick Start ### Exec provider (`codexExec`) — process-per-call ```js import { generateText } from 'ai'; import { codexExec } from 'ai-sdk-provider-codex-cli'; const model = codexExec('gpt-6-astra', { allowNpx: true, skipGitRepoCheck: true, approvalMode: 'on-request', sandboxMode: 'workspace-write', }); const { text } = await generateText({ model, prompt: 'Reply with a single word: hello.', }); console.log(text); ``` ### App-server provider (`createCodexAppServer`) — persistent process ```js import { streamText } from 'ai'; import { createCodexAppServer } from 'ai-sdk-provider-codex-cli'; const provider = createCodexAppServer({ defaultSettings: { minCodexVersion: '0.156.0', autoApprove: false, personality: 'pragmatic', }, }); const { textStream } = await streamText({ model: provider('gpt-6-astra'), prompt: 'Write two short lines of encouragement.', }); for await (const chunk of textStream) process.stdout.write(chunk); await provider.close(); ``` ### App-server stateful threads (optional) By default, `codexAppServer` is stateless (new ephemeral thread per call). To continue a prior conversation across calls, start a persistent thread and then pass its `threadId` in `providerOptions['codex-app-server']`. ```js import { generateText } from 'ai'; import { createCodexAppServer } from 'ai-sdk-provider-codex-cli'; const provider = createCodexAppServer(); const first = await generateText({ model: provider('gpt-6-astra'), prompt: 'Start a migration checklist.', providerOptions: { 'codex-app-server': { threadMode: 'persistent' }, }, }); const threadId = first.finalStep.providerMetadata?.['codex-app-server']?.threadId; const second = await generateText({ model: provider('gpt-6-astra'), prompt: 'Continue from step 2.', providerOptions: { 'codex-app-server': { threadId }, }, }); await provider.close(); ``` ### Object generation (Zod) ```js import { generateObject } from 'ai'; import { z } from 'zod'; import { codexExec } from 'ai-sdk-provider-codex-cli'; const schema = z.object({ name: z.string(), age: z.number().int() }); const { object } = await generateObject({ model: codexExec('gpt-6-astra', { allowNpx: true, skipGitRepoCheck: true }), schema, prompt: 'Generate a small user profile.', }); console.log(object); ``` ## Features - AI SDK v7 compatible (native LanguageModelV4 provider spec) - Dual provider architecture: - `codexExec` / `createCodexExec` for `codex exec` - `codexAppServer` / `createCodexAppServer` for `codex app-server` - Backward-compatible aliases: `codexCli` / `createCodexCli` map to exec mode - Model discovery via `listModels()` / `provider.listModels()` — available slugs follow your installed Codex CLI - Streaming and non‑streaming - **Configurable logging** - Verbose mode, custom loggers, or silent operation - **Tool streaming support** - Monitor autonomous tool execution in real-time - **Native JSON Schema support** via `--output-schema` (exec) / the `outputSchema` turn parameter (app-server) - JSON object generation with Zod schemas (100-200 fewer tokens per request vs prompt engineering) - Safe defaults for non‑interactive automation (`on-request`, `workspace-write`, `--skip-git-repo-check`) - Fallback to `npx -y @openai/codex` when the local `@openai/codex` package can't be resolved (`allowNpx`) - Usage tracking from experimental JSON event format - **Fast mode / service tiers** - `serviceTier: 'fast'` (or any tier advertised by the model) in both providers, overridable per call - **Image support** - Local binary images in both providers; remote HTTP/HTTPS image URLs work via AI SDK download ### Image Support The provider supports multimodal (image) inputs for vision-capable models: ```js import { generateText } from 'ai'; import { codexExec } from 'ai-sdk-provider-codex-cli'; import { readFileSync } from 'fs'; const model = codexExec('gpt-6-astra', { allowNpx: true, skipGitRepoCheck: true }); const imageBuffer = readFileSync('./screenshot.png'); const { text } = await generateText({ model, messages: [ { role: 'user', content: [ { type: 'text', text: 'What do you see in this image?' }, { type: 'file', data: imageBuffer, mediaType: 'image/png' }, ], }, ], }); console.log(text); ``` **Supported image formats:** - Base64 data URL (`data:image/png;base64,...`) - Base64 string (without data URL prefix) - `Buffer` / `Uint8Array` / `ArrayBuffer` **Remote image URLs:** - Pass remote images as `{ type: 'file', data: new URL('https://...'), mediaType: 'image/png' }` message parts in either mode - Both providers declare `supportedUrls = {}`, so the AI SDK downloads the URL itself and hands the provider the bytes, which flow through the same temp-file path as local images - Raw URL shapes that bypass the AI SDK's download step are warned and skipped in exec mode; app-server mode forwards them to Codex as-is, but the SDK download route above is the supported path Local image data is written to temporary files and passed to Codex CLI via `--image` (or app-server `localImage`). Temp files are automatically cleaned up after each request. See [examples/exec/image-support.mjs](examples/exec/image-support.mjs) and [examples/app-server/image-support.mjs](examples/app-server/image-support.mjs) for complete working examples. ### Tool Streaming The provider supports comprehensive tool streaming, enabling real-time monitoring of Codex CLI's autonomous tool execution: ```js import { streamText } from 'ai'; import { codexExec } from 'ai-sdk-provider-codex-cli'; const result = await streamText({ model: codexExec('gpt-6-astra', { allowNpx: true, skipGitRepoCheck: true }), prompt: 'List files and count lines in the largest one', }); for await (const part of result.stream) { if (part.type === 'tool-call') { console.log('🔧 Tool:', part.toolName); } if (part.type === 'tool-result') { console.log('✅ Result:', part.output); } } ``` **What you get:** - Tool invocation events when Codex starts executing tools (exec, patch, web_search, mcp_tool_call) - Tool input tracking with full parameter visibility - Tool result events with complete output payloads - `providerExecuted: true` on all tool calls (Codex executes autonomously, app doesn't need to) **Current behavior:** - `codexExec`: tool outputs are delivered in final `tool-result` events. - `codexAppServer`: when Codex emits tool output delta notifications, the provider surfaces `tool-result` parts whose `output.type === 'output-delta'` during streaming. See `examples/exec/streaming-tool-calls.mjs`, `examples/exec/streaming-multiple-tools.mjs`, and their app-server counterparts under `examples/app-server/`. ### Logging Configuration Control logging verbosity and integrate with your observability stack: ```js import { codexExec } from 'ai-sdk-provider-codex-cli'; // Default: warn/error only (clean production output) const model = codexExec('gpt-6-astra', { allowNpx: true, skipGitRepoCheck: true, }); // Verbose mode: enable debug/info logs for troubleshooting const verboseModel = codexExec('gpt-6-astra', { allowNpx: true, skipGitRepoCheck: true, verbose: true, // Shows all log levels }); // Custom logger: integrate with Winston, Pino, Datadog, etc. const customModel = codexExec('gpt-6-astra', { allowNpx: true, skipGitRepoCheck: true, verbose: true, logger: { debug: (msg) => myLogger.debug('Codex:', msg), info: (msg) => myLogger.info('Codex:', msg), warn: (msg) => myLogger.warn('Codex:', msg), error: (msg) => myLogger.error('Codex:', msg), }, }); // Silent: disable all logging const silentModel = codexExec('gpt-6-astra', { allowNpx: true, skipGitRepoCheck: true, logger: false, // No logs at all }); ``` **Log Levels:** - `debug`: Detailed execution traces (verbose mode only) - `info`: General execution flow (verbose mode only) - `warn`: Warnings and misconfigurations (always shown) - `error`: Errors and failures (always shown) **Default Logger:** Adds level tags `[DEBUG]`, `[INFO]`, `[WARN]`, `[ERROR]` to console output. Use a custom logger or `logger: false` if you need different formatting. See `examples/exec/logging-*.mjs` and `examples/app-server/logging-*.mjs` for complete examples, and [docs/ai-sdk-v7/guide.md](docs/ai-sdk-v7/guide.md) for detailed configuration. ### Text Streaming behavior **`codexExec` mode:** Incremental streaming is not currently available with `codex exec --experimental-json`. The `--experimental-json` output format (introduced Sept 25, 2025) currently only emits `item.completed` events with full text content. Incremental streaming via `item.updated` or delta events is not yet implemented by OpenAI. **What this means in exec mode:** - `streamText()` works functionally but delivers the entire response in a single chunk after generation completes - No incremental text deltas—you wait for the full response, then receive it all at once - The AI SDK's streaming interface is supported, but actual incremental streaming is not available **`codexAppServer` mode:** supports true incremental text deltas via `item/agentMessage/delta`, so `streamText()` emits progressively as tokens arrive. When OpenAI adds streaming support to `codex exec --experimental-json`, this provider will surface those deltas in exec mode as well. ## Documentation - Getting started, configuration, and troubleshooting live in `docs/`: - [docs/ai-sdk-v7/guide.md](docs/ai-sdk-v7/guide.md) – full usage guide and examples - [docs/ai-sdk-v7/configuration.md](docs/ai-sdk-v7/configuration.md) – all settings and how they map to CLI flags - [docs/ai-sdk-v7/troubleshooting.md](docs/ai-sdk-v7/troubleshooting.md) – common issues and fixes - [docs/ai-sdk-v7/limitations.md](docs/ai-sdk-v7/limitations.md) – known constraints and behavior differences - [docs/ai-sdk-v7/migration-v6-to-v7.md](docs/ai-sdk-v7/migration-v6-to-v7.md) – migrating from the 1.x (AI SDK v6) package line - See [examples/](examples/) for runnable scripts covering core usage, streaming, permissions/sandboxing, and object generation. - Validation helpers: - `npm run validate:docs` checks markdown links and example command paths - `npm run validate:examples:app-server` runs all app-server examples with intent checks - `npm run validate:full` runs build/type/lint/test plus docs and app-server example validation ## Authentication - Preferred: ChatGPT OAuth via `codex login` (stores tokens at `~/.codex/auth.json`) - Alternative: export `OPENAI_API_KEY` in the provider’s `env` settings (forwarded to the spawned process) ## Configuration (high level) - `allowNpx`: The provider prefers the locally installed `@openai/codex` package; when it can't be resolved, `allowNpx: true` falls back to `npx -y @openai/codex` (otherwise a `codex` binary on PATH is used) - `cwd`: Working directory for Codex - `addDirs`: Extra directories Codex may read/write (repeats `--add-dir`) - Autonomy/sandbox: - `dangerouslyBypassApprovalsAndSandbox` (bypass approvals and sandbox; dangerous) - Otherwise the provider writes `-c approval_policy=...` and `-c sandbox_mode=...` for you; defaults to `on-request` and `workspace-write`. `approvalMode: 'on-failure'` is deprecated (Codex CLI 0.143 retired it) and is sent as `on-request` - `fullAuto` is deprecated: Codex CLI 0.147 removed `codex exec --full-auto`. The flag now defaults to `sandboxMode: 'workspace-write'` and `approvalMode: 'never'` (what `--full-auto` pinned); explicit `sandboxMode` / `approvalMode` win, and it still suppresses `dangerouslyBypassApprovalsAndSandbox`. To migrate, set both settings explicitly and drop the bypass flag if it was configured alongside - `skipGitRepoCheck`: on by default (pass `false` to keep Codex's git-repo check for CI/non‑repo safety) - `color`: `always` | `never` | `auto` - `serviceTier`: Codex fast mode / service tier (`'fast'`, `'ultrafast'`, `'default'`, or any tier id advertised by the model); exec emits `-c service_tier="<tier>"`, app-server sends `serviceTier` on thread/start, thread/resume and turn/start (a per-call override applies to that call's turn only). See [Fast mode (service tier)](#fast-mode-service-tier) - `outputLastMessageFile`: by default the provider sets a temp path and reads it to capture final text reliably - Logging: - `verbose`: Enable debug/info logs (default: `false` for clean output) - `logger`: Custom logger object or `false` to disable all logging See [docs/ai-sdk-v7/configuration.md](docs/ai-sdk-v7/configuration.md) for the full list and examples. ### App-server settings highlights `createCodexAppServer({ defaultSettings })` accepts app-server specific options: - `connectionTimeoutMs`: initialize handshake timeout - `requestTimeoutMs`: default per-request JSON-RPC timeout - `idleTimeoutMs`: close idle app-server process after inactivity - `minCodexVersion`: minimum supported app-server version (semver) - `includeRawChunks`: emit raw JSON-RPC notifications as `raw` stream parts by default (per call, prefer the standard AI SDK v7 option `include: { rawChunks: true }` on `streamText`) - `serverRequests`: typed handlers for server-initiated JSON-RPC requests - `autoApprove`: default approval response when no custom handler is provided (covers command execution, file changes, skills, and MCP tool call approvals via `mcpServer/elicitation/request` on Codex >= 0.139) - `persistExtendedHistory`: request extended thread history persistence - `serviceTier`: Codex fast mode (`'fast'`), `'ultrafast'`, or `'default'` to force standard speed; sent on thread/start, thread/resume and every turn/start. A per-call `providerOptions['codex-app-server'].serviceTier` is sent as `serviceTierForTurn` and applies to that call's turn only (see [Fast mode (service tier)](#fast-mode-service-tier)) - `threadMode`: `stateless` (default) or `persistent` automatic thread reuse - `resume`: shorthand to resume an existing thread id - `onSessionCreated`: receive a session object for `injectMessage()` / `interrupt()` Per-call app-server overrides use `providerOptions['codex-app-server']` (for example `threadId`, `threadMode`, `includeRawChunks`, `personality`, `serviceTier`, `approvalPolicy`, `sandboxPolicy`, `serverRequests`, `configOverrides`). Raw chunk emission can also be requested per call with the standard AI SDK v7 option `include: { rawChunks: true }`. Additional app-server helpers: - `listModels()`: query available models via a temporary app-server process (or use `provider.listModels()` to query through an existing provider/client) - `tool()`, `createLocalMcpServer()`, `createSdkMcpServer()`: define and expose local MCP tools Local MCP security defaults: - `createLocalMcpServer()` binds to loopback hosts by default and rejects non-loopback `host` values unless you set `allowNonLoopbackHost: true`. - `createLocalMcpServer()` generates a per-server bearer token and expects `Authorization: Bearer <token>` on direct HTTP calls. The token is available at `server.config.bearerToken`. - `createSdkMcpServer()` propagates this auth config automatically, so provider-level MCP wiring works without extra manual headers. - Without `cacheKey`, SDK MCP server/tool function identity participates in persistent keying to avoid conflating closure-dependent tool behavior. - Use `createSdkMcpServer({ cacheKey })` when you intentionally recreate equivalent SDK MCP definitions per call and want stable persistent model reuse. ## Model Parameters & Advanced Options Control reasoning effort, verbosity, and advanced Codex features at model creation time: ```ts import { codexExec } from 'ai-sdk-provider-codex-cli'; const model = codexExec('gpt-6-astra', { allowNpx: true, skipGitRepoCheck: true, addDirs: ['../shared'], // Reasoning & verbosity reasoningEffort: 'medium', // none | minimal | low | medium | high | xhigh | max | ultra (max/ultra need Codex CLI >= 0.149; check listModels().supportedReasoningEfforts) reasoningSummary: 'auto', // auto | detailed (Note: 'concise' and 'none' are rejected by API) reasoningSummaryFormat: 'none', // none | experimental modelVerbosity: 'high', // low | medium | high // Speed (fast mode) serviceTier: 'fast', // fast | ultrafast | default | any tier id in listModels().serviceTiers (maps to -c service_tier=...) // Advanced features profile: 'production', // adds --profile production oss: false, // adds --oss when true webSearch: true, // maps to -c tools.web_search=true // MCP servers (stdio + HTTP/RMCP) rmcpClient: true, // enables HTTP-based MCP clients (features.rmcp_client=true) mcpServers: { local: { transport: 'stdio', command: 'node', args: ['tools/mcp.js'], env: { API_KEY: process.env.MCP_API_KEY ?? '' }, }, docs: { transport: 'http', url: 'https://mcp.my-org.com', bearerTokenEnvVar: 'MCP_BEARER', httpHeaders: { 'x-tenant': 'acme' }, }, }, // Generic overrides (maps to -c key=value) configOverrides: { experimental_resume: '/tmp/session.jsonl', sandbox_workspace_write: { network_access: true }, }, }); ``` Nested override objects are flattened to dotted keys (e.g., the example above emits `-c sandbox_workspace_write.network_access=true`). Arrays are serialized to JSON strings. MCP server env/header objects flatten the same way (e.g., `mcp_servers.docs.http_headers.x-tenant=acme`). ### Fast mode (service tier) Codex's fast mode (the `/fast` toggle in the TUI, `service_tier` in `config.toml`) is exposed as `serviceTier` in both providers and in their per-call `providerOptions`: - `'fast'` — Fast mode; Codex sends it as the catalog tier `priority`. Faster responses at higher usage: with a ChatGPT login it consumes included usage at 2.5x the standard rate; with an API key the API fast-mode price applies. - `'ultrafast'` — Ultrafast mode, only advertised by some models (GPT-6 Astra, GPT-6.1 Sol) and plans. - `'default'` — explicit standard speed. Use it to override a `service_tier` set in `~/.codex/config.toml`, or per call to run one request at standard speed. - Per-call overrides are scoped to the call. In the app-server provider the model-level tier is the thread default, and a per-call `serviceTier` is sent as `turn/start` `serviceTierForTurn`, so it never changes the tier of a persistent or resumed thread (and does not apply to a turn that is already running). - Any other string is passed through as a catalog tier id. Codex owns the list per model (`listModels()` reports `serviceTiers` and `defaultServiceTier`); a tier the model does not advertise is dropped with a warning on Codex's stderr and the request still runs at standard speed. ```ts import { codexExec, createCodexAppServer } from 'ai-sdk-provider-codex-cli'; const execFast = codexExec('gpt-6-sol', { serviceTier: 'fast' }); // -c service_tier="fast" const appServer = createCodexAppServer(); const appServerFast = appServer('gpt-6-sol', { serviceTier: 'fast' }); // serviceTier on thread/start + turn/start ``` When `serviceTier` is omitted nothing is sent and Codex falls back to your config.toml / the model's default tier. Runnable examples: `node examples/exec/fast-mode.mjs` and `node examples/app-server/fast-mode.mjs`. ### Per-call overrides via `providerOptions` Override these parameters for individual AI SDK calls using the `providerOptions` map. Per-call values take precedence over constructor defaults while leaving other settings intact. ```ts import { generateText } from 'ai'; import { codexExec } from 'ai-sdk-provider-codex-cli'; const model = codexExec('gpt-6-astra', { allowNpx: true, reasoningEffort: 'medium', modelVerbosity: 'medium', }); const response = await generateText({ model, prompt: 'Summarize the latest release notes.', providerOptions: { 'codex-cli': { reasoningEffort: 'high', reasoningSummary: 'detailed', textVerbosity: 'high', // AI SDK naming; maps to model_verbosity serviceTier: 'default', // standard speed for this call (fast | ultrafast | default | catalog tier id) rmcpClient: true, mcpServers: { scratch: { transport: 'stdio', command: 'pnpm', args: ['mcp', 'serve'], }, }, configOverrides: { experimental_resume: '/tmp/resume.jsonl', }, }, }, }); ``` **Precedence:** `providerOptions['codex-cli']` > top-level `reasoning` call option > constructor `CodexCliSettings` > Codex CLI defaults. The AI SDK v7 top-level `reasoning` option (`'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'`) maps directly to Codex reasoning effort in both provider modes; provider-specific effort options (`reasoningEffort` for exec, `effort` for app-server) win when both are set, and `'provider-default'` leaves your configured default untouched. The newer Codex levels `'max'` and `'ultra'` (Codex CLI >= 0.149, e.g. `gpt-6-astra`) are not part of the AI SDK union, so set them through the provider-specific options. App-server per-call overrides use `providerOptions['codex-app-server']`: ```ts import { createCodexAppServer } from 'ai-sdk-provider-codex-cli'; const appServerProvider = createCodexAppServer(); const response = await generateText({ model: appServerProvider('gpt-6-astra'), prompt: 'Continue this task.', providerOptions: { 'codex-app-server': { threadId: 'thr_existing', personality: 'pragmatic', serviceTier: 'fast', approvalPolicy: 'on-request', }, }, }); ``` ## Zod Compatibility - Peer dependency: `zod@^4.1.8` (Zod 4 only; Zod 3 is not supported) ## Limitations - Node ≥ 22, ESM-only, local process only (no Edge) - Codex `--experimental-json` mode emits events rather than streaming deltas; streaming typically yields a final chunk. The CLI provides the final assistant text in the `item.completed` event, which this provider reads and emits at the end. - Some AI SDK parameters are unsupported by Codex CLI (e.g., temperature/topP/penalties); the provider surfaces warnings and ignores them ### JSON Schema Limitations **⚠️ Important:** OpenAI strict mode has limitations: - **Optional fields NOT supported**: All fields must be required (no `.optional()`) - **Format validators stripped**: `.email()`, `.url()`, `.uuid()` are removed (use descriptions instead) - **Pattern validators stripped**: `.regex()` is removed (use descriptions instead) See [LIMITATIONS.md](LIMITATIONS.md) for comprehensive details and migration guidance. ## Disclaimer This is a community provider and not an official OpenAI or Vercel product. You are responsible for complying with all applicable terms and ensuring safe usage. ## License MIT