# provider-openai-codex

> OpenAI Codex (ChatGPT subscription) provider; implements provider::openai-codex::stream and provider::openai-codex::refresh_models behind llm-router, with ChatGPT device-code sign-in and automatic session renewal backed by private state.

| field | value |
|-------|-------|
| version | 0.4.27 |
| type | binary |
| license | Apache-2.0 |
| repo | https://github.com/iii-hq/workers |
| supported_targets | x86_64-apple-darwin, aarch64-apple-darwin, x86_64-pc-windows-msvc, aarch64-pc-windows-msvc, x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu, x86_64-unknown-linux-musl, armv7-unknown-linux-gnueabihf |
| author | iii |

## installation

```sh
iii trigger compose::add worker=provider-openai-codex@0.4.27
```

## dependencies

- `llm-router` @ `latest`
- `state` @ `latest`

## readme

# provider-openai-codex

OpenAI **Codex (ChatGPT subscription)** provider worker behind
[llm-router](https://github.com/iii-hq/workers/tree/main/llm-router). It lets the stack generate against a ChatGPT/Codex
subscription (billed to the plan, "Sign in with ChatGPT") instead of a
pay-per-token API key, by speaking OpenAI's **Responses API** at the Codex
backend.

Implements the provider protocol from `tech-specs/2026-06-agentic/llm-router.md`:
`provider::openai-codex::stream` (Responses SSE → `AssistantMessageEvent` frames
into a router-owned channel), `provider::openai-codex::refresh_models`
(fetches and reconciles the authenticated Codex model catalog), and
`provider::openai-codex::count_tokens` (local prompt token estimation with
the tiktoken tokenizers behind `router::count_tokens`; never runs the model,
costs nothing, and needs no network).

> ⚠️ **Terms-of-service caveat — local/personal dev only.** This drives a
> personal ChatGPT subscription through the undocumented
> `https://chatgpt.com/backend-api/codex` backend with a Codex-client
> `originator` header. That is plausibly against OpenAI's terms and may risk
> account action; the backend is unversioned and can change without notice. Use
> it for local, personal development. For team/CI/production, use official
> API-key billing (`provider-openai`). You assume the risk.

## Credentials

Open this provider's configuration form in the console and select **Sign in
with ChatGPT**. Open the verification link, enter the displayed code, and
approve the login. The provider finishes the login in the background, saves the
session, and refreshes the model catalog. No Codex CLI is required, including
when the provider runs on a remote machine.

Device login must be enabled in your ChatGPT security settings or workspace
permissions. Codes expire after 15 minutes. Cancel or start a new attempt if
needed; reopening the form resumes an attempt while the worker is running.
Restarting the worker cancels pending attempts, but retains completed logins.

The form shows session status independently from the saved model catalog. Use
**Refresh models** to retry catalog discovery, **Switch account** to replace
the active account after a successful login, or **Log out** to sign out this
provider. Logging out does not sign out the Codex CLI or revoke other clients.
The provider will not silently reconnect using a local or external credential.

One account is shared by this provider's consumers in each engine namespace.
Run one provider instance per namespace. Its tokens are kept in the private
`provider-openai-codex-auth` state scope, separate from router registration.
The state worker's public API and state-change subscriptions cannot expose that
scope. Keep the state adapter durable to retain sessions across stack restarts;
a private namespace provides access separation, not encryption at rest.

Managed credentials renew automatically within 60 seconds of expiry. Refresh
requests are serialized and token rotations are persisted atomically. A
revoked session requires another login; temporary storage/network errors do
not erase it or switch accounts. The provider never returns tokens to the UI
or writes them into router configuration.

Before the first managed login or explicit disconnect, existing installations
can still use `auth::get_token` from an external credential vault, then a
read-only `${CODEX_HOME:-$HOME/.codex}/auth.json` fallback. The vault remains
responsible for its own refresh. The provider never imports or writes the CLI
file, and never refreshes the CLI's tokens. The file fallback needs host access
and does not support an OS keyring-only login.

### Authentication functions

All IDs below begin with `provider::openai-codex::`. These are operator APIs;
the harness, event bindings, and guarded dispatchers deny agent calls to them
and to the provider's private state accessors. These checks rely on the existing
trusted-engine boundary: they do not isolate credentials from arbitrary code
with a direct engine connection or host filesystem access.

| Function | Input | Result |
| --- | --- | --- |
| `login::start` | `{}` | `login_id`, `verification_uri`, `user_code`, `expires_at` (Unix seconds), `interval` (seconds) |
| `login::poll` | `{login_id}` | `status`: `pending`, `ok`, `expired`, `canceled`, or `error`; sanitized error when present |
| `login::cancel` | `{login_id}` | `{ok: true}`; idempotent, keeps the active account |
| `auth::status` | `{}` | `status`: `signed_out`, `authenticated`, or `expired`; `source`, `account_id`, pending `login` |
| `auth::logout` | `{}` | `{ok: true}` after disconnect is persisted |

Unknown or pre-restart login IDs return `canceled`. Storage failures return an
error instead of a success acknowledgment. Tokens stay entirely in the backend.

API-key credentials are rejected — they belong on `provider-openai` under
provider id `openai`.

## Behavior

- **Registration:** self-declares via `router::provider::register` with backoff,
  and re-declares on the `router::ready` trigger. It advertises dynamic model
  listing and `credential_env_var: None`; identity binds via the
  `registration_token` persisted in state (scope `provider-openai-codex`).
- **Models:** fetches the account-scoped Codex catalog from authenticated
  `GET /backend-api/codex/models?client_version=…` at startup, on explicit
  refresh, after successful sign-in, after router readiness, and every three minutes. Picker-visible
  results become **namespaced** router ids (`codex/<upstream-id>`). Each
  successful non-empty response replaces the complete provider slice, adding
  new models and removing retired ones. Failed or empty refreshes preserve the
  router's persisted last-known-good slice. Namespacing prevents
  `AmbiguousModel` collisions with `provider-openai`.
  Context limits follow the catalog's `max_context_window`, using
  `context_window` only when it is absent. In the [upstream Codex contract](https://github.com/openai/codex/blob/rust-v0.159.0/codex-rs/protocol/src/openai_models.rs#L452-L455)
  `context_window` is the CLI's default working window (272K) and
  `max_context_window` the ceiling for configuration overrides (872K). The
  backend itself accepts input up to ~922K on current models, so the ceiling
  is the larger limit that is still safe to advertise.
- **Request:** Responses API — `input` items, `stream: true`, `store: false`,
  optional `tools` and `reasoning: { effort }`. Headers: `Authorization: Bearer`,
  `chatgpt-account-id`, Codex compatibility `version`,
  `openai-beta: responses=experimental`,
  `originator: codex_cli_rs`.
- **Cache routing:** the `session-id` / `thread-id` / `x-client-request-id`
  headers always carry a UUID derived from the router's `session_id`. The body
  `prompt_cache_key` is resolved separately: a caller's
  `provider_options.openai-codex.prompt_cache_key` override, else a UUID
  derived from the router's `cache_intent.surface_digest` (the frozen
  agent-profile prefix), else the same session-derived UUID.

  The subscription backend caches per session, not per content: a second turn
  in the same session reads the prefix from cache (`cached_tokens` ~17.9k on an
  18k-token prefix), but an independent session on a byte-identical prefix
  reads 0 and the backend records `cache_write_tokens: 0` for it. The cache
  entry is keyed to the session-affinity headers, which are per-session by
  design, so a shared body `prompt_cache_key` does not move routing to a shared
  shard, and cross-session reuse is not achievable here without reusing session
  identity across independent agents. The backend also rejects
  `prompt_cache_breakpoint` on every model (`gpt-6-astra` included:
  `prompt_cache_breakpoint is not supported on this model`), so the explicit
  breakpoint that `provider-openai` uses on GPT-5.6+ does not apply. Read
  `usage.cache_read` for the real signal; the shared body key stays in case the
  backend's routing changes.
- **SSE:** `response.output_text.delta` → text, `response.reasoning_*` →
  thinking, `response.function_call_arguments.delta` → tool calls,
  `response.completed` → usage + terminal. Unknown event types are ignored
  (forward-compat).
- **Liveness / errors:** `ping` at least every 30s of silence; 401/403 →
  `auth_expired`, 429 → `rate_limited`, `context_length_exceeded` →
  `context_overflow`, 5xx/network → `transient`, other 4xx → `permanent`. The
  provider attempts one managed-token refresh and retry on HTTP 401 before
  streaming starts; it never replays content already delivered. The router
  owns other retry policy.

## Image generation

`provider::openai-codex::image::generate` and
`provider::openai-codex::image::read` are the **agent-callable** functions of
this worker (images have no router front door). The Codex backend has no
`/images/generations` endpoint, so the picture is made the way the Codex CLI
makes it: a Responses call on a Codex chat model (`host_model`, default
`gpt-5.5`; `codex/…` router ids accepted) carries the hosted
`image_generation` tool pinned to the requested image model, `tool_choice`
forces that tool, and the streamed `image_generation_call` item's `result`
is the image. Billing follows the ChatGPT plan.

`generate` writes the picture, at full resolution, to
`data/provider-openai-codex/images/<stem>-<unix_ms>-<8 hex>.<ext>` (relative
to the Compose project directory, `III_COMPOSE_DIR`) and returns that path
with **no image bytes** — base64 in a function result only inflates the
conversation context.

```jsonc
// request
{ "model": "gpt-image-2.5-flare",         // or gpt-image-2.5-sunburst (anything else is rejected)
  "prompt": "a lighthouse at dusk, oil painting",
  "size": "1024x1536",                     // 1024x1024 | 1536x1024 | 1024x1536 | auto
  "quality": "medium",                     // low | medium | high | auto
  "output_format": "png",                  // png (default) | jpeg | webp
  "background": "auto",                    // transparent | opaque | auto
  "file_name": "lighthouse",               // optional stem for the saved file
  "host_model": "gpt-5.5" }                // optional Codex chat model hosting the tool call

// response — the same envelope as browser::screenshot, minus the picture
{ "content": [
    { "type": "text", "text": "Image generated by gpt-image-2.5-flare via Codex (1024x1536, 1612044 bytes, image/png) saved to /…/data/provider-openai-codex/images/lighthouse-1790171000000-8c21be07.png; view with provider::openai-codex::image::read { path }" } ],
  "details": { "model", "host_model", "path", "mime", "bytes", "size", "quality", "width", "height", "inline": "none", "revised_prompt?", "usage?" } }
```

**Preview in the chat.** The injected console UI (`ui/src/image-renderer.tsx`)
renders the card for a `generate` call by fetching a downscaled JPEG from
this worker through `image::read`, and shows it beside the copyable path,
dimensions, size and models — the bytes travel worker → console, never
through the model.

**Looking at the picture from an agent.** `image::read { path, variant? }`
takes the `details.path` a generate call returned (or the bare file name)
and returns viewable content blocks: `variant: "preview"` (default; JPEG
≤512px / ~80 KB, fits the harness's 256 KiB result cap) or `variant:
"full"`. Anything outside `data/provider-openai-codex/images/` is refused,
symlinks included. `generate` also accepts `inline: "preview" | "full"` to
embed the picture in its own result. If the host model answers in prose
instead of calling the tool (a plan without image generation, a refused
prompt), the error carries its text so the reason is visible.

## Running

Standard worker CLI: `--url` (engine WebSocket, default `ws://127.0.0.1:49134`,
or `III_URL`), `--manifest` (print the registry manifest and exit), `--config`
(accepted but ignored — this worker has no file-based config).

```bash
cargo run -- --url ws://127.0.0.1:49134
```

## Tests

```bash
cargo test    # OAuth/session modules, HTTP/SSE stubs, schema goldens
pnpm --dir ui test
pnpm --dir ui build
```

Regenerate the wire-schema goldens with `UPDATE_GOLDENS=1 cargo test`.

## Troubleshooting

| Symptom | Cause | Fix |
| --- | --- | --- |
| `not configured: sign in with ChatGPT …` | no active session | select **Sign in with ChatGPT** in the provider form |
| `device_login_disabled` | device-code sign-in is disabled | enable it in ChatGPT security settings or ask your workspace administrator |
| `storage_unavailable` | state worker is down or lacks private namespace support | start/update the state worker and retry; credentials are not replaced by a fallback |
| `auth_expired` | token was revoked or the CLI fallback expired | sign in again in the provider form |
| `requires a ChatGPT OAuth login … API keys belong on provider-openai` | credential is an API key | this provider is OAuth-only; use `provider-openai` for keys |
| `missing ChatGPT account id` | token lacks the account claim | sign in again with a ChatGPT account |
| backend `Unsupported parameter` / shape errors | Codex backend contract drifted | update this worker's request/SSE mapping against the current backend |
| model refresh fails or returns no visible models | auth/network/backend catalog problem | the last known catalog is retained; fix the underlying error and call `provider::openai-codex::refresh_models` |
| model routes ambiguously | a `codex/*` id collided with another provider | keep codex ids namespaced; or pin `provider: "openai-codex"` |

The OAuth adapter follows the upstream [Codex device login](https://github.com/openai/codex/blob/rust-v0.153.4/codex-rs/login/src/device_code_auth.rs)
and token refresh protocol.
See [OpenAI authentication guidance](https://learn.chatgpt.com/docs/auth) for
account/workspace setup.

## api reference

```json
{
  "functions": [
    {
      "description": "Serve the provider-openai-codex worker's injected console UI assets (content function for its console:script / console:style / console:module triggers).",
      "metadata": {
        "internal": true
      },
      "name": "provider-openai-codex::ui-content",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Input of the content function: the console asks for one asset by path.",
        "properties": {
          "path": {
            "description": "The asset path from the trigger config (e.g. `state/page.js`).",
            "type": "string"
          }
        },
        "required": [
          "path"
        ],
        "title": "UiContentInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Output of the content function.",
        "properties": {
          "content": {
            "description": "The asset source, verbatim.",
            "type": "string"
          },
          "content_type": {
            "description": "MIME type the console should serve the asset with.",
            "type": "string"
          }
        },
        "required": [
          "content",
          "content_type"
        ],
        "title": "UiContentResult",
        "type": "object"
      }
    },
    {
      "description": "Cancel the in-flight upstream stream for a request_id (router::abort fan-out), stopping billed generation immediately.",
      "metadata": {
        "internal": true
      },
      "name": "provider::openai-codex::abort",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Input of a provider's `provider::<id>::abort`: actively cancel the in-flight upstream stream for `request_id` (the router's `request_id`, delivered to the provider as `resolution_key`) so billed generation stops immediately instead of waiting for the provider to notice the closed channel on its next write.",
        "properties": {
          "request_id": {
            "type": "string"
          }
        },
        "required": [
          "request_id"
        ],
        "title": "ProviderAbortRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Output of `provider::<id>::abort`. `aborted: false` means the request was unknown — already finished, never started, or aborted before (idempotent).",
        "properties": {
          "aborted": {
            "type": "boolean"
          }
        },
        "required": [
          "aborted"
        ],
        "title": "ProviderAbortResponse",
        "type": "object"
      }
    },
    {
      "description": "Disconnect this provider, cancel pending login, and persistently disable automatic use of legacy credentials. Does not sign out the Codex CLI.",
      "metadata": {
        "internal": true
      },
      "name": "provider::openai-codex::auth::logout",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "EmptyRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "Ack",
        "type": "object"
      }
    },
    {
      "description": "Read Codex session status, credential source, account id, and any pending login. Never returns tokens.",
      "metadata": {
        "internal": true
      },
      "name": "provider::openai-codex::auth::status",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "EmptyRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "AuthStatus": {
            "enum": [
              "signed_out",
              "authenticated",
              "expired"
            ],
            "type": "string"
          },
          "CredentialSource": {
            "enum": [
              "managed",
              "vault",
              "local"
            ],
            "type": "string"
          },
          "LoginStartResponse": {
            "properties": {
              "expires_at": {
                "description": "Unix timestamp in seconds.",
                "format": "int64",
                "type": "integer"
              },
              "interval": {
                "description": "Seconds between status requests from the UI.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "login_id": {
                "type": "string"
              },
              "user_code": {
                "type": "string"
              },
              "verification_uri": {
                "type": "string"
              }
            },
            "required": [
              "expires_at",
              "interval",
              "login_id",
              "user_code",
              "verification_uri"
            ],
            "type": "object"
          }
        },
        "properties": {
          "account_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "login": {
            "anyOf": [
              {
                "$ref": "#/definitions/LoginStartResponse"
              },
              {
                "type": "null"
              }
            ]
          },
          "source": {
            "anyOf": [
              {
                "$ref": "#/definitions/CredentialSource"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "$ref": "#/definitions/AuthStatus"
          }
        },
        "required": [
          "status"
        ],
        "title": "AuthStatusResponse",
        "type": "object"
      }
    },
    {
      "description": "Count prompt tokens for {model, system_prompt?, tools?, messages} locally with the tiktoken tokenizers; never runs the model and costs nothing.",
      "metadata": {
        "internal": true
      },
      "name": "provider::openai-codex::count_tokens",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "AgentFunction": {
            "description": "Function invocation schema — what a provider sees as a `tools` array entry (README § Function invocation schema; adapter boundary). These describe iii functions exposed to the model, not provider-native tools.",
            "properties": {
              "description": {
                "type": "string"
              },
              "execution_mode": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "label": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "parameters": true
            },
            "required": [
              "description",
              "name",
              "parameters"
            ],
            "type": "object"
          },
          "AgentMessage": {
            "anyOf": [
              {
                "$ref": "#/definitions/AssistantMessage"
              },
              {
                "$ref": "#/definitions/FunctionResultMessage"
              },
              {
                "$ref": "#/definitions/CustomMessage"
              },
              {
                "$ref": "#/definitions/UserMessage"
              }
            ],
            "description": "The canonical transcript message union. Untagged: the single-variant role tags disambiguate deserialization."
          },
          "AssistantMessage": {
            "properties": {
              "content": {
                "items": {
                  "$ref": "#/definitions/ContentBlock"
                },
                "type": "array"
              },
              "error_kind": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/ErrorKind"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "error_message": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "model": {
                "type": "string"
              },
              "native_stop_reason": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "provider": {
                "type": "string"
              },
              "role": {
                "$ref": "#/definitions/AssistantRoleTag"
              },
              "stop_reason": {
                "$ref": "#/definitions/StopReason"
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              },
              "usage": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Usage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "warnings": {
                "items": {
                  "type": "string"
                },
                "type": [
                  "array",
                  "null"
                ]
              }
            },
            "required": [
              "content",
              "model",
              "provider",
              "role",
              "stop_reason",
              "timestamp"
            ],
            "type": "object"
          },
          "AssistantRoleTag": {
            "enum": [
              "assistant"
            ],
            "type": "string"
          },
          "ContentBlock": {
            "description": "Content blocks — the atomic units of message content (README § Content blocks).",
            "oneOf": [
              {
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "text"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "text",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "attachment_id": {
                    "description": "Optional link to the stored original in the session-manager attachment store. Transcript bookkeeping for lazy readers only: the harness clears it before `router::chat`, and no provider mapping reads it. Tolerated here so a block that still carries it deserializes instead of failing the request; omitted on the wire when absent.",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "data": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "image"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "data",
                  "mime",
                  "type"
                ],
                "type": "object"
              },
              {
                "description": "Reference to an original upload in the session-manager attachment store. A REFERENCE ONLY (never inline bytes); the harness strips it before `router::chat`. Tolerated here so a stray block deserializes instead of failing the request; every counter/mapping emits nothing for it.",
                "properties": {
                  "attachment_id": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "size": {
                    "format": "uint64",
                    "minimum": 0,
                    "type": "integer"
                  },
                  "type": {
                    "enum": [
                      "file"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "attachment_id",
                  "mime",
                  "name",
                  "size",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "signature": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "text": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "thinking"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "text",
                  "type"
                ],
                "type": "object"
              },
              {
                "description": "Opaque redacted thinking payload — replayed verbatim on the Anthropic wire.",
                "properties": {
                  "data": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "redacted_thinking"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "data",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "arguments": true,
                  "function_id": {
                    "type": "string"
                  },
                  "id": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "function_call"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "arguments",
                  "function_id",
                  "id",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "content": {
                    "items": {
                      "$ref": "#/definitions/ContentBlock"
                    },
                    "type": "array"
                  },
                  "function_call_id": {
                    "type": "string"
                  },
                  "is_error": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "type": {
                    "enum": [
                      "function_result"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "content",
                  "function_call_id",
                  "type"
                ],
                "type": "object"
              }
            ]
          },
          "CustomMessage": {
            "properties": {
              "content": {
                "items": {
                  "$ref": "#/definitions/ContentBlock"
                },
                "type": "array"
              },
              "custom_type": {
                "type": "string"
              },
              "details": true,
              "display": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "role": {
                "$ref": "#/definitions/CustomRoleTag"
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "content",
              "custom_type",
              "role",
              "timestamp"
            ],
            "type": "object"
          },
          "CustomRoleTag": {
            "enum": [
              "custom"
            ],
            "type": "string"
          },
          "ErrorKind": {
            "enum": [
              "auth_expired",
              "rate_limited",
              "context_overflow",
              "transient",
              "permanent"
            ],
            "type": "string"
          },
          "FunctionResultMessage": {
            "properties": {
              "content": {
                "items": {
                  "$ref": "#/definitions/ContentBlock"
                },
                "type": "array"
              },
              "details": true,
              "function_call_id": {
                "type": "string"
              },
              "function_id": {
                "type": "string"
              },
              "is_error": {
                "type": "boolean"
              },
              "role": {
                "$ref": "#/definitions/FunctionResultRoleTag"
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "content",
              "details",
              "function_call_id",
              "function_id",
              "is_error",
              "role",
              "timestamp"
            ],
            "type": "object"
          },
          "FunctionResultRoleTag": {
            "enum": [
              "function_result"
            ],
            "type": "string"
          },
          "StopReason": {
            "enum": [
              "end",
              "length",
              "function_call",
              "aborted",
              "error"
            ],
            "type": "string"
          },
          "Usage": {
            "properties": {
              "cache_read": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cache_write": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cost_usd": {
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "input": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "output": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "reasoning": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "type": "object"
          },
          "UserMessage": {
            "properties": {
              "content": {
                "items": {
                  "$ref": "#/definitions/ContentBlock"
                },
                "type": "array"
              },
              "role": {
                "$ref": "#/definitions/UserRoleTag"
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "content",
              "role",
              "timestamp"
            ],
            "type": "object"
          },
          "UserRoleTag": {
            "description": "Single-variant role tags: exact-match on deserialize, correct wire string on serialize, and they let `AgentMessage` be an untagged union.",
            "enum": [
              "user"
            ],
            "type": "string"
          }
        },
        "properties": {
          "messages": {
            "description": "Wire agent messages, the same shape `provider::openai-codex::stream` accepts. Must be non-empty.",
            "items": {
              "$ref": "#/definitions/AgentMessage"
            },
            "type": "array"
          },
          "model": {
            "description": "Model id the prompt targets; selects the tokenizer (o200k_base for gpt-4o/gpt-5/o-series and anything unknown-modern, cl100k_base for gpt-3.5 and non-o gpt-4 families).",
            "type": "string"
          },
          "system_prompt": {
            "default": null,
            "description": "System prompt counted as its own wire message when present.",
            "type": [
              "string",
              "null"
            ]
          },
          "tools": {
            "default": null,
            "description": "Function invocation schemas; each serialized schema counts toward the total.",
            "items": {
              "$ref": "#/definitions/AgentFunction"
            },
            "type": [
              "array",
              "null"
            ]
          }
        },
        "required": [
          "messages",
          "model"
        ],
        "title": "CountTokensRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "estimator": {
            "description": "Always `tiktoken`: a local tokenizer produced the estimate.",
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "tokens": {
            "description": "Estimated prompt tokens for the assembled request.",
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "estimator",
          "model",
          "tokens"
        ],
        "title": "CountTokensResponse",
        "type": "object"
      }
    },
    {
      "description": "Generate one image from a text prompt with gpt-image-2.5-sunburst or gpt-image-2.5-flare on the ChatGPT subscription backend (a Codex chat model hosts the image_generation tool). Returns viewable content blocks (image + caption) that render inline, and saves the file under data/provider-openai-codex/images/ (details.path) for other processes to pick up.",
      "metadata": {},
      "name": "provider::openai-codex::image::generate",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "background": {
            "default": null,
            "description": "`transparent`, `opaque`, or `auto`; transparency needs png or webp.",
            "type": [
              "string",
              "null"
            ]
          },
          "file_name": {
            "default": null,
            "description": "File stem for the persisted image (letters, digits, `.`, `_`, `-`; anything else becomes `-`). A timestamp and a random suffix are always appended so files never collide. Defaults to `image`.",
            "type": [
              "string",
              "null"
            ]
          },
          "host_model": {
            "default": null,
            "description": "Codex chat model that hosts the `image_generation` tool call (default `gpt-5.5`; the router's `codex/` prefix is accepted).",
            "type": [
              "string",
              "null"
            ]
          },
          "inline": {
            "default": null,
            "description": "Whether the result embeds image bytes: `none` (default — the file is saved, `details.path` names it, and the console fetches its own preview), `preview` (a JPEG at most 512px / ~80 KB, for an agent that must look at the picture; fits the harness result cap), or `full` (the original bytes — over a megabyte for a 1024px PNG).",
            "type": [
              "string",
              "null"
            ]
          },
          "model": {
            "description": "Image model: `gpt-image-2.5-sunburst` or `gpt-image-2.5-flare`.",
            "type": "string"
          },
          "output_format": {
            "default": null,
            "description": "`png` (default), `jpeg`, or `webp`: the format of the file saved under data/ (and of the inline picture when `inline` is `full`).",
            "type": [
              "string",
              "null"
            ]
          },
          "prompt": {
            "description": "What to draw (up to 32k characters).",
            "type": "string"
          },
          "quality": {
            "default": null,
            "description": "`low`, `medium`, `high`, or `auto`; the model default when omitted.",
            "type": [
              "string",
              "null"
            ]
          },
          "size": {
            "default": null,
            "description": "`1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto`; the model default when omitted.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "model",
          "prompt"
        ],
        "title": "ImageGenerateRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "ContentBlock": {
            "description": "One block of a viewable response: an image block plus a text line — the shape the harness renders inline (same as `browser::screenshot`).",
            "properties": {
              "data": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "mime": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "text": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "type": {
                "type": "string"
              }
            },
            "required": [
              "type"
            ],
            "type": "object"
          },
          "ImageDetails": {
            "properties": {
              "bytes": {
                "description": "Saved file size in bytes.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "height": {
                "description": "Pixel height of the saved file, when decodable.",
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "host_model": {
                "description": "Codex chat model that hosted the tool call.",
                "type": "string"
              },
              "inline": {
                "description": "`preview`, `full`, or `none`: what the inline image block carries.",
                "type": "string"
              },
              "mime": {
                "description": "Mime of the saved file: `image/png`, `image/jpeg`, or `image/webp`.",
                "type": "string"
              },
              "model": {
                "description": "Image model that produced the picture.",
                "type": "string"
              },
              "path": {
                "description": "Absolute path of the full-resolution file under `data/provider-openai-codex/images/`.",
                "type": "string"
              },
              "preview": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/PreviewDetails"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Present when `inline` is `preview` and the preview could be built."
              },
              "quality": {
                "description": "Requested quality (`auto` when left to the model).",
                "type": "string"
              },
              "revised_prompt": {
                "description": "The prompt as the model actually rendered it, when upstream reports one.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "size": {
                "description": "Requested size (`auto` when left to the model).",
                "type": "string"
              },
              "usage": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/ImageUsage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "width": {
                "description": "Pixel width of the saved file, when decodable.",
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "required": [
              "bytes",
              "host_model",
              "inline",
              "mime",
              "model",
              "path",
              "quality",
              "size"
            ],
            "type": "object"
          },
          "ImageUsage": {
            "description": "Token usage of the hosting Responses call (absent when the backend omits it).",
            "properties": {
              "input_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "output_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "total_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "type": "object"
          },
          "PreviewDetails": {
            "description": "What the inline image block actually holds when it is a preview.",
            "properties": {
              "bytes": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "height": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "mime": {
                "type": "string"
              },
              "width": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "bytes",
              "height",
              "mime",
              "width"
            ],
            "type": "object"
          }
        },
        "properties": {
          "content": {
            "description": "`[image block, text line]` (`[text line]` with `inline: none`) — render `content` and the picture shows.",
            "items": {
              "$ref": "#/definitions/ContentBlock"
            },
            "type": "array"
          },
          "details": {
            "$ref": "#/definitions/ImageDetails"
          }
        },
        "required": [
          "content",
          "details"
        ],
        "title": "ImageGenerateResponse",
        "type": "object"
      }
    },
    {
      "description": "Read back an image saved by image::generate (its details.path or bare file name under data/provider-openai-codex/images/) as viewable content blocks: a JPEG preview (default, fits the harness result cap) or the full bytes. Refuses any path outside that folder.",
      "metadata": {},
      "name": "provider::openai-codex::image::read",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Read a generated image back. Callers pass the `details.path` a generate call returned (or just its file name); anything outside `IMAGE_DATA_DIR` is refused, symlinks included, so this never becomes a general file reader. The console renderer uses it for the chat preview; an agent uses it when it needs to look at a picture it generated without `inline`.",
        "properties": {
          "path": {
            "description": "Absolute path returned by `image::generate`, or the bare file name inside `data/provider-openai-codex/images/`.",
            "type": "string"
          },
          "variant": {
            "default": null,
            "description": "`preview` (default; a JPEG at most 512px / ~80 KB that fits the harness result cap) or `full` (the saved bytes as they are).",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "path"
        ],
        "title": "ImageReadRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "ContentBlock": {
            "description": "One block of a viewable response: an image block plus a text line — the shape the harness renders inline (same as `browser::screenshot`).",
            "properties": {
              "data": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "mime": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "text": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "type": {
                "type": "string"
              }
            },
            "required": [
              "type"
            ],
            "type": "object"
          },
          "ImageReadDetails": {
            "properties": {
              "bytes": {
                "description": "Saved file size in bytes.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "height": {
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "mime": {
                "description": "Mime of the saved file.",
                "type": "string"
              },
              "path": {
                "description": "Absolute path of the file that was read.",
                "type": "string"
              },
              "preview": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/PreviewDetails"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "variant": {
                "description": "`preview` or `full`: what the image block carries.",
                "type": "string"
              },
              "width": {
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "required": [
              "bytes",
              "mime",
              "path",
              "variant"
            ],
            "type": "object"
          },
          "PreviewDetails": {
            "description": "What the inline image block actually holds when it is a preview.",
            "properties": {
              "bytes": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "height": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "mime": {
                "type": "string"
              },
              "width": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "bytes",
              "height",
              "mime",
              "width"
            ],
            "type": "object"
          }
        },
        "properties": {
          "content": {
            "description": "`[image block, text line]` — the same viewable envelope as generate.",
            "items": {
              "$ref": "#/definitions/ContentBlock"
            },
            "type": "array"
          },
          "details": {
            "$ref": "#/definitions/ImageReadDetails"
          }
        },
        "required": [
          "content",
          "details"
        ],
        "title": "ImageReadResponse",
        "type": "object"
      }
    },
    {
      "description": "Cancel a pending device login. Does not disconnect the current account.",
      "metadata": {
        "internal": true
      },
      "name": "provider::openai-codex::login::cancel",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "login_id": {
            "type": "string"
          }
        },
        "required": [
          "login_id"
        ],
        "title": "LoginIdRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "Ack",
        "type": "object"
      }
    },
    {
      "description": "Read a device login attempt's status without exposing OAuth tokens.",
      "metadata": {
        "internal": true
      },
      "name": "provider::openai-codex::login::poll",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "login_id": {
            "type": "string"
          }
        },
        "required": [
          "login_id"
        ],
        "title": "LoginIdRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "LoginStatus": {
            "enum": [
              "pending",
              "ok",
              "expired",
              "canceled",
              "error"
            ],
            "type": "string"
          },
          "SessionError": {
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ],
            "type": "object"
          }
        },
        "properties": {
          "error": {
            "anyOf": [
              {
                "$ref": "#/definitions/SessionError"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "$ref": "#/definitions/LoginStatus"
          }
        },
        "required": [
          "status"
        ],
        "title": "LoginPollResponse",
        "type": "object"
      }
    },
    {
      "description": "Start a ChatGPT device-code login. Returns the verification URL and one-time user code; the provider completes and saves the session in the background.",
      "metadata": {
        "internal": true
      },
      "name": "provider::openai-codex::login::start",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "EmptyRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "expires_at": {
            "description": "Unix timestamp in seconds.",
            "format": "int64",
            "type": "integer"
          },
          "interval": {
            "description": "Seconds between status requests from the UI.",
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "login_id": {
            "type": "string"
          },
          "user_code": {
            "type": "string"
          },
          "verification_uri": {
            "type": "string"
          }
        },
        "required": [
          "expires_at",
          "interval",
          "login_id",
          "user_code",
          "verification_uri"
        ],
        "title": "LoginStartResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal: router::ready subscriber that re-declares this provider and refreshes its catalog.",
      "metadata": {
        "internal": true
      },
      "name": "provider::openai-codex::on_router_ready",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Event delivered to a provider's `provider::<id>::on_router_ready` (the `router::ready` trigger payload, currently `{}`). Unknown fields are ignored.",
        "title": "RouterReadyEvent",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Ack returned by a provider's `provider::<id>::on_router_ready`.",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "ProviderReadyAck",
        "type": "object"
      }
    },
    {
      "description": "Fetch the authenticated Codex model catalog and replace this provider's namespaced router slice; returns the active model count.",
      "metadata": {
        "internal": true
      },
      "name": "provider::openai-codex::refresh_models",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Input of a provider's `provider::<id>::refresh_models` — takes no arguments. A struct (not `Value`) keeps the request schema concrete; unknown fields (e.g. the engine-injected `_caller_worker_id`) are ignored.",
        "title": "RefreshModelsRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Output of `provider::<id>::refresh_models`.",
        "properties": {
          "count": {
            "format": "uint",
            "minimum": 0,
            "type": "integer"
          },
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "count",
          "ok"
        ],
        "title": "RefreshModelsResponse",
        "type": "object"
      }
    },
    {
      "description": "Stream an OpenAI Codex completion: resolve a ChatGPT OAuth token from the provider session, call the upstream Responses API, and relay AssistantMessageEvent frames to writer_ref.",
      "metadata": {
        "internal": true
      },
      "name": "provider::openai-codex::stream",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "AgentFunction": {
            "description": "Function invocation schema — what a provider sees as a `tools` array entry (README § Function invocation schema; adapter boundary). These describe iii functions exposed to the model, not provider-native tools.",
            "properties": {
              "description": {
                "type": "string"
              },
              "execution_mode": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "label": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "parameters": true
            },
            "required": [
              "description",
              "name",
              "parameters"
            ],
            "type": "object"
          },
          "AgentMessage": {
            "anyOf": [
              {
                "$ref": "#/definitions/AssistantMessage"
              },
              {
                "$ref": "#/definitions/FunctionResultMessage"
              },
              {
                "$ref": "#/definitions/CustomMessage"
              },
              {
                "$ref": "#/definitions/UserMessage"
              }
            ],
            "description": "The canonical transcript message union. Untagged: the single-variant role tags disambiguate deserialization."
          },
          "AssistantMessage": {
            "properties": {
              "content": {
                "items": {
                  "$ref": "#/definitions/ContentBlock"
                },
                "type": "array"
              },
              "error_kind": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/ErrorKind"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "error_message": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "model": {
                "type": "string"
              },
              "native_stop_reason": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "provider": {
                "type": "string"
              },
              "role": {
                "$ref": "#/definitions/AssistantRoleTag"
              },
              "stop_reason": {
                "$ref": "#/definitions/StopReason"
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              },
              "usage": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Usage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "warnings": {
                "items": {
                  "type": "string"
                },
                "type": [
                  "array",
                  "null"
                ]
              }
            },
            "required": [
              "content",
              "model",
              "provider",
              "role",
              "stop_reason",
              "timestamp"
            ],
            "type": "object"
          },
          "AssistantRoleTag": {
            "enum": [
              "assistant"
            ],
            "type": "string"
          },
          "ChannelDirection": {
            "enum": [
              "read",
              "write"
            ],
            "type": "string"
          },
          "ContentBlock": {
            "description": "Content blocks — the atomic units of message content (README § Content blocks).",
            "oneOf": [
              {
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "text"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "text",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "attachment_id": {
                    "description": "Optional link to the stored original in the session-manager attachment store. Transcript bookkeeping for lazy readers only: the harness clears it before `router::chat`, and no provider mapping reads it. Tolerated here so a block that still carries it deserializes instead of failing the request; omitted on the wire when absent.",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "data": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "image"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "data",
                  "mime",
                  "type"
                ],
                "type": "object"
              },
              {
                "description": "Reference to an original upload in the session-manager attachment store. A REFERENCE ONLY (never inline bytes); the harness strips it before `router::chat`. Tolerated here so a stray block deserializes instead of failing the request; every counter/mapping emits nothing for it.",
                "properties": {
                  "attachment_id": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "size": {
                    "format": "uint64",
                    "minimum": 0,
                    "type": "integer"
                  },
                  "type": {
                    "enum": [
                      "file"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "attachment_id",
                  "mime",
                  "name",
                  "size",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "signature": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "text": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "thinking"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "text",
                  "type"
                ],
                "type": "object"
              },
              {
                "description": "Opaque redacted thinking payload — replayed verbatim on the Anthropic wire.",
                "properties": {
                  "data": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "redacted_thinking"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "data",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "arguments": true,
                  "function_id": {
                    "type": "string"
                  },
                  "id": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "function_call"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "arguments",
                  "function_id",
                  "id",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "content": {
                    "items": {
                      "$ref": "#/definitions/ContentBlock"
                    },
                    "type": "array"
                  },
                  "function_call_id": {
                    "type": "string"
                  },
                  "is_error": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "type": {
                    "enum": [
                      "function_result"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "content",
                  "function_call_id",
                  "type"
                ],
                "type": "object"
              }
            ]
          },
          "CustomMessage": {
            "properties": {
              "content": {
                "items": {
                  "$ref": "#/definitions/ContentBlock"
                },
                "type": "array"
              },
              "custom_type": {
                "type": "string"
              },
              "details": true,
              "display": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "role": {
                "$ref": "#/definitions/CustomRoleTag"
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "content",
              "custom_type",
              "role",
              "timestamp"
            ],
            "type": "object"
          },
          "CustomRoleTag": {
            "enum": [
              "custom"
            ],
            "type": "string"
          },
          "ErrorKind": {
            "enum": [
              "auth_expired",
              "rate_limited",
              "context_overflow",
              "transient",
              "permanent"
            ],
            "type": "string"
          },
          "FunctionResultMessage": {
            "properties": {
              "content": {
                "items": {
                  "$ref": "#/definitions/ContentBlock"
                },
                "type": "array"
              },
              "details": true,
              "function_call_id": {
                "type": "string"
              },
              "function_id": {
                "type": "string"
              },
              "is_error": {
                "type": "boolean"
              },
              "role": {
                "$ref": "#/definitions/FunctionResultRoleTag"
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "content",
              "details",
              "function_call_id",
              "function_id",
              "is_error",
              "role",
              "timestamp"
            ],
            "type": "object"
          },
          "FunctionResultRoleTag": {
            "enum": [
              "function_result"
            ],
            "type": "string"
          },
          "Model": {
            "description": "The capability record (README § Model descriptor).",
            "properties": {
              "context_window": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "display_name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "id": {
                "type": "string"
              },
              "input_limit": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "max_output_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "pricing": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Pricing"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "provider": {
                "type": "string"
              },
              "reasoning_efforts": {
                "items": {
                  "$ref": "#/definitions/ReasoningEffort"
                },
                "type": [
                  "array",
                  "null"
                ]
              },
              "speech": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/SpeechModel"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Set on speech models only; see [`SpeechModel`]."
              },
              "supports_cache": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "supports_structured_output": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "supports_thinking": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "supports_thinking_off": {
                "description": "Whether `thinking_level: off` can switch the model's reasoning off. `Some(true)`: a native off switch exists. `Some(false)`: the model always reasons, or the provider has no switch. `None`: the provider does not know; consoles show the choice disabled.",
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "supports_tools": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "supports_vision": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "supports_xhigh": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "thinking_budgets": {
                "additionalProperties": {
                  "format": "uint64",
                  "minimum": 0,
                  "type": "integer"
                },
                "type": [
                  "object",
                  "null"
                ]
              }
            },
            "required": [
              "context_window",
              "id",
              "max_output_tokens",
              "provider"
            ],
            "type": "object"
          },
          "Pricing": {
            "properties": {
              "cache_read": {
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "cache_write": {
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "input": {
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "output": {
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              }
            },
            "type": "object"
          },
          "PromptCacheIntent": {
            "description": "Why a request's stable prefix is shareable across sessions: `surface_digest` is the caller's content identity for the text before the boundary (`sha256:<hex>`). A routing/accounting hint only — never a provider cache handle, and never evidence of a cache hit.",
            "properties": {
              "surface_digest": {
                "type": "string"
              }
            },
            "required": [
              "surface_digest"
            ],
            "type": "object"
          },
          "PromptSection": {
            "description": "One ordered system-prompt section. `cache_boundary` marks the end of a cumulative prefix worth its own provider cache entry (the frozen agent-profile surface). Adapters without a boundary concept read the sections joined with \"\\n\\n\", which must equal `system_prompt` when both forms are sent.",
            "properties": {
              "cache_boundary": {
                "default": false,
                "type": "boolean"
              },
              "text": {
                "type": "string"
              }
            },
            "required": [
              "text"
            ],
            "type": "object"
          },
          "ReasoningEffort": {
            "description": "One provider-native reasoning effort advertised for a specific model.\n\nValues intentionally remain strings: provider catalogs can add efforts without requiring a router-wide enum release first.",
            "properties": {
              "description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "effort": {
                "type": "string"
              }
            },
            "required": [
              "effort"
            ],
            "type": "object"
          },
          "ResponseFormat": {
            "properties": {
              "schema": true,
              "type": {
                "type": "string"
              }
            },
            "required": [
              "type"
            ],
            "type": "object"
          },
          "SpeechModality": {
            "description": "What a speech model does. Chat models carry no `speech` block.",
            "oneOf": [
              {
                "description": "Speech to text, served through `router::transcribe`.",
                "enum": [
                  "stt"
                ],
                "type": "string"
              },
              {
                "description": "Text to speech, served through `router::speak`.",
                "enum": [
                  "tts"
                ],
                "type": "string"
              }
            ]
          },
          "SpeechModel": {
            "description": "Facts about a speech model. Present only on models served through `router::transcribe` / `router::speak`; such models report `context_window` and `max_output_tokens` as 0.",
            "properties": {
              "languages": {
                "description": "BCP-47 tags of the languages the model handles; empty when the provider does not say.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "modality": {
                "$ref": "#/definitions/SpeechModality"
              },
              "streaming": {
                "default": false,
                "description": "Realtime input (stt) or streamed audio output (tts) is available.",
                "type": "boolean"
              }
            },
            "required": [
              "modality"
            ],
            "type": "object"
          },
          "StopReason": {
            "enum": [
              "end",
              "length",
              "function_call",
              "aborted",
              "error"
            ],
            "type": "string"
          },
          "StreamChannelRef": {
            "properties": {
              "access_key": {
                "type": "string"
              },
              "channel_id": {
                "type": "string"
              },
              "direction": {
                "$ref": "#/definitions/ChannelDirection"
              }
            },
            "required": [
              "access_key",
              "channel_id",
              "direction"
            ],
            "type": "object"
          },
          "ThinkingLevel": {
            "description": "\"off\" asks the provider not to reason at all and is honoured only where the model advertises `Model::supports_thinking_off` (elsewhere the provider falls back to its own lowest setting, or omits the parameter, and warns). \"minimal\" requests the lowest reasoning effort and needs only `thinking` support; levels map to provider-native knobs via `Model::thinking_budgets`.",
            "enum": [
              "off",
              "minimal",
              "low",
              "medium",
              "high",
              "xhigh"
            ],
            "type": "string"
          },
          "Usage": {
            "properties": {
              "cache_read": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cache_write": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cost_usd": {
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "input": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "output": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "reasoning": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "type": "object"
          },
          "UserMessage": {
            "properties": {
              "content": {
                "items": {
                  "$ref": "#/definitions/ContentBlock"
                },
                "type": "array"
              },
              "role": {
                "$ref": "#/definitions/UserRoleTag"
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "content",
              "role",
              "timestamp"
            ],
            "type": "object"
          },
          "UserRoleTag": {
            "description": "Single-variant role tags: exact-match on deserialize, correct wire string on serialize, and they let `AgentMessage` be an untagged union.",
            "enum": [
              "user"
            ],
            "type": "string"
          }
        },
        "description": "Input of a provider worker's `provider::<id>::stream` iii function — what the router forwards per attempt. (No `PartialEq`: `iii_sdk::StreamChannelRef` doesn't implement it.)",
        "properties": {
          "cache_intent": {
            "anyOf": [
              {
                "$ref": "#/definitions/PromptCacheIntent"
              },
              {
                "type": "null"
              }
            ]
          },
          "max_output_tokens": {
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "messages": {
            "items": {
              "$ref": "#/definitions/AgentMessage"
            },
            "type": "array"
          },
          "model": {
            "type": "string"
          },
          "model_meta": {
            "anyOf": [
              {
                "$ref": "#/definitions/Model"
              },
              {
                "type": "null"
              }
            ]
          },
          "provider_options": true,
          "resolution_key": {
            "type": [
              "string",
              "null"
            ]
          },
          "response_format": {
            "anyOf": [
              {
                "$ref": "#/definitions/ResponseFormat"
              },
              {
                "type": "null"
              }
            ]
          },
          "session_id": {
            "description": "Stable conversation identity for provider cache affinity.",
            "type": [
              "string",
              "null"
            ]
          },
          "system_prompt": {
            "type": [
              "string",
              "null"
            ]
          },
          "system_sections": {
            "description": "Ordered sections behind `system_prompt` (always forwarded alongside the flat string, which equals the sections joined with \"\\n\\n\").",
            "items": {
              "$ref": "#/definitions/PromptSection"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "thinking_level": {
            "anyOf": [
              {
                "$ref": "#/definitions/ThinkingLevel"
              },
              {
                "type": "null"
              }
            ]
          },
          "tools": {
            "items": {
              "$ref": "#/definitions/AgentFunction"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "writer_ref": {
            "$ref": "#/definitions/StreamChannelRef"
          }
        },
        "required": [
          "messages",
          "model",
          "writer_ref"
        ],
        "title": "ProviderStreamInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Output of a provider's `provider::<id>::stream` (spec § stream contract): the function streams frames to `writer_ref` and returns this ack.",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "ProviderStreamOutput",
        "type": "object"
      }
    }
  ],
  "triggers": []
}
```
