diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index f4d7e814f..000000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-# These are supported funding model platforms
-
-github: [headroom-sdk]
-# patreon: headroom
-# open_collective: headroom
-# ko_fi: headroom
-# custom: ["https://headroomlabs.ai/sponsor"]
diff --git a/.gitignore b/.gitignore
index 34fe52207..52f01de44 100644
--- a/.gitignore
+++ b/.gitignore
@@ -118,6 +118,9 @@ env.bak/
venv.bak/
.python-version
+# Node.js dependencies (never commit vendored deps)
+node_modules/
+
# Secrets and API keys - NEVER commit these
*.pem
*.key
@@ -229,10 +232,7 @@ CLAUDE.md
# Vitals provenance data
.vitals/
-# Superpowers working files (plans, specs, brainstorming)
-# docs/spec/ (lives in git - git-versioned living specification)
-
-# Managed platform (separate private repo)
+# Separate private repos — never commit here
headroom-managed/
# Local act testing (never commit test tokens)
diff --git a/ENTERPRISE.md b/ENTERPRISE.md
deleted file mode 100644
index 9fb04b27d..000000000
--- a/ENTERPRISE.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Enterprise
-
-## Enterprise Support
-
-Interested in using Headroom at scale? We're happy to discuss your deployment requirements! Email us at: **hello@headroomlabs.ai**
\ No newline at end of file
diff --git a/PR.md b/PR.md
deleted file mode 100644
index 3a311c869..000000000
--- a/PR.md
+++ /dev/null
@@ -1,170 +0,0 @@
-## Description
-
-Implement unified CI/CD release automation with semantic versioning across all three packages:
-- **Python (headroom-ai)** — pip package on PyPI
-- **TypeScript SDK (headroom-ai)** — npm package on npmjs.org
-- **OpenClaw plugin (headroom-openclaw)** — npm package on npmjs.org and GitHub Package Registry
-
-Currently the three packages are independently versioned (0.5.25 / 0.1.0 / 0.1.0). This PR introduces a single-source-of-truth version in `pyproject.toml` that propagates to all packages on every release, driven by conventional commit messages.
-
-Fixes #(issue number)
-
-## Type of Change
-
-- [ ] Bug fix (non-breaking change that fixes an issue)
-- [x] New feature (non-breaking change that adds functionality)
-- [ ] Breaking change (fix or feature that would cause existing functionality to change)
-- [x] Documentation update
-- [ ] Performance improvement
-- [x] Code refactoring (no functional changes)
-
-## Changes Made
-
-### New Files
-
-**Scripts:**
-- `scripts/version-sync.py` — Reads version from `pyproject.toml`, updates all 4 version files. Supports `--version X.Y.Z` and `--bump {major,minor,patch}`.
-- `scripts/changelog-gen.py` — Parses conventional commits since last tag, groups by type, generates markdown changelog with breaking change detection.
-- `scripts/verify-versions.py` — Pre-release sanity check that all 4 version files are in sync.
-- `scripts/tests/test_version_sync.py` — 5 tests for version-sync.py
-- `scripts/tests/test_changelog_gen.py` — 23 tests for changelog-gen.py
-
-**Workflows:**
-- `.github/workflows/release.yml` — Unified release pipeline: detect → build → publish-pypi → publish-npm → publish-github-packages → create-release
-- `.commitlintrc.json` — Conventional commit enforcement via `@commitlint/config-conventional`
-
-**Local Testing (act):**
-- `.actrc` — Default `act` flags (Ubuntu runner, reuse, quiet)
-- `.github/act/dry-run.json` — `act` event file for dry-run testing
-- `.github/act/push-feat.json` — `act` event file for simulating a feat commit
-- `.actrc.local.example` — Local override template for `act`
-- `.env.act.example` — Secrets documentation template for `act` local testing
-
-**Documentation:**
-- `docs/content/docs/releases.mdx` — Full documentation for the release pipeline, testing guide, and configuration reference
-
-### Modified Files
-
-- `.github/workflows/ci.yml` — Added `commitlint` job to enforce conventional commits
-- `.github/workflows/publish.yml` — Changed from `release` trigger to `workflow_dispatch` only (superseded by `release.yml`)
-- `.github/workflows/release.yml` — **Rewritten** with canonical+commit-height algorithm (no more commit loop)
-- `.gitignore` — Added `!scripts/version-sync.py`, `!scripts/changelog-gen.py`, `!scripts/verify-versions.py`, `!scripts/tests/`, `.env.act`, `.actrc.local`
-
-## Testing
-
-- [x] Unit tests pass (`pytest`)
- - `scripts/tests/test_version_sync.py` — 5/5 passing
- - `scripts/tests/test_changelog_gen.py` — 23/23 passing
-- [x] Linting passes (`ruff check .`)
-- [ ] Type checking passes (`mypy headroom`) — pre-existing issue in `headroom/cli/wrap.py:487` (unrelated)
-- [x] New tests added for new functionality
-- [x] Workflow tested with `act` (dry-run passes all jobs through build step — no infinite loop)
-
-## Algorithm Validation
-
-The canonical+commit-height algorithm was validated with test cases:
-- Canonical `0.5.25`, no prior tag, `feat:` commit → git tag `v0.6.0.0`, npm `0.6.0` ✅
-- Canonical `0.5.25`, tag `v0.5.25.2`, `fix:` commit → git tag `v0.5.25.3`, npm `0.5.26` ✅
-- Canonical `0.5.25`, no prior tag, `fix:` commit → git tag `v0.5.25.0`, npm `0.5.25` ✅
-- Manual override `1.2.3` → git tag `v1.2.3`, npm `1.2.3` ✅
-
-## Test Output
-
-```
-scripts/tests/test_version_sync.py .....
-scripts/tests/test_changelog_gen.py .......................
-```
-
-## Checklist
-
-- [x] My code follows the project's style guidelines
-- [x] I have performed a self-review of my code
-- [x] I have commented my code, particularly in hard-to-understand areas
-- [x] My changes generate no new warnings
-- [x] I have added tests that prove my fix is effective or that my feature works
-- [x] New and existing unit tests pass locally with my changes
-- [x] I have made corresponding changes to the documentation
-- [ ] I have updated the CHANGELOG.md if applicable
-
-## Additional Notes
-
-### Version Bump Logic
-
-**Canonical + Commit Height Algorithm** — The workflow NEVER commits back to the repo. `pyproject.toml` is the canonical source of truth, updated manually before merging.
-
-| Commit | Bump | Git Tag | npm Version |
-|--------|------|---------|-------------|
-| `fix:`, `ci:`, `chore:`, `perf:`, `refactor:` | patch | `v0.5.25.3` | `0.5.26` |
-| `feat:` | minor | `v0.6.0.0` | `0.6.0` |
-| `feat!:` or `feat:` + `BREAKING CHANGE` body | major | `v1.0.0.0` | `1.0.0` |
-
-The git tag uses `v{canonical}.{height}` (e.g., `v0.5.25.3` = 3 commits since canonical `0.5.25`). npm versions use 3-part semver, bumped from canonical.
-
-### Package Publishing Targets
-
-| Package | Target | Status |
-|---------|--------|--------|
-| `headroom-ai` (Python) | PyPI | ✅ via `pypa/gh-action-pypi-publish` |
-| `headroom-ai` (TypeScript SDK) | npmjs.org | ✅ via `npm publish` |
-| `headroom-openclaw` | npmjs.org | ✅ via `npm publish` |
-| `headroom-openclaw` | GitHub Package Registry | ✅ via `npm publish --registry npm.pkg.github.com` |
-
-### Safety Gates
-
-Each publish job requires both `dry_run != 'true'` **and** the corresponding skip variable not set:
-
-| Variable | Effect |
-|----------|--------|
-| `PYPI_SKIP=true` | Skip PyPI publish |
-| `NPM_SKIP=true` | Skip both npm publishes |
-| `GH_PACKAGES_SKIP=true` | Skip GitHub Package Registry publish |
-
-Set in: **GitHub repo → Settings → Variables → Actions Variables**.
-
-### Workflow Triggers
-
-- **Auto:** On push to `main` — analyzes latest commit, bumps version, builds, publishes, creates GitHub Release
-- **Manual:** `workflow_dispatch` with optional `version` override and `dry_run` flag
-- **Paths ignore:** Skips runs when only `docs/`, `.github/workflows/ci.yml`, `.github/workflows/publish.yml`, `scripts/`, `.commitlintrc.json`, `.actrc`, `.github/act/`, or `.env.act.example` change
-
-### Local Testing
-
-```bash
-# Install act
-winget install act
-
-# Dry-run (no publishes)
-act -W .github/workflows/release.yml -e .github/act/dry-run.json
-
-# Test feat: commit (minor bump)
-act -W .github/workflows/release.yml -e .github/act/push-feat.json
-```
-
-### Required GitHub Secrets
-
-| Secret | Purpose |
-|--------|---------|
-| `NPM_TOKEN` | Publishing to npmjs.org |
-| `GITHUB_TOKEN` | GitHub Package Registry (auto-provided by GitHub Actions) |
-
-PyPI uses trusted publisher OIDC — no secret required, only the `pypi` GitHub Environment must be configured.
-
-### First Release Note
-
-The TypeScript packages are currently at `0.1.0` while Python is at `0.5.25`. The first release will align all three to the same version. Update `pyproject.toml` to the desired canonical version before merging, then use `workflow_dispatch` with a manual `version` input to set the target explicitly.
-
-After each release, update `pyproject.toml` to match the published version to keep the canonical current and ensure unique git tags.
-
-### Parameterized Configuration
-
-All package names and registries are top-level `env` constants in `release.yml`:
-
-```yaml
-env:
- PYPI_PACKAGE: headroom-ai
- PYPI_ENVIRONMENT: pypi
- NPM_REGISTRY_URL: https://registry.npmjs.org
- NPM_SDK_PACKAGE: headroom-ai
- NPM_OPENCLAW_PACKAGE: headroom-openclaw
- GITHUB_PACKAGES_REGISTRY_URL: https://npm.pkg.github.com
-```
diff --git a/README.md b/README.md
index 2fd3ecfe9..066807597 100644
--- a/README.md
+++ b/README.md
@@ -26,8 +26,7 @@
Proof ·
Agents ·
Discord ·
- llms.txt ·
- Enterprise
+ llms.txt
@@ -181,7 +180,7 @@ unshaped as a control group: `export HEADROOM_OUTPUT_HOLDOUT=0.1`. The dashboard
shows an **Output Tokens Saved** card next to input compression, labelled
`measured` or `estimated` with the confidence band.
-→ Full write-up incl. the measurement methodology: [`docs/proposals/output-token-reduction.md`](docs/proposals/output-token-reduction.md)
+→ Full write-up incl. the measurement methodology: [Output token reduction](https://headroom-docs.vercel.app/docs/savings)
diff --git a/RUST_DEV.md b/RUST_DEV.md
index f2abab522..863ea61c1 100644
--- a/RUST_DEV.md
+++ b/RUST_DEV.md
@@ -288,9 +288,8 @@ doesn't rediscover them.
## Multi-worker deployment — CCR fragmentation
-**Status:** PR-B7 (`REALIGNMENT/04-phase-B-live-zone.md`) introduced two
-persistent CCR backends. The single-`--workers` recommendation no longer
-applies once you select a persistent backend.
+**Status:** two persistent CCR backends are available. The single-`--workers`
+recommendation no longer applies once you select a persistent backend.
### Backend selection
diff --git a/docs/auth-modes.md b/docs/auth-modes.md
deleted file mode 100644
index 0fb8a9af8..000000000
--- a/docs/auth-modes.md
+++ /dev/null
@@ -1,132 +0,0 @@
-# Auth Modes
-
-Headroom classifies every inbound request into one of three **auth modes** at request entry. The mode drives every downstream compression, cache, and header policy decision. Detection is a pure function of HTTP headers — no I/O, no allocation beyond a single `to_lowercase` of the User-Agent, runs in <10us per call.
-
-The classifier ships in two equivalent implementations:
-
-- **Rust:** `crates/headroom-core/src/auth_mode.rs` (`classify`)
-- **Python:** `headroom/proxy/auth_mode.py` (`classify_auth_mode`)
-
-Both are byte-for-byte identical on every header set covered by the parity test suite (`crates/headroom-core/tests/auth_mode.rs` + `tests/test_auth_mode.py`).
-
-## The three modes
-
-### `Payg` — pay-as-you-go API key
-
-| Signal | Examples |
-|---|---|
-| `Authorization: Bearer sk-ant-api*` | Anthropic PAYG key |
-| `Authorization: Bearer sk-*` (excluding `sk-ant-oat-`) | OpenAI PAYG key |
-| `x-api-key: ...` | Anthropic API key style |
-| `x-goog-api-key: ...` | Google Gemini key |
-
-**Compression policy:** aggressive. The caller pays per token; compression directly saves them money. Cache hit-rate matters financially (Anthropic 1.25-2× cache write, 0.10× cache read). Live-zone compression, CCR, type-aware compressors all turn on. This is the OSS default.
-
-### `OAuth` — OAuth bearer / IAM-signed
-
-| Signal | Examples |
-|---|---|
-| `Authorization: Bearer sk-ant-oat-*` | Claude Pro / Max OAuth |
-| `Authorization: Bearer ` (3-segment) | Codex / Cursor / Copilot OAuth |
-| `Authorization: AWS4-HMAC-SHA256 ...` | Bedrock SigV4 |
-| Any other non-`Bearer` Authorization scheme | Vertex ADC, custom proxies |
-
-**Compression policy:** passthrough-prefer. Per-token cost is opaque (subscription) or zero from the caller's POV (IAM-bound usage); compression value is **extending effective context within rate-limit / quota windows**, not saving money. Cache safety is paramount because OAuth scopes pin to `(account, model, session)` and beta-header drift can break OAuth-issued scopes. **No auto-`cache_control`, no auto-`prompt_cache_key`, no lossy compressors.** Lossless-only.
-
-### `Subscription` — UX-bound CLI / IDE
-
-| Signal | UA prefix |
-|---|---|
-| Claude Code | `claude-code/` |
-| Claude CLI | `claude-cli/` |
-| Codex CLI | `codex-cli/` |
-| Cursor | `cursor/` |
-| Claude VS Code | `claude-vscode/` |
-| GitHub Copilot | `github-copilot/` |
-| Anthropic CLI | `anthropic-cli/` |
-| Antigravity | `antigravity/` |
-
-**Compression policy:** stealth. Provider rate-limits by request count; programmatic-fingerprint detection means Headroom MUST look like the upstream agent. Same compression policy as `OAuth` **plus**:
-
-- Preserve `accept-encoding` byte-for-byte.
-- Never inject `X-Headroom-*` headers on upstream-bound requests.
-- Never mutate `User-Agent`.
-- Skip `X-Forwarded-*` headers on upstream-bound requests (see Phase F PR-F4).
-
-The Subscription UA wins over any bearer token shape — a Claude Code session that happens to carry a `sk-ant-oat-*` token is still a subscription client, never OAuth.
-
-## Detection signals — full decision order
-
-The classifier evaluates these in order; the **first** matching rule wins.
-
-1. **User-Agent contains a `SUBSCRIPTION_UA_PREFIXES` entry** → `Subscription`.
-2. **`Authorization: Bearer sk-ant-oat-*`** → `OAuth`.
-3. **`Authorization: Bearer sk-ant-api*` or `Bearer sk-*`** → `Payg`.
-4. **`Authorization: Bearer `** (3 dot-separated segments) → `OAuth`.
-5. **`Authorization` present but not `Bearer ...`** (e.g., `AWS4-HMAC-SHA256`) → `OAuth`.
-6. **`x-api-key` present** → `Payg`.
-7. **`x-goog-api-key` present** → `Payg`.
-8. **Default** → `Payg`.
-
-The subscription-UA check is intentionally first because the same OAuth token shape appears in both Claude Pro (web) and Claude Code (CLI), and only the User-Agent disambiguates them.
-
-The "default to PAYG" rule is intentionally conservative: misclassifying a non-PAYG client as PAYG over-compresses, which only costs us a re-run; under-compressing a PAYG client leaves money on the table, which is worse for the OSS-default user.
-
-## How to extend
-
-### Adding a new subscription CLI
-
-Add the UA prefix to **both** files — they must agree:
-
-- `crates/headroom-core/src/auth_mode.rs` → `SUBSCRIPTION_UA_PREFIXES`
-- `headroom/proxy/auth_mode.py` → `SUBSCRIPTION_UA_PREFIXES`
-
-Then add a parametrised parity test case in **both**:
-
-- `crates/headroom-core/tests/auth_mode.rs` → add a `#[test] fn ..._ua_classified_subscription`.
-- `tests/test_auth_mode.py` → covered automatically by the existing `test_every_subscription_prefix_classified_subscription` parametrised test.
-
-### Adding a new OAuth token shape
-
-Add the prefix check **before** the `sk-` PAYG branch in both `classify` and `classify_auth_mode`. Order matters: any token shape that's a strict prefix of `sk-` must be checked first.
-
-### Making the prefix list user-configurable
-
-The list lives in a `const` so a future Phase F follow-up PR can swap it for a configurable source (env var, TOML config, CLI flag) without touching the function body. The recommended path:
-
-1. Read the list from `Config::subscription_ua_prefixes` (Rust) / `headroom.config.Settings.subscription_ua_prefixes` (Python).
-2. Default to the current static list if unset.
-3. Pass the list as a parameter to `classify` / `classify_auth_mode`.
-
-The classifier itself is a pure function — adding a parameter is a localized change.
-
-## Performance
-
-| Path | Per-call latency (p50) |
-|---|---|
-| Rust empty headers | ~20 ns |
-| Rust PAYG (Bearer prefix match) | ~50 ns |
-| Rust Subscription (UA lowercase + scan) | ~600 ns |
-| Python empty headers | ~3 us |
-| Python Subscription | ~12 us |
-
-All paths are well under the <10us Rust budget and the <100us Python budget asserted by the test suite.
-
-## Where the auth-mode value flows
-
-After classification, the value is stored on the request object so downstream code reads it without re-classifying:
-
-- **Rust:** `req.extensions_mut().insert(auth_mode)`. Read with `req.extensions().get::()`.
-- **Python:** `request.state.auth_mode`. Read with `request.state.auth_mode`.
-
-A structured log line (`event = auth_mode_classified`) fires once per request at request entry; the value is logged as `auth_mode = "payg" | "oauth" | "subscription"`.
-
-## Phase F roadmap
-
-PR-F1 (this PR) lands the helper. The rest of Phase F wires it into specific policy gates:
-
-- **PR-F2:** per-mode compression policy gates (auto-`cache_control`, `prompt_cache_key`, lossy compressors).
-- **PR-F3:** TOIN per-tenant aggregation key includes `(auth_mode, model_family, structure_hash)`.
-- **PR-F4:** `X-Forwarded-*` skipped on Subscription mode.
-
-See `REALIGNMENT/08-phase-F-auth-mode.md` for the full phase plan.
diff --git a/docs/bedrock.md b/docs/bedrock.md
deleted file mode 100644
index c3a51bc45..000000000
--- a/docs/bedrock.md
+++ /dev/null
@@ -1,218 +0,0 @@
-# AWS Bedrock — Operator Guide
-
-Headroom's Rust proxy ships a native AWS Bedrock InvokeModel surface. After Phase D (PRs D1–D3), Anthropic-on-Bedrock requests are signed, compressed, and observed by the proxy directly — no LiteLLM Python shim on the request path.
-
-This document covers how to deploy the Bedrock-native surface, how compression policy is applied, and how to read the Prometheus metrics the proxy exports.
-
-## What's in scope
-
-| Capability | Status |
-|---|---|
-| `POST /model/{model}/invoke` | PR-D1 — native Rust handler |
-| `POST /model/{model}/converse` | PR-D1 — same handler (Bedrock accepts both paths for the Anthropic envelope) |
-| `POST /model/{model}/invoke-with-response-stream` | PR-D2 — binary EventStream parsed and translated to SSE |
-| AWS SigV4 signing (post-compression) | PR-D1 |
-| `AuthMode::OAuth` classification | PR-D3 — Bedrock IAM is OAuth-equivalent under the policy matrix |
-| Per-model + per-region Prometheus metrics | PR-D3 — exposed at `GET /metrics` |
-| OAuth compression policy gates (no auto cache_control, lossless-only) | Phase F PR-F2/F3 (gates the marker D3 wires) |
-
-## Running the proxy
-
-The native surface lives in the `headroom-proxy` binary, which ships in the published
-container images (every `proxy`-extra tag) at `/usr/local/bin/headroom-proxy`. You can run
-it directly from any published image — no separate build:
-
-```sh
-docker run --rm -p 8787:8787 \
- -v "$HOME/.aws:/home/nonroot/.aws:ro" \
- -e HEADROOM_PROXY_AWS_PROFILE=my-profile \
- --entrypoint headroom-proxy \
- ghcr.io/chopratejas/headroom:latest \
- --listen 0.0.0.0:8787 \
- --upstream https://bedrock-runtime.us-east-1.amazonaws.com \
- --bedrock-region us-east-1
-```
-
-The published images default to the `nonroot` user (home `/home/nonroot`), so AWS
-credentials are mounted at `/home/nonroot/.aws` — that is where the SDK looks for
-`~/.aws`. For a root-based image (`RUNTIME_USER=root` build), mount to `/root/.aws`
-instead, or pass `--user root`.
-
-Then point the AWS SDK / CLI at the proxy:
-
-```sh
-AWS_ENDPOINT_URL_BEDROCK_RUNTIME=http://localhost:8787 \
- aws bedrock-runtime invoke-model --model-id anthropic.claude-3-haiku-20240307-v1:0 ...
-```
-
-The proxy can also drop in front of the Python proxy (`--upstream http://127.0.0.1:8788`)
-so non-Bedrock traffic is forwarded while Bedrock requests are signed + compressed
-natively. The default `--enable-bedrock-native=true` mounts the Bedrock routes; everything
-else is passed through to `--upstream`.
-
-## AWS credential configuration
-
-The proxy uses the [aws-config default credential chain](https://docs.aws.amazon.com/sdkref/latest/guide/standardized-credentials.html), resolved once at startup.
-
-The chain searches in this order, stopping at the first source that yields valid credentials:
-
-1. **Environment variables** — `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, optional `AWS_SESSION_TOKEN`. Useful for ECS task roles that inject creds via env or for `aws sts assume-role` shells.
-2. **Shared credentials file** — `~/.aws/credentials`. Profile selected by `--aws-profile` (or `AWS_PROFILE`). Falls back to `[default]`.
-3. **IAM instance profile / IMDS** — when running on EC2.
-4. **ECS task role / EKS pod identity** — when running on the AWS-managed compute platforms.
-5. **AWS SSO** — `~/.aws/sso/cache/...` when `aws sso login` has been run.
-
-If the chain does NOT resolve any credentials at startup, the proxy logs `event=bedrock_credentials_unavailable` at WARN and continues to start. Bedrock invoke routes will then return `500` with `event=bedrock_credentials_missing` per request — there is **no silent fallback to unsigned requests**, by design.
-
-### Required IAM permissions
-
-The proxy needs:
-
-- `bedrock:InvokeModel` for non-streaming
-- `bedrock:InvokeModelWithResponseStream` for streaming
-
-Scope these to the specific model ARNs you intend to use. Example IAM policy snippet:
-
-```json
-{
- "Version": "2012-10-17",
- "Statement": [
- {
- "Effect": "Allow",
- "Action": [
- "bedrock:InvokeModel",
- "bedrock:InvokeModelWithResponseStream"
- ],
- "Resource": [
- "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-haiku-20240307-v1:0",
- "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0"
- ]
- }
- ]
-}
-```
-
-## Region configuration
-
-```sh
-headroom-proxy \
- --upstream http://unused-when-bedrock-only \
- --bedrock-region us-east-1
-```
-
-| Flag | Env var | Default | Notes |
-|---|---|---|---|
-| `--bedrock-region` | `HEADROOM_PROXY_BEDROCK_REGION` (or `AWS_REGION`) | `us-east-1` | Drives both the SigV4 region and the derived endpoint hostname. |
-| `--bedrock-endpoint` | `HEADROOM_PROXY_BEDROCK_ENDPOINT` | derived from region | Override for FIPS endpoints (`bedrock-runtime-fips.{region}.amazonaws.com`), VPC endpoints, or local mock servers. |
-| `--aws-profile` | `HEADROOM_PROXY_AWS_PROFILE` | unset | Selects the named profile from the shared credentials file. |
-| `--enable-bedrock-native` | `HEADROOM_PROXY_ENABLE_BEDROCK_NATIVE` | `true` | Set to `false` to mount no Bedrock routes at all (Bedrock requests will then fall through to the catch-all and fail without SigV4). |
-
-## Supported model IDs
-
-The proxy classifies model IDs by **literal vendor match** — no regexes. It strips a known cross-region inference-profile geo prefix (`eu.`, `us.`, `apac.`, `global.`) if present, then takes the leading dot-segment as the vendor. A model is treated as Anthropic-shape when that canonical vendor is `anthropic` — so both the bare `anthropic.…` foundation models and the geo-prefixed inference profiles (`eu.anthropic.…`, `us.anthropic.…`, `apac.anthropic.…`, `global.anthropic.…`) qualify. For those, the live-zone compression dispatcher runs over the body, the envelope is re-emitted with `anthropic_version` preserved as the first key, and the request is signed with SigV4.
-
-Examples that hit the Anthropic compression path:
-
-- `anthropic.claude-3-haiku-20240307-v1:0` (foundation model)
-- `anthropic.claude-3-5-sonnet-20241022-v2:0`
-- `eu.anthropic.claude-haiku-4-5-20251001-v1:0` (EU cross-region inference profile)
-- `us.anthropic.claude-3-5-sonnet-20241022-v2:0` (US inference profile)
-- `global.anthropic.claude-haiku-4-5-20251001-v1:0`
-
-Other Bedrock vendors (`amazon.titan-...`, `meta.llama3-...`, `cohere.command-...`, `ai21.j2-...`, `stability.stable-diffusion-...`, and their geo-prefixed inference profiles such as `eu.amazon.nova-...`) are signed and forwarded **without compression** — the proxy does not yet understand their body shapes and would risk corrupting them. These model IDs log `event=bedrock_compression_skipped, reason=non_anthropic_vendor` per request. Full Anthropic envelopes only.
-
-The contract: **any new model ID that AWS adds under the `anthropic.` vendor (as a bare prefix or behind a cross-region geo prefix) automatically picks up the full compression + signing pipeline.** No code change in the proxy is needed for new versions of Claude on Bedrock.
-
-## Compression behaviour
-
-Bedrock requests are subject to the **same** live-zone compression rules as direct Anthropic (`/v1/messages`):
-
-- Only the live-zone messages (latest user turn, latest tool/output blocks) are eligible for compression.
-- The cache hot zone (older messages, system prompt, tools list) is byte-faithful passthrough.
-- The dispatcher only mutates body bytes when at least one block compressed. The byte-equality invariant for unchanged blocks is enforced at `debug_assert!` granularity.
-
-### OAuth policy (PR-D3 → PR-F2/F3)
-
-The Bedrock auth-mode middleware classifies every Bedrock request as `AuthMode::OAuth`. Even when the inbound request has no Authorization header (the common case where the AWS SDK signs after our proxy), the middleware **coerces** to OAuth and emits `event=bedrock_auth_mode_unexpected` at WARN if F1's classifier disagreed — so the divergence is loud, not silent.
-
-Under the OAuth policy matrix (see `docs/auth-modes.md`):
-
-- **No auto-`cache_control` injection.** OAuth subscriptions pin the cache scope to `(account, model, session)`; auto-injecting markers can void cache hits.
-- **No auto-`prompt_cache_key`.** Same reasoning.
-- **Lossless-only compressors.** Lossy compressors (text rewriting, summarisation) are gated off for OAuth.
-
-PR-D3 lands the classification + the resulting `AuthMode` in `request.extensions()`. PR-F2 and PR-F3 wire the actual policy gates that read it. Until those PRs land, the Bedrock route uses the existing dispatcher (which is a no-op in `compression_mode=off`); the OAuth contract above is the documented forward direction.
-
-### Cache safety
-
-The bytes signed by SigV4 are exactly the bytes Bedrock receives — the signer hashes the post-compression body. There is no "sign before compress" shortcut that would produce a signature mismatched to the wire payload. Compression mutates the body once, then the signer runs once, then the bytes are forwarded once.
-
-## Prometheus metrics
-
-The proxy exposes a `GET /metrics` endpoint that serves the standard Prometheus text-format scrape. Three Bedrock-specific metric families are exported:
-
-| Metric | Type | Labels | Source |
-|---|---|---|---|
-| `bedrock_invoke_count_total` | Counter | `model`, `region`, `auth_mode` | One increment per `/model/.../invoke` (and `/converse` and `/invoke-with-response-stream`) request. |
-| `bedrock_invoke_latency_seconds` | Histogram | `model`, `region` | Observed at request completion (success or failure). |
-| `bedrock_eventstream_message_count_total` | Counter | `model`, `region`, `event_type` | One increment per parsed binary EventStream message in the streaming path. `event_type` is the `:event-type` header (`chunk`, `metadata`, `internalServerException`, etc.). |
-
-All labels are bounded by infrastructure config (`region` from `--bedrock-region`, `auth_mode` from the 3-variant enum) or by the path parameter (`model`, supplied by the axum extractor — never by user-controlled body bytes). Cardinality is bounded by deployment fan-out, not by traffic volume.
-
-### Sample PromQL queries
-
-**p99 latency by model:**
-```promql
-histogram_quantile(
- 0.99,
- sum by (model, le) (rate(bedrock_invoke_latency_seconds_bucket[5m]))
-)
-```
-
-**Request rate by region (RPS):**
-```promql
-sum by (region) (rate(bedrock_invoke_count_total[1m]))
-```
-
-**EventStream message rate by event type (debugging the streaming path):**
-```promql
-sum by (event_type) (rate(bedrock_eventstream_message_count_total[1m]))
-```
-
-**Error breakdown by HTTP status (cross-references the structured logs `event=bedrock_upstream_error`):**
-```promql
-sum by (model) (rate(bedrock_invoke_count_total{auth_mode="oauth"}[5m]))
- / sum by (model) (rate(bedrock_invoke_latency_seconds_count[5m]))
-```
-
-(The denominator is the total observed latency samples — useful for sanity-checking that every counted invoke also got a histogram observation. They should be equal.)
-
-### Structured-log correlation
-
-Every metric increment in the Bedrock path is paired with a `tracing::debug!` log line carrying:
-
-- `event = "metric_recorded"`
-- `metric = "bedrock_invoke_count_total" | "bedrock_invoke_latency_seconds" | "bedrock_eventstream_message_count_total"`
-- the same labels as the metric
-
-Enable with `RUST_LOG=headroom_proxy::observability=debug` for incident correlation. In normal operation keep this at the default `info` level — debug volume per request is bounded by the same cardinality the metric uses.
-
-## Live cloud validation
-
-The PR-D1, D2, D3 implementations are exercised end-to-end against a wiremock upstream (`crates/headroom-proxy/tests/integration_bedrock_*.rs`). The wiremock-based tests are the canonical correctness gate.
-
-A real Bedrock smoke test (`aws bedrock-runtime invoke-model ...` through the proxy) requires `bedrock:InvokeModel` permissions in the developer's AWS account. Set the proxy upstream to the proxy URL (`http://localhost:8787`) via the AWS SDK's `AWS_ENDPOINT_URL_BEDROCK_RUNTIME` env var:
-
-```sh
-AWS_ENDPOINT_URL_BEDROCK_RUNTIME=http://localhost:8787 \
- aws bedrock-runtime invoke-model \
- --model-id anthropic.claude-3-haiku-20240307-v1:0 \
- --body '{"anthropic_version":"bedrock-2023-05-31","max_tokens":32,"messages":[{"role":"user","content":"hi"}]}' \
- /tmp/out.json
-```
-
-If the SDK signs the request before sending to the proxy, the proxy will see a SigV4 `Authorization` header and classify as OAuth via the standard rule. If the SDK is configured to sign downstream of the proxy (some IAM-instance-profile setups), the proxy still classifies as OAuth via the middleware's coerce-and-log fallback.
-
-## Rollback
-
-Set `--enable-bedrock-native=false` to unmount all Bedrock routes; the catch-all proxy then forwards Bedrock requests unchanged to `--upstream`. This is an emergency rollback only — without SigV4 re-signing, the catch-all path will fail closed unless the upstream is itself a Bedrock-aware proxy (e.g., the Python LiteLLM converter on a different port).
diff --git a/docs/claude-code-vertex-headroom.md b/docs/claude-code-vertex-headroom.md
deleted file mode 100644
index c8b0b655e..000000000
--- a/docs/claude-code-vertex-headroom.md
+++ /dev/null
@@ -1,163 +0,0 @@
-# Claude Code + Google Vertex AI, with Headroom compression
-
-*Validated end-to-end on 2026-06-19 (Claude Code 2.1.181, Headroom 0.27.0).*
-
-This is the **working, tested** way to run **Claude Code** against **Claude models on
-Google Vertex AI** with **Headroom compressing the context** in the middle.
-
-## TL;DR
-
-Run Claude Code in **normal Anthropic mode** (NOT Vertex mode) pointed at a local
-Headroom proxy, and let **Headroom** be the thing that talks to Vertex:
-
-```
-Claude Code ──ANTHROPIC_BASE_URL──▶ Headroom proxy ──LiteLLM (vertex_ai)──▶ Vertex AI
- (normal mode) (plain http) (compresses) (your GCP ADC) (Claude)
-```
-
-Two non-obvious requirements make the difference between "works" and "silently does nothing":
-
-1. **`pip install "google-cloud-aiplatform>=1.38"`** into the proxy's environment —
- LiteLLM's `vertex_ai` provider needs it, or every request 500s with
- `No module named 'vertexai'`.
-2. **Start the proxy with `--code-aware`** — coding sessions are mostly *source code*,
- which routes to the AST/code-aware compressor. It is **disabled by default**, so
- without this flag compression no-ops on code and you see `tokens_saved: 0`.
-
-## Why not "just point Claude Code's Vertex URL at Headroom"?
-
-That approach (Vertex mode + `ANTHROPIC_VERTEX_BASE_URL`=proxy) **does not work** with
-Claude Code today. In Vertex mode Claude Code runs a **client-side `probeVertexModel`
-check before any request**. When `ANTHROPIC_VERTEX_BASE_URL` points at a non-Google
-host, that probe fails *instantly* (no network call is made) with a misleading
-`"The model … is not available on your vertex deployment"`, and the proxy never
-receives a byte. This is a Claude Code limitation, not a Headroom bug. The native
-`:rawPredict` passthrough in Headroom is correct and compresses (verified by direct
-curl) — but the client won't route to it. So we use the Anthropic-mode path below.
-
-## Prerequisites
-
-- **Google Cloud auth (ADC).** Run once: `gcloud auth application-default login`
- (and `gcloud config set project `). The proxy uses ADC to call Vertex; no
- API key is held by Headroom. A service-account JSON via
- `GOOGLE_APPLICATION_CREDENTIALS` works too.
-- **Vertex Claude quota** for the model + location you intend to use. Confirm with a
- direct call before involving Headroom:
- ```bash
- ACCESS_TOKEN="$(gcloud auth application-default print-access-token)"
- curl -sS -X POST \
- -H "Authorization: Bearer ${ACCESS_TOKEN}" -H "Content-Type: application/json" \
- "https://aiplatform.googleapis.com/v1/projects//locations/global/publishers/anthropic/models/claude-sonnet-4-6:rawPredict" \
- -d '{"anthropic_version":"vertex-2023-10-16","max_tokens":20,"messages":[{"role":"user","content":"hi"}]}'
- ```
- HTTP 200 → good. 429 → model exists but no quota in that location. 404 → model not
- enabled in that project/location.
-- **Headroom ML extra** for compression: `pip install "google-cloud-aiplatform>=1.38"`
- plus the Kompress ML stack (`torch`, `transformers`, `onnxruntime` — the
- `headroom-ai[ml]` extra). The `kompress-v2-base` model downloads from Hugging Face
- on first use.
-
-## Terminal 1 — start the Headroom proxy (Vertex backend)
-
-```bash
-cd /path/to/headroom
-source .venv/bin/activate
-
-export VERTEXAI_PROJECT=
-export GOOGLE_CLOUD_PROJECT=
-export VERTEXAI_LOCATION=global # match where your quota lives
-
-headroom proxy --port 8787 \
- --backend litellm-vertex_ai \ # NOTE: the _ai suffix is required
- --region global \ # becomes LiteLLM vertex_location
- --code-aware # REQUIRED for code compression
-```
-
-On startup, confirm components loaded: `curl -s localhost:8787/debug/warmup` should
-show `kompress: loaded`, `code_aware: loaded`, `tree_sitter: loaded`,
-`smart_crusher: loaded`.
-
-## Terminal 2 — run Claude Code (normal Anthropic mode) against the proxy
-
-```bash
-cd /path/to/your/project
-
-export ANTHROPIC_BASE_URL=http://127.0.0.1:8787
-export ANTHROPIC_API_KEY=sk-placeholder-not-used # Claude Code needs *a* key to start
-export ANTHROPIC_MODEL=claude-sonnet-4-6 # sent to Headroom, mapped to vertex_ai/claude-sonnet-4-6
-export ANTHROPIC_SMALL_FAST_MODEL=claude-sonnet-4-6 # pin background model to one you have quota for
-
-# Do NOT set CLAUDE_CODE_USE_VERTEX or ANTHROPIC_VERTEX_BASE_URL — those put Claude
-# Code into Vertex mode and trigger the broken probe described above.
-
-claude
-```
-
-Claude Code now talks plain Anthropic `/v1/messages` to Headroom; Headroom compresses
-and forwards to Vertex via LiteLLM, then translates the answer back.
-
-## Verify compression is happening
-
-- Dashboard: — "tokens saved" climbs as you work.
-- `curl -s localhost:8787/stats` → `tokens.saved`, and `request_logs[].transforms_applied`
- (look for `router:tool_result:mixed`, `kompress:*`, `code_aware:*`).
-- Savings appear on **large tool outputs** (Bash/Grep/web fetches) and accumulate over
- turns. Note: **`Read`/`Glob`/`Grep`/`Write`/`Edit` outputs are protected from the
- ContentRouter by default** (safest for coding agents); stale `Read`s are handled
- separately by the Read-lifecycle system. So the biggest wins come from non-excluded
- large outputs and multi-turn sessions, not single one-shot reads.
-
-## What `--code-aware` does — and what it never touches
-
-**What it does.** Code-Aware is an **AST (tree-sitter) compressor for source code that
-passes through the proxy inside a request**. It parses the code, **keeps the structure
-that matters** — imports, function/class signatures, type annotations, error handlers —
-and **shrinks the less-important function bodies**, always emitting **syntactically
-valid code** (the output still parses). Languages: Python, JS, TS (tier 1); Go, Rust,
-Java, C, C++ (tier 2). The original is **stored for retrieval (CCR, ~5-minute TTL)**, so
-if the model needs the exact bytes it can pull them back via the `headroom_retrieve`
-tool — compression is reversible, not destructive.
-
-**What it does NOT touch:**
-
-- **Your files on disk.** Headroom is a network proxy: it only rewrites the *request
- body* in flight on the way to Vertex. It never reads, writes, or modifies any local
- file. Code-Aware operates on text that is *already inside the API request*, not on
- your repository.
-- **Claude Code's `Read` tool output.** `Read`, `Glob`, `Grep`, `Write`, and `Edit`
- are in `DEFAULT_EXCLUDE_TOOLS` and are **protected from the ContentRouter by default**
- (`protect_recent_reads_fraction = 0.0` ⇒ protect-all). So when Claude Code opens a
- file the normal way, **the model sees it verbatim** — Code-Aware does not alter it.
- (Stale `Read`s — files you later edit — are handled separately and reversibly by the
- Read-lifecycle, replacing the superseded copy with a retrievable marker.)
-
-**Where it actually applies:** code that reaches the model through *other* channels —
-most commonly **`Bash` output that prints code** (`cat file.py`, `sed`, `nl`, build
-logs with snippets) or large code in results from non-excluded/custom tools. That is
-the content that gets AST-compressed. In the validation run, the ~22% savings came
-exactly from two `Bash` commands that dumped source files — not from `Read`.
-
-**Net:** with the default config your real file reads and edits go to the model
-untouched; Code-Aware only trims bulky *incidental* code (shell dumps, logs, pasted
-snippets) and keeps the originals retrievable. Omit `--code-aware` if you want zero
-code transformation at all (you lose code compression but keep everything else).
-
-## Model-string notes (Vertex)
-
-- Headroom maps clean ids to Vertex publisher ids: `claude-sonnet-4-6` →
- `vertex_ai/claude-sonnet-4-6` (see `headroom/backends/litellm.py`). Newer models use
- the bare alias; older ones are date-pinned (e.g. `claude-sonnet-4-5@20250929`).
-- `--region global` works (LiteLLM targets the `aiplatform.googleapis.com` global
- endpoint). Use a specific region (`us-east5`, `europe-west1`, …) only if that's where
- your quota is.
-
-## Troubleshooting
-
-| Symptom | Cause | Fix |
-|---|---|---|
-| `500 … No module named 'vertexai'` | LiteLLM vertex provider dep missing | `pip install "google-cloud-aiplatform>=1.38"`, restart proxy |
-| `tokens_saved: 0` on code | Code-Aware disabled | start proxy with `--code-aware` |
-| `tokens_saved: 0` everywhere, `/debug/warmup` shows `kompress: not installed` | ML extra missing | install `headroom-ai[ml]` (torch/transformers/onnxruntime) |
-| `"model … not available on your vertex deployment"`, proxy logs nothing | Claude Code is in Vertex mode (probe) | unset `CLAUDE_CODE_USE_VERTEX` / `ANTHROPIC_VERTEX_BASE_URL`; use Anthropic mode above |
-| `429 RESOURCE_EXHAUSTED` | no quota in that location | switch `--region`/`VERTEXAI_LOCATION` to where your quota is |
-| `404 Publisher Model not found` | model not enabled in project/location | enable it in Vertex Model Garden / request quota |
diff --git a/docs/content/docs/configuration.mdx b/docs/content/docs/configuration.mdx
index 15d51e8f5..da88261d9 100644
--- a/docs/content/docs/configuration.mdx
+++ b/docs/content/docs/configuration.mdx
@@ -233,7 +233,7 @@ headroom proxy --learn --min-evidence 3
| `HEADROOM_STATELESS` | Set to `true` to disable filesystem writes | `false` |
| `HEADROOM_MODEL_LIMITS` | Custom model config (JSON string or file path) | -- |
| `HEADROOM_BASE_URL` | Base URL of the Headroom proxy (TypeScript SDK) | `http://localhost:8787` |
-| `HEADROOM_API_KEY` | API key for Headroom Cloud authentication | -- |
+| `HEADROOM_API_KEY` | Optional API key for authenticated Headroom endpoints (TypeScript SDK) | -- |
| `HEADROOM_CONFIG_DIR` | Canonical config (read-mostly) root. Derives `models.json` and per-plugin config paths when set. | `~/.headroom/config` |
| `HEADROOM_WORKSPACE_DIR` | Canonical workspace (read-write state) root. Derives savings, memory DB, logs, TOIN, subscription state, and more when set. | `~/.headroom` |
| `HEADROOM_SAVINGS_PATH` | Override persistent savings file location. Always wins when set. | derived from `${HEADROOM_WORKSPACE_DIR}` |
diff --git a/docs/cortex-code.md b/docs/cortex-code.md
deleted file mode 100644
index 3d93d7afe..000000000
--- a/docs/cortex-code.md
+++ /dev/null
@@ -1,247 +0,0 @@
-# Cortex Code + Headroom — Integration Guide
-
-Headroom compresses the context Cortex Code (CoCo) sends to `claude-sonnet-4-6`
-before it reaches the Snowflake Cortex inference endpoint. The result is 60–65%
-fewer prompt tokens billed, with the same answers.
-
-## Benchmark (measured, not estimated)
-
-Token counts are from `usage.prompt_tokens` in the actual Snowflake Cortex API
-response — not headroom's local estimate.
-
-| Payload | Before | After | Saved |
-|---|---:|---:|---:|
-| Full CoCo session (tables + dbt + search) | 17,827 | 6,781 | **62%** |
-| `INFORMATION_SCHEMA` tables (79 rows) | 10,161 | 3,979 | **61%** |
-| `dbt` run-results (40 models) | 4,968 | 1,927 | **61%** |
-| Cortex Search results (15 docs) | 2,764 | 956 | **65%** |
-
-At 1,000 calls/day: **~$16/day saved**, **~$6,000/year saved**.
-
-> Numbers above are per-call averages across the four benchmark payloads.
-> The full-session payload alone saves ~$33/1,000 calls/day.
-
-## How it works
-
-```
-CoCo (cortex CLI)
- │ OPENAI_BASE_URL=http://127.0.0.1:8787/v1
- ▼
-Headroom proxy (local, your data never leaves your machine)
- │ SmartCrusher compresses JSON context
- │ CacheAligner stabilises KV-cache prefixes
- ▼
-Snowflake Cortex /api/v2/cortex/inference:complete
- │ claude-sonnet-4-6
- ▼
-Response (same answer, fewer billed tokens)
-```
-
-Headroom's **SmartCrusher** targets the large JSON blobs that CoCo produces:
-`INFORMATION_SCHEMA` query results, `dbt` run-results, Cortex Search payloads,
-and schema introspection output. These are highly repetitive structures that
-compress 60–99% without any loss of information.
-
-## Quick start
-
-```bash
-pip install "headroom-ai[all]"
-headroom wrap cortex-code # starts proxy + prints the env var to set
-```
-
-`headroom wrap cortex-code` starts the local proxy and prints:
-
-```
- Headroom proxy is running. Configure Cortex Code (CoCo):
-
- Set the following environment variable before launching cortex:
- OPENAI_BASE_URL=http://127.0.0.1:8787/v1
-```
-
-Then in a new shell:
-
-```bash
-OPENAI_BASE_URL=http://127.0.0.1:8787/v1 cortex
-```
-
-Or add it to your shell profile so it applies to every CoCo session:
-
-```bash
-# ~/.zshrc or ~/.bashrc
-export OPENAI_BASE_URL=http://127.0.0.1:8787/v1
-```
-
-## Manual proxy startup
-
-If you prefer to manage the proxy lifecycle yourself:
-
-```bash
-# Terminal 1 — start the proxy
-headroom proxy --port 8787
-
-# Terminal 2 — launch CoCo through the proxy
-OPENAI_BASE_URL=http://127.0.0.1:8787/v1 cortex
-```
-
-Point the proxy at your Snowflake Cortex endpoint explicitly with
-`--openai-api-url`:
-
-```bash
-headroom proxy \
- --port 8787 \
- --openai-api-url https://.snowflakecomputing.com
-```
-
-## Library mode (inline, no proxy)
-
-If you are building an application on top of the Snowflake Cortex REST API
-and want to compress context before every call:
-
-```python
-from headroom import compress
-import json, urllib.request
-
-# Build your messages (large JSON tool results, search results, etc.)
-messages = [
- {"role": "system", "content": json.dumps(cortex_search_results, indent=2)},
- {"role": "assistant", "content": "I have reviewed the context."},
- {"role": "user", "content": "What is failing and how do I fix it?"},
-]
-
-# Compress before sending — local, no API call, no data leaves your machine
-result = compress(messages, model="claude-sonnet-4-6")
-print(f"Saved {result.tokens_saved} tokens ({result.tokens_saved / result.tokens_before:.0%})")
-
-# Send compressed messages to Snowflake Cortex REST API
-response = call_cortex(result.messages, token=sf_token)
-```
-
-### What to put in the system message
-
-The Snowflake Cortex REST API supports `system`, `user`, and `assistant` roles.
-For maximum compression, inject large retrieved context into `system`:
-
-```python
-# Query results, search results, schema — these compress 60–99%
-system_context = {
- "tables": json.loads(show_tables_result),
- "search_results": cortex_search_results,
- "schema": describe_table_result,
- "dbt_results": dbt_run_results_json,
-}
-messages = [
- {"role": "system", "content": json.dumps(system_context, indent=2)},
- {"role": "assistant", "content": "Context loaded."},
- {"role": "user", "content": user_question},
-]
-result = compress(messages, model="claude-sonnet-4-6")
-```
-
-## Authentication
-
-Cortex Code authenticates using your Snowflake connection. Headroom sits
-between CoCo and the Cortex endpoint and forwards auth headers unchanged —
-it never reads or stores your credentials.
-
-If you use `snowflake-connector-python` directly, keep the connection open
-while making API calls; closing it invalidates the OAuth session token:
-
-```python
-import snowflake.connector, sys, io
-
-# Suppress connector's browser-auth console output
-_s = sys.stdout; sys.stdout = io.StringIO()
-conn = snowflake.connector.connect(connection_name="my_connection")
-token = conn.rest.token
-sys.stdout = _s
-
-# Make all API calls while conn is open, then:
-conn.close()
-```
-
-## Per-project savings attribution
-
-Use `headroom wrap cortex-code --project ` to attribute savings to a
-specific project in the headroom dashboard:
-
-```bash
-headroom wrap cortex-code --project my-dbt-project
-```
-
-The dashboard at `http://127.0.0.1:8787` shows per-project token and cost
-savings across all your CoCo sessions.
-
-## Verifying savings
-
-After a CoCo session, check what headroom saved:
-
-```bash
-headroom perf # token savings for the last session
-headroom perf --hours 24 # last 24 hours
-```
-
-Or run the included end-to-end benchmark against your own Snowflake account:
-
-```bash
-# Measures real usage.prompt_tokens from claude-sonnet-4-6
-python3 tests/e2e_cortex_savings.py
-```
-
-## Testing
-
-Unit tests for the provider slice:
-
-```bash
-uv run --with pytest pytest tests/test_provider_cortex_code.py -v
-```
-
-Compression benchmark (no API key needed — local only):
-
-```bash
-uv run --with pytest pytest tests/test_cortex_code_compression.py -v -s
-```
-
-Real E2E test against Snowflake Cortex (requires Snowflake connection):
-
-```bash
-python3 tests/e2e_cortex_savings.py
-```
-
-## How the provider is implemented
-
-Cortex Code routes through headroom's OpenAI-compatible pipeline. The provider
-slice lives in `headroom/providers/cortex_code/`:
-
-| File | Purpose |
-|---|---|
-| `runtime.py` | `proxy_base_url(port)` → `http://127.0.0.1:{port}/v1`; `default_api_url()` reads `SNOWFLAKE_HOST` / `SNOWFLAKE_ACCOUNT` |
-| `install.py` | `build_install_env()` → `{"OPENAI_BASE_URL": ...}`; `render_setup_lines()` |
-| `__init__.py` | Public exports |
-
-Registered in `headroom/providers/install_registry.py` under the key
-`"cortex-code"`, which is what `headroom wrap cortex-code` resolves to.
-
-## Limitations
-
-- The Snowflake Cortex REST API at `/api/v2/cortex/inference:complete` does not
- support `role: "tool"` messages or OpenAI-style `tool_calls`. Use the
- `system` message to inject large retrieved context (where SmartCrusher
- achieves the highest compression ratios).
-
-- The headroom proxy cannot rewrite the Cortex inference path
- (`/api/v2/cortex/inference:complete` ≠ `/v1/chat/completions`), so
- **library mode** (`from headroom import compress`) is required when calling
- the Cortex REST API directly. The proxy mode works for any
- OpenAI-compatible client that points at Cortex via a gateway that exposes
- `/v1/chat/completions`.
-
-- Output-token reduction (`HEADROOM_OUTPUT_SHAPER=1`) is supported in proxy
- mode. In library mode only input compression applies.
-
-## See also
-
-- [Architecture](ARCHITECTURE.md)
-- [Proxy configuration](proxy.md)
-- [CCR — reversible compression](ccr.md)
-- [Claude Code + Vertex](claude-code-vertex-headroom.md)
-- [Benchmarks](benchmarks.md)
diff --git a/docs/output-token-reduction-guide.md b/docs/output-token-reduction-guide.md
deleted file mode 100644
index 5a54f21d0..000000000
--- a/docs/output-token-reduction-guide.md
+++ /dev/null
@@ -1,145 +0,0 @@
-# Output Token Reduction — User Guide
-
-A plain-English guide to cutting the tokens the model **writes back**.
-
-## Why this exists
-
-Headroom normally shrinks the prompt you **send**. This feature shrinks what the
-model **returns**. That matters because:
-
-- Output tokens cost **5× more** than input on Opus-class models.
-- A lot of model output is waste: "Great, let me help with that…" intros,
- re-printing code you already showed it, restating tool results, and long
- internal "thinking" even on trivial steps.
-
-You don't change any code. It runs in the Headroom proxy.
-
-## Turn it on
-
-```bash
-export HEADROOM_OUTPUT_SHAPER=1 # off by default
-headroom proxy --port 8787
-```
-
-> **If a proxy is already running** (e.g. `headroom wrap claude` attaches to one
-> on port 8787 instead of starting a fresh one), it reads this switch from the
-> environment it was launched with — so exporting it afterwards wouldn't reach
-> it. `headroom wrap` handles this for you: it hot-syncs your current output
-> settings to the running proxy (loopback `POST /admin/runtime-env`), applied
-> immediately with no restart. Set the variables before you run `wrap`. Because
-> one proxy is shared by every session attached to it, these settings are global
-> — the most recent explicit value wins.
-
-That's it. Two things now happen on every request:
-
-1. **Verbosity steering** — a short "be terse, don't restate context" instruction
- is added to the **end** of the system prompt. (The end, so your prompt cache
- still works.)
-2. **Effort routing** — if a turn is just the model continuing after a tool ran
- (e.g. it read a file and there were no errors), Headroom turns the model's
- "thinking effort" down for that one turn. Real questions and error-handling
- turns keep full effort.
-
-## The verbosity dial (levels 0–4)
-
-| Level | What the model is told | Good for |
-|------:|------------------------|----------|
-| 0 | (off) | disable steering |
-| 1 | Skip the intro/outro chit-chat | people who read everything |
-| 2 | Also: don't restate code/output already on screen | **default** — safe |
-| 3 | Also: conclusions only, skip the reasoning | people who skim |
-| 4 | Bare minimum, fragments OK | maximum savings, terse |
-
-Set it by hand if you want:
-
-```bash
-export HEADROOM_VERBOSITY_LEVEL=3
-```
-
-Or — better — let Headroom learn it from your habits (next section).
-
-## Let Headroom pick the level for you
-
-People rarely *say* "be brief." They *show* it: they interrupt long answers, or
-reply so fast they couldn't have read the whole thing. `headroom learn
---verbosity` reads your past sessions and picks a level from those signals.
-
-```bash
-# Preview what it found (doesn't change anything)
-headroom learn --verbosity
-
-# Save it — the proxy uses this level from now on
-headroom learn --verbosity --apply
-```
-
-Example output:
-
-```
-Verbosity — headroom
- Interrupts: 29 (11% of turns) ← push-back signal
- Fast-skips: 31 / 119 long answers (26% unread) ← strongest signal
- >> Recommended verbosity level: 3 (confidence: high)
-```
-
-Add `--llm-judge` to have an LLM double-check the level (needs an API key).
-
-## See how much you saved
-
-Here's the honest part. We **can't directly measure** output savings — we never
-see what the model *would* have written without our nudge. So Headroom reports an
-**estimate with a confidence range**, never a fake exact number:
-
-```bash
-headroom output-savings
-```
-
-```
-Output-token reduction
- Method: ESTIMATED (synthetic control)
- Requests: 1,240 shaped
- Saved: ~410,000 output tokens
- Reduction: 28.0% (95% CI 24.1% … 31.9%)
-```
-
-- **ESTIMATED** = compared against a baseline of your past (unshaped) sessions.
-- **MEASURED** = the gold standard, if you opt into a holdout (below).
-
-### Want a *measured* number?
-
-Leave a slice of traffic unshaped as a control group:
-
-```bash
-export HEADROOM_OUTPUT_HOLDOUT=0.1 # 10% of conversations stay unshaped
-```
-
-Now `headroom output-savings` compares shaped vs unshaped directly and reports a
-**measured** reduction. The trade-off: you give up the savings on that 10%.
-
-## On the dashboard
-
-Open `http://localhost:8787/dashboard`. Next to the input-compression card
-you'll see an **Output Tokens Saved** card showing the token count, the percent,
-a `measured`/`estimated` badge, and the confidence range.
-
-## FAQ
-
-**Will this make answers worse?**
-At level 2 (default), no — in our tests the model finds the same bugs and writes
-the same fixes; it just stops re-printing code and skipping the "let me…" intro.
-Levels 3–4 are terser by design; that's why learning the level per user matters.
-
-**Does it break prompt caching?**
-No. The steering text is added at the *end* of the system prompt and is
-byte-stable, so your cached prefix is untouched.
-
-**Is it safe with extended thinking / tool loops?**
-Yes. It never disables thinking outright (that can error), it only lowers effort
-on routine turns, and it never adds settings the model doesn't support.
-
-**How do I turn it off?**
-Unset `HEADROOM_OUTPUT_SHAPER` (or set it to `0`) and restart the proxy. You can
-also send `x-headroom-bypass: true` on a request to skip it for that call.
-
----
-
-Deep dive (design + the counterfactual math): [`proposals/output-token-reduction.md`](proposals/output-token-reduction.md)
diff --git a/docs/proposals/output-token-reduction.md b/docs/proposals/output-token-reduction.md
deleted file mode 100644
index c768e5f35..000000000
--- a/docs/proposals/output-token-reduction.md
+++ /dev/null
@@ -1,461 +0,0 @@
-# Output Token Reduction
-
-**Branches:** `feat/output-token-reduction` (Phase 1) → `feat/verbosity-learning-and-counterfactual` (Phase 2).
-**Status:** Phase 1 (output shaper) and Phase 2 (`learn --verbosity`, AIMD controller, counterfactual estimator, dashboard) both implemented + tested. Runtime AIMD signal-capture is staged (controller built/tested, live emission off by default).
-
-See **§7** for the counterfactual measurement methodology (how we honestly report a number we can't directly observe).
-
----
-
-## 1. The problem in one line
-
-Headroom's entire transform pipeline compresses what goes **into** the model.
-Nothing today touches what comes **out**. But output tokens are billed at
-5× input on Opus-class models ($25 vs $5 per MTok on `claude-opus-4-8`), and in
-agentic coding loops a large fraction of the bill is output: thinking tokens,
-restated code, ceremony ("Great, let me…"), and full-file rewrites where a
-10-line edit would do.
-
-**The constraint that shapes everything:** the proxy never generates output
-tokens — the model does. Once a token is streamed it is already billed. So
-every output-token lever is **request-side**: change what we ask for, cap what
-we allow, or avoid the generation entirely. There is no post-hoc lever.
-
-That gives three lever families plus a learning loop:
-
-| Lever | Mechanism | Status |
-|---|---|---|
-| **Verbosity steering** | Append a terse-style instruction to the system-prompt tail | ✅ built |
-| **Effort routing** | Lower `output_config.effort` on mechanical turns | ✅ built |
-| **Thinking-budget clamp** | Clamp legacy `thinking.budget_tokens` on mechanical turns | ✅ built |
-| **Per-user learned level** | Mine past sessions for the right verbosity per user (`learn --verbosity`) | ✅ built |
-| **Counterfactual estimator** | Honestly estimate output tokens saved + dashboard surfacing | ✅ built |
-| **Runtime AIMD auto-tune** | Adjust level live from interrupt / skip signals | 🟡 controller built/tested; live signal emission off by default |
-
----
-
-## 2. Phase 1 — the output shaper (built)
-
-### 2.1 What it is
-
-`headroom/proxy/output_shaper.py` — a request-body rewriter invoked in
-`handle_anthropic_messages` after every other body mutation (so the turn
-classifier sees the final message list) and gated behind the same
-`x-headroom-bypass` header as compression. Opt-in via `HEADROOM_OUTPUT_SHAPER=1`.
-
-### 2.2 Lever A — verbosity steering
-
-A deterministic instruction block is appended to the **tail** of the system
-prompt. Five levels, cumulative:
-
-- **L0** — off (touch nothing).
-- **L1** — no ceremony: skip preamble/postamble, don't announce what you're about to do.
-- **L2** — L1 + no echo: never restate code/diffs/tool output already in context; reference by path:line; don't narrate tool results. **(default)**
-- **L3** — L2 + conclusions only, omit rationale unless asked, prefer smallest edit.
-- **L4** — caveman: fragments, minimum tokens, nothing but the answer.
-
-**Why the tail, not the head.** Prompt caching is a prefix match — any byte
-change ahead of a `cache_control` breakpoint invalidates everything after it.
-Prepending steering text would bust the provider prefix cache and cost more
-than it saves. Appending after the last system block leaves the cached prefix
-byte-identical; only the small, byte-stable steering block is reprocessed. The
-steering text is frozen per level and applied idempotently (sentinel-tagged),
-so repeated requests keep an identical prefix and a level change replaces the
-block in place rather than stacking.
-
-### 2.3 Lever B — effort routing
-
-In an agentic loop, most API calls are **mechanical continuations**: the last
-message is a clean `tool_result` (a file read, a passing test) and the model is
-just resuming. Harnesses like Claude Code pin `output_config.effort` at `xhigh`
-for *every* turn, including these — and effort drives thinking depth, which
-bills as output. The router lowers effort to `low` on mechanical turns only.
-
-Turn classification is **purely structural** — no content regexes, no keyword
-lists (per the project's no-hardcoded-patterns rule):
-
-| Last user message contains… | Classification | Action |
-|---|---|---|
-| Any text / image / document block | `NEW_USER_ASK` | leave effort alone |
-| Only `tool_result`, none `is_error` | `MECHANICAL_CONTINUATION` | lower effort → `low` |
-| Any `tool_result` with `is_error: true` | `ERROR_CONTINUATION` | leave effort alone (model must reason about the failure) |
-| Anything else | `UNKNOWN` | leave alone |
-
-### 2.4 Lever C — legacy thinking-budget clamp
-
-On older models still sending `thinking: {type: "enabled", budget_tokens: N}`,
-the router clamps `N` to the API floor (1024) on mechanical turns. The `type`
-field is **never** toggled.
-
-### 2.5 Safety rules (each prevents a concrete failure)
-
-1. **Never inject `output_config.effort` where the client didn't send it.**
- Models without effort support return 400 on it. Lowering an
- already-present value is always valid — its presence proves the target
- model accepts the param.
-2. **Never toggle `thinking.type`.** Disabling thinking while history carries
- thinking blocks 400s on some models, and the toggle busts the messages
- cache tier (per the caching invalidation hierarchy).
-3. **Byte-stable, idempotent steering** — repeated requests keep an identical
- prefix; cache stays warm.
-4. **Respect `x-headroom-bypass`** — sub-agent calls that opt out of
- compression also opt out of shaping.
-
-### 2.6 Configuration
-
-| Env var | Default | Meaning |
-|---|---|---|
-| `HEADROOM_OUTPUT_SHAPER` | off | master switch (`1`/`true`/`yes`) |
-| `HEADROOM_VERBOSITY_LEVEL` | `2` | 0–4 (clamped) |
-| `HEADROOM_EFFORT_ROUTER` | on | set `0` to disable effort routing |
-| `HEADROOM_MECHANICAL_EFFORT` | `low` | floor effort for mechanical turns |
-
-### 2.7 Tests
-
-`tests/test_output_shaper.py` — 34 tests, all passing. Covers turn
-classification (every block-type path), cache-safe steering (string→block
-conversion, append-after-`cache_control`, idempotency, level change),
-effort routing (lower / never-inject / untouched-on-non-mechanical /
-configurable target), legacy budget clamp, and the env gate. Ruff + mypy clean.
-
----
-
-## 3. Live before/after results
-
-Measured against `claude-opus-4-8` via `scripts/eval_output_shaper.py`,
-comparing the exact body a client sends vs. the body the proxy forwards.
-`usage.output_tokens` includes thinking.
-
-### 3.1 Verbosity steering — complex code-review ask
-
-Prompt: "review this TTLCache, find every bug, show fixes."
-
-| Condition | Mean output tokens | Reduction |
-|---|---|---|
-| Baseline | ~1,800–1,930 | — |
-| L2 (no ceremony, no echo) | ~1,180–1,470 | **−22% to −39%** |
-| L3 (conclusions only) | ~670 | **−63%** |
-
-**Quality check — same bugs found, only redundancy removed.** The baseline
-opens with a title + "Let me go through them," finds the bugs, **re-prints the
-entire fixed class**, then adds a **summary table restating all six bugs**,
-then a trailing notes section — the same information appears ~2.5×. L2 opens
-directly with the findings, gives the same fixed code block once, and stops.
-Both correctly identify the no-locking race, `popitem(last=True)` evicting the
-wrong end, and the mutate-during-iteration `RuntimeError`. Nothing of substance
-is lost at L2; L3 additionally drops rationale prose (only for users who don't
-read explanations).
-
-### 3.2 Effort routing — agentic mechanical continuation
-
-Transcript ending in a clean `tool_result`, `effort: xhigh` the way Claude Code
-sends it.
-
-| Condition | Mean output tokens | Reduction |
-|---|---|---|
-| Baseline (xhigh) | ~1,120 | — |
-| Shaped (routed to low) | 793 | **−29%** |
-
-### 3.3 Honest framing
-
-Caveman (L4) would get ~60–70% but degrades the experience. The taxonomy-driven
-default (L2 + effort routing on mechanical turns) gets a realistic **25–40%**
-with the user barely noticing. The learning loop (Phase 2) finds where each
-user sits between those poles.
-
----
-
-## 4. Phase 2 — learning the right level per user
-
-### 4.1 Why this is necessary
-
-The right verbosity is **per-user**, not global. A fixed `HEADROOM_VERBOSITY_LEVEL`
-is a guess. We can do better: mine the user's own past sessions to infer what
-they actually tolerate — exactly the philosophy of `headroom learn`, which
-already reads `~/.claude/projects/*.jsonl` and turns history into learned
-context.
-
-### 4.2 The key insight (validated on real data)
-
-I prototyped the signal extraction and ran it over **24 real sessions** for
-this project. The finding that shapes the whole design:
-
-| Signal | This user's data | Carries signal? |
-|---|---|---|
-| Explicit "be brief" keywords | **1** of 210 human msgs | ❌ almost none |
-| Explicit "explain more" keywords | **1** of 210 | ❌ almost none |
-| **Interruptions** (user cuts Claude off) | **29** (~1 per 7 turns) | ✅ strong |
-| **Fast-skips** (reply <30s after a >250-word answer) | **15 of 100 long outputs** | ✅ strong |
-| Long-output frequency | 100 outputs >250 words | ✅ context |
-
-**Users almost never *say* what verbosity they want — they show it
-behaviorally.** Keyword matching (the obvious approach) is nearly empty. The
-behavioral signals are rich. The strongest is **fast-skip**: a reply arriving
-faster than the answer could have been read is a direct measurement of
-"generated tokens nobody consumed," computable from timestamps + lengths
-already in the JSONL.
-
-For this user — 29 interrupts, 15% unread-long-output rate, zero "explain more"
-requests — the data reads as a clear **L2, arguably L3** user.
-
-### 4.3 Design — `headroom learn --verbosity`
-
-Slots into the existing `learn` architecture. `headroom/learn/plugins/claude.py`
-already parses the JSONL; `analyzer.py` already does cheap-extraction → digest →
-LLM-returns-JSON. We add a verbosity analysis path:
-
-**Step 1 — structural pass (pure Python, no patterns).** Per session, compute:
-- **interrupt rate** — `[Request interrupted by user…]` markers per human turn
-- **fast-skip rate** — human reply latency vs. preceding assistant output length
-- **long-output frequency** — share of assistant texts over N words
-- **echo ratio** — n-gram overlap between assistant output and prior context (restated code)
-- reply-latency distribution vs. output length
-
-All mechanical, all from data already on disk. (Prototype:
-`scripts/verbosity_scan.py`, validated above.)
-
-**Step 2 — LLM judgment pass (mirrors today's `learn`).** Feed a digest of
-human messages + the structural stats to the analyzer LLM with one question:
-*"Does this user read long explanations, and when they push back, is it for
-more detail or less?"* This replaces brittle keyword lists with judgment —
-consistent with the no-hardcoded-patterns rule. Returns a level + confidence +
-rationale as JSON.
-
-**Step 3 — output (this is what `--verbosity` produces).** See §4.4.
-
-**Step 4 — runtime AIMD auto-tune.** The offline pass sets the *starting* level;
-a live loop tracks drift. An interrupt or fast-skip nudges the level up one; an
-"explain"/"why" follow-up drops it back. Hysteresis (require 2–3 consistent
-signals before moving) prevents oscillation. Like TCP congestion control: probe
-toward terser, back off on a "too terse" signal.
-
-### 4.4 What `--verbosity` outputs — and how it helps
-
-The command produces three concrete artifacts:
-
-**(a) A human-readable report (stdout):**
-```
-Verbosity analysis — /Users/tcms/demo/headroom (24 sessions, 210 turns)
-
- Interrupts: 29 (1 per 7.2 turns) ← strong "too much" signal
- Fast-skips: 15 / 100 long outputs ← 15% of long answers unread
- Explicit brevity: 1 explicit verbose: 1 ← behavioral, not stated
-
- LLM read: "User interrupts frequently and rarely reads long
- explanations; pushes back for less, never more detail."
-
- Recommended verbosity level: 2 (confidence: high)
- Estimated output-token reduction at L2: ~25–35%
-```
-
-**(b) A persisted setting** written to `~/.headroom/` (alongside the existing
-savings tracker) — per-project verbosity level + confidence:
-```json
-{"project": "/Users/tcms/demo/headroom",
- "verbosity_level": 2, "confidence": "high",
- "signals": {"interrupt_rate": 0.138, "fast_skip_rate": 0.15},
- "learned_at": "2026-06-12T…"}
-```
-
-**(c) The shaper reads it as its default.** `OutputShaperSettings.from_env()`
-gains a fallback: if `HEADROOM_VERBOSITY_LEVEL` is unset, load the learned
-per-project level instead of the hardcoded `2`. So **the output of `--verbosity`
-directly becomes the live verbosity the proxy applies** — no manual tuning.
-
-**How it helps, concretely:**
-1. **Removes the guess.** Today you set `HEADROOM_VERBOSITY_LEVEL=2` by hand.
- After `learn --verbosity`, the level is derived from *your* behavior — a
- heavy-interrupter gets L3, a "read everything" user gets L1.
-2. **Per-project, not global.** Your exploratory side-project and your
- production repo can carry different levels.
-3. **Justified, not magic.** The report shows the signals and the LLM's read,
- so the recommendation is auditable (matches the dashboard philosophy of
- showing directional data, not opaque scores).
-4. **Seeds the runtime loop.** The learned level is the AIMD starting point;
- live signals refine it without re-running the offline pass.
-
-### 4.5 Mapping signals → level (initial heuristic, LLM-refined)
-
-| Interrupt rate | Fast-skip rate | "explain more" present | → Level |
-|---|---|---|---|
-| low | low | yes | 1 |
-| low–med | low–med | no | 2 |
-| high | high | no | 3 |
-| very high | very high | no | 4 (offer, don't auto-apply) |
-
-The LLM judgment pass adjusts this — the table is the prior, not the verdict.
-
----
-
-## 5. Files
-
-| File | Status | Purpose |
-|---|---|---|
-| `headroom/proxy/output_shaper.py` | ✅ built | the shaper (steering + effort routing) |
-| `headroom/proxy/handlers/anthropic.py` | ✅ wired | invoke shaper after body mutations |
-| `tests/test_output_shaper.py` | ✅ 34 passing | unit coverage |
-| `scripts/eval_output_shaper.py` | ✅ built | live before/after eval |
-| `scripts/verbosity_scan.py` | 🔬 prototype | session-mining signal extraction |
-| `headroom/learn/plugins/claude.py` (+ analyzer) | 🔜 extend | `--verbosity` analysis path |
-| `~/.headroom/verbosity.json` | 🔜 | persisted per-project learned level |
-
----
-
-## 6. Roadmap
-
-1. ✅ **Measure** — live eval establishes the realistic ceiling and baseline.
-2. ✅ **Effort router** — biggest win per unit risk, fully mechanical, invisible.
-3. ✅ **Verbosity ladder at fixed L2** — safe default, cache-safe tail injection.
-4. 🔜 **`learn --verbosity`** — derive the per-user starting level from sessions.
-5. 🔜 **Runtime AIMD auto-tune** — refine the level live from interrupt/skip signals.
-6. 🔭 **Waste taxonomy on the dashboard** — echo ratio, ceremony ratio,
- full-file-rewrite detection, as token counts (no dollar estimates).
-7. 🔭 **Budget whispering** — tell the model its token budget per turn-type,
- sized from the historical output distribution in SQLite.
-
----
-
-## 7. Counterfactual measurement — how we show a % we can't directly observe
-
-This is the hard part, and it deserves its own section.
-
-### 7.1 Why output savings are not directly measurable
-
-Input compression is a **pure function**: Headroom takes a request, shrinks it,
-and can count `tokens_before` and `tokens_after` — both are observable on the
-same request. Output is different. When the shaper makes a request terser, the
-model emits N output tokens. We **never observe** what it *would* have emitted
-without the steering. Only one side of the counterfactual ever happens. So a
-flat "we saved 30%" is a guess dressed as a fact.
-
-The design rule that follows: **never report a single number as if it were
-measured.** Separate what is genuinely measured from what is estimated, label
-each, and always attach uncertainty.
-
-### 7.2 Three tiers of honesty
-
-**Tier 1 — Estimated (synthetic control).** Build a per-stratum baseline of
-*unshaped* output tokens from session history that predates the shaper
-(`learn --verbosity` does this in the same pass that picks the level). For each
-shaped request, the expected unshaped output is the baseline mean for that
-request's stratum. Aggregate estimate:
-
-```
-tokens_saved = Σ over shaped requests ( baseline_mean[stratum] − observed_output )
-```
-
-Summed as **signed** deltas — never clamped per-request. Clamping each delta at
-zero would throw away the cases where a shaped response happened to be *longer*
-by chance, biasing the total upward. Over many requests the noise averages out;
-the systematic effect remains. Reported with a propagated 95% CI (see §7.5) and
-always labelled "estimated."
-
-**Tier 2 — Measured (A/B holdout).** Set `HEADROOM_OUTPUT_HOLDOUT=0.1` and 10%
-of conversations are deliberately left **unshaped** as a control arm. Within
-each stratum, `mean(control) − mean(treatment)` is an **unbiased causal
-estimate** of the per-request saving. This is the only number we call
-"measured." It self-corrects: if steering doesn't actually help on some
-workload, the holdout reveals it. The cost is real (you forgo savings on 10% of
-traffic), so it's opt-in; default holdout is 0 (estimate-only).
-
-**Tier 3 — Direct waste (no counterfactual at all).** Echo ratio — the n-gram
-overlap between a response and the context it was given — is a property of a
-single response. "32% of this output restated context already on screen" needs
-no counterfactual; it's a measured fact about output we *did* see, and it's
-exactly what the shaper targets. Surfaced in `learn --verbosity` as
-`mean_echo_ratio`.
-
-### 7.3 Stratification — comparing like with like
-
-You can't compare a "fix this typo" response to "design a caching layer." The
-estimator buckets every request by features observable **before** the response:
-
-```
-stratum = model_family | turn_kind | input_token_bucket | has_tools
- = e.g. "opus | mechanical_continuation | xl | tools"
-```
-
-Coarse on purpose (~25–50 strata) so per-stratum baselines stay dense. The live
-proxy computes the stratum the exact same way the offline baseline does, so
-treatment requests line up with their baseline. Unseen strata fall back
-hierarchically (drop `has_tools`, then the bucket, …, then the global mean).
-
-### 7.4 The two constraints that happen to align
-
-Holdout assignment is **conversation-stable** — a whole conversation is either
-treatment or control, decided by hashing a conversation-stable key (model +
-first user message). This matters for two independent reasons that point the
-same way:
-
-1. **Measurement validity** — mixing shaped and unshaped turns within one
- conversation would contaminate the comparison (the history itself differs).
-2. **Cache safety** — flipping a conversation's verbosity mid-stream changes the
- system-prompt tail, which busts the provider prefix cache.
-
-So the same rule (assign per conversation, never per turn) is forced by both
-the statistics and the caching. Nice when constraints agree.
-
-### 7.5 The confidence interval
-
-For the estimated tier, uncertainty comes from two sources, both propagated:
-
-```
-Var(tokens_saved) ≈ Σ_s [ n_s · σ²_observed,s + n_s² · σ²_baseline,s / m_s ]
- └─ spread of shaped outputs ─┘ └─ finite-baseline error ─┘
-```
-
-where `n_s` is treatment count in stratum `s` and `m_s` the baseline sample
-count. For the measured tier it's the standard difference-of-means variance
-`σ²_c/n_c + σ²_t/n_t` per stratum. The 95% band is `point ± 1.96·√Var`, surfaced
-everywhere the number is (CLI and dashboard), so the reader sees the precision,
-not just a point estimate.
-
-Output-token counts are right-skewed (a few huge responses). Means are still the
-right statistic for *totals* (you're billed on the sum), but the CI widens
-honestly when a stratum is dominated by a few large responses — which is the
-correct signal that the estimate is soft there.
-
-### 7.6 How it flows end to end
-
-```
-learn --verbosity --apply
- ├─ writes verbosity.json (the level the shaper applies)
- └─ seeds output_savings.json (the per-stratum baseline = synthetic control)
-
-proxy request (HEADROOM_OUTPUT_SHAPER=1)
- ├─ assign_arm(conversation) → treatment | control (holdout)
- ├─ stratum_key(request features)
- ├─ treatment: shape body; control: leave unshaped
- └─ tag (arm, stratum) onto transforms_applied ← rides existing plumbing
-
-response completes → emit_request_outcome (one funnel, all paths)
- └─ recorder.record(arm, stratum, output_tokens) → output_savings.json
-
-headroom output-savings / dashboard "Output Tokens Saved" card
- └─ best_estimate(): measured if a holdout exists, else estimated; with CI
-```
-
-The recording rides the existing `transforms_applied` label channel, so it
-works for streaming, non-streaming, and backend paths with no change to
-`RequestOutcome` or its construction sites.
-
-### 7.7 What the user sees
-
-- **CLI:** `headroom output-savings` →
- `Reduction: 31.7% (95% CI 27.7% … 35.7%) [MEASURED, 400 shaped requests]`
-- **Dashboard:** an "Output Tokens Saved" hero card next to input compression —
- token count, percent, a `measured`/`estimated` badge, and the CI band.
-- **No dollar estimates** on the output card (per project convention) — token
- counts and directional percentages only.
-
-### 7.8 Honest limitations
-
-- Estimated-tier accuracy depends on the baseline matching current workload; if
- your tasks drift, re-run `learn --verbosity` or turn on a small holdout.
-- The baseline must come from *unshaped* history. If you learn from sessions
- where the shaper was already active, the baseline is contaminated — the live
- holdout is the clean path forward.
-- Runtime AIMD upward-ratcheting is gated off by default: we can reliably detect
- "too much output" (fast-skip timing, stream cancellation) but not yet "too
- little" at runtime without content heuristics, so auto-escalation stays
- behind `HEADROOM_VERBOSITY_AUTOTUNE` until both directions are trustworthy.
diff --git a/docs/proposals/vertex-claude-compression-review.md b/docs/proposals/vertex-claude-compression-review.md
deleted file mode 100644
index e4486b7cd..000000000
--- a/docs/proposals/vertex-claude-compression-review.md
+++ /dev/null
@@ -1,266 +0,0 @@
-# Claude Code + Vertex AI + Headroom compression — does it work?
-
-*A plain-English deep code review. Last updated 2026-06-18.*
-
-## TL;DR (read this first)
-
-**Yes — and the working path is now validated end-to-end (2026-06-19). See the
-copy-paste runbook: [`docs/claude-code-vertex-headroom.md`](../claude-code-vertex-headroom.md).**
-
-> **2026-06-19 update — tested against live Vertex quota (Claude Code 2.1.181):**
-> Of the two setups below, **only Setup B works in practice.**
->
-> - **Setup A (Vertex mode + `ANTHROPIC_VERTEX_BASE_URL`→proxy) is blocked by Claude
-> Code itself.** In Vertex mode Claude Code runs a client-side `probeVertexModel`
-> check *before any request*; pointing its Vertex URL at a non-Google host makes that
-> probe fail instantly ("model … not available on your vertex deployment") and the
-> proxy never receives a byte. Not a Headroom bug — the native `:rawPredict`
-> passthrough is correct and compresses (verified by direct curl), but the client
-> won't route to it.
-> - **Setup B (normal Anthropic mode + `--backend litellm-vertex_ai`) is the working
-> path.** Verified: Claude Code → Headroom → LiteLLM → Vertex (`global`), real
-> answers, and **~22% context compression on a code-heavy request**. Two gotchas:
-> (1) `pip install "google-cloud-aiplatform>=1.38"` or requests 500 with
-> `No module named 'vertexai'`; (2) start the proxy with **`--code-aware`** or code
-> content silently no-ops (it is disabled by default).
-
-There is still **no `headroom wrap claude` turnkey** for Vertex, and the one backend
-flag older help text advertises (`--backend litellm-vertex`) is broken — use
-`--backend litellm-vertex_ai`.
-
-Everything in the *middle* (compression, request/response translation, streaming,
-tool calls) is implemented correctly. The gaps are all at the **edges**: how the
-client is pointed at Headroom, one mis-named backend, a missing pip extra, a
-default-off compressor, and a few env vars Headroom never sets for you.
-
-> Correction to an earlier claim: it is **not** true that "the Python proxy just
-> passes Vertex through without compressing." For the Anthropic publisher it runs
-> the full compression pipeline. That earlier statement was based on an incomplete
-> read of the routing code; the verified behavior is in this doc.
-
----
-
-## The thing we're trying to do
-
-An enterprise runs **Claude Code**, but their Claude models live on **Google
-Vertex AI** (not the direct Anthropic API). They want **Headroom** in the middle so
-their prompts get compressed (fewer input tokens = lower cost), without changing
-the answers.
-
-For that to happen, three things must all be true:
-
-1. **The client's traffic must actually reach Headroom** (the proxy must be in the path).
-2. **Headroom must compress it.**
-3. **Headroom must forward it to Vertex correctly** (right URL, right auth, right body shape) and translate the answer back so Claude Code understands it.
-
-This review checks all three.
-
----
-
-## The map: where Claude-on-Vertex can run, and what compresses
-
-There are **two proxies** in this repo and **three** possible routes. Only some compress.
-
-| Route | What it is | Compresses? | Notes |
-|---|---|---|---|
-| **Python proxy, native Vertex `:rawPredict`** (publisher = `anthropic`) | Client sends a real Vertex request to Headroom | ✅ **Yes** | Runs the full Anthropic compression pipeline, keeps the Vertex body shape, forwards the client's own Google token. `proxy_routes.py:648` |
-| **Python proxy, `--backend litellm-vertex_ai`** | Client speaks plain Anthropic; Headroom translates to Vertex | ✅ **Yes** (correct string only) | Full Anthropic↔Vertex translation incl. streaming + tools. **`litellm-vertex` is broken — must use `litellm-vertex_ai`.** |
-| **Rust proxy, native Vertex `:rawPredict`** | A separate `headroom-proxy` binary | ✅ **Yes** | Correct and well-built — **but never run by `headroom proxy`/`wrap`.** Dead code for normal users. |
-| **Python proxy, passthrough** (any *other* publisher) | Generic verbatim forward | ❌ No | Only used for non-Anthropic, non-Google publishers. `openai.py:6014` |
-
-**Key takeaway:** the *compression engine* for Vertex+Claude exists and works in the
-Python proxy. The problems are getting traffic into it and one naming bug.
-
----
-
-## Does it work end-to-end? The honest answer
-
-**Through `headroom wrap claude` with zero extra setup: no.** `wrap claude` only
-sets `ANTHROPIC_BASE_URL`. If Claude Code is in Vertex mode it ignores that and
-talks straight to Google — Headroom is never in the path. And `wrap claude` has no
-`--backend`/`--region` flags and sets no Vertex environment variables.
-
-**With manual setup: yes, one of two ways.** Both are below. Both work *around*
-issues, not because the product wires them for you.
-
----
-
-## Setup A — Claude Code stays in Vertex mode (recommended for Vertex shops)
-
-Idea: Claude Code keeps using its native Vertex mode and its own Google login.
-You just tell it "send Vertex requests to Headroom instead of straight to Google,"
-and you tell Headroom where the real Vertex endpoint is.
-
-```bash
-# 1) Run Headroom, telling it the real Vertex endpoint (match your region!)
-headroom proxy --port 8787 \
- --vertex-api-url https://us-east5-aiplatform.googleapis.com # use YOUR region
-
-# 2) Run Claude Code in Vertex mode, but point its Vertex base URL at Headroom
-export CLAUDE_CODE_USE_VERTEX=1
-export ANTHROPIC_VERTEX_PROJECT_ID=
-export CLOUD_ML_REGION=us-east5
-export ANTHROPIC_VERTEX_BASE_URL=http://127.0.0.1:8787 # <-- the redirect that makes it work
-claude
-```
-
-What happens: Claude Code → `ANTHROPIC_VERTEX_BASE_URL` (Headroom) → Headroom
-matches the `:rawPredict` route, sees `publisher=anthropic`, **compresses**, then
-forwards to the real Vertex endpoint using Claude Code's own Google token.
-
-Caveats: you must set `--vertex-api-url` to your region (see Issue #6), and
-`wrap claude` won't set `ANTHROPIC_VERTEX_BASE_URL` for you (Issue #3).
-
----
-
-## Setup B — Claude Code in normal Anthropic mode; Headroom talks to Vertex
-
-Idea: Claude Code thinks it's talking to plain Anthropic. Headroom holds the Google
-credentials and is the one that actually talks to Vertex.
-
-```bash
-# Headroom does the Vertex talking — note the backend name carefully
-export HEADROOM_BACKEND=litellm-vertex_ai # NOT "litellm-vertex" (that's broken — Issue #1)
-export HEADROOM_REGION=us-east5 # becomes the Vertex location
-export VERTEXAI_PROJECT= # Headroom does NOT set this for you (Issue #4)
-export GOOGLE_APPLICATION_CREDENTIALS=/path/sa.json # or use `gcloud auth application-default login`
-export ANTHROPIC_API_KEY=placeholder-not-used # Claude Code needs *a* key to start (Issue #5)
-
-# Do NOT set CLAUDE_CODE_USE_VERTEX here — Claude Code must stay in normal mode
-headroom wrap claude
-```
-
-What happens: Claude Code → Headroom (plain Anthropic `/v1/messages`) →
-**compresses** → LiteLLM converts to Vertex and calls Claude on Vertex → converts
-the answer back to Anthropic shape → Claude Code reads it.
-
-Caveats: the backend-name bug (Issue #1), the missing project env (Issue #4), and
-this path has **no automated tests** (Issue #8) — smoke-test it before relying on it.
-
----
-
-## How to verify compression is really happening
-
-1. Open the dashboard: `http://localhost:8787/dashboard` — "tokens saved" should
- climb as you use Claude Code.
-2. Or check response headers on a request: `x-headroom-tokens-before`,
- `x-headroom-tokens-after`, `x-headroom-tokens-saved`.
-3. Confirm it actually hit Vertex (proxy logs show a `vertex_ai/claude-…` model or
- a Vertex host, not `api.anthropic.com`).
-
-If `tokens-saved` is 0 on large prompts, compression isn't running — re-check the
-setup against the issues below.
-
----
-
-## Every issue we found (the full list)
-
-Severity: **BROKEN** = doesn't work; **GAP** = works only with manual workaround;
-**BUG** = wrong behavior in an edge case; **HOUSEKEEPING** = confusing but harmless.
-
-### 1. BROKEN — `--backend litellm-vertex` never reaches Vertex
-The backend name is turned into a provider by chopping off `litellm-`, so
-`litellm-vertex` becomes the provider `vertex`. But the Vertex integration is keyed
-on `vertex_ai`, not `vertex`. So Headroom falls back to a generic "unknown
-provider" mode: it builds the wrong model name (`vertex/claude-…` instead of
-`vertex_ai/claude-…`), **ignores the region**, and mishandles auth.
-**You must use `--backend litellm-vertex_ai`.** Worse: every help message and the
-`wrap` example tell users the broken `litellm-vertex`.
-*Where:* `providers/registry.py:174-178`, `backends/litellm.py:291,326-336,681-682`;
-help text at `cli/proxy.py:524`, `cli/wrap.py:3645`, `proxy/server.py:3913`.
-*Fix (small):* alias `vertex` → `vertex_ai` in `create_proxy_backend`, or add a
-`"vertex"` entry to the provider registry. Then fix the help text.
-
-### 2. GAP — `headroom wrap claude` has no Vertex support
-The `claude` wrap command has no `--backend` and no `--region` (the `aider` wrap
-command has both). It only ever sets `ANTHROPIC_BASE_URL`. So there's no flag to
-turn on a Vertex backend for Claude Code — you must pre-export env vars.
-*Where:* `cli/wrap.py:2780-2819` (vs `cli/wrap.py:3612,3615` for aider).
-*Fix:* add `--backend`/`--region` to `wrap claude`, mirroring `aider`.
-
-### 3. GAP — Vertex-mode Claude Code bypasses the proxy, and Headroom never sets the fix
-With `CLAUDE_CODE_USE_VERTEX=1`, Claude Code ignores `ANTHROPIC_BASE_URL` and goes
-straight to Google. There **is** a documented override — `ANTHROPIC_VERTEX_BASE_URL`
-— that points Claude Code's Vertex traffic at a gateway. But Headroom never sets it
-(0 references in the codebase). So the proxy has the right routes, but nothing
-connects the client to them automatically.
-*Where:* repo-wide grep for `ANTHROPIC_VERTEX_BASE_URL` = 0 hits.
-*Fix:* in a Vertex-aware `wrap claude`, set `ANTHROPIC_VERTEX_BASE_URL` to the proxy.
-
-### 4. GAP — the GCP project is never passed to LiteLLM
-For Setup B, Headroom passes the region to LiteLLM but never the project. You must
-export `VERTEXAI_PROJECT` (or `GOOGLE_CLOUD_PROJECT`) yourself or it fails.
-*Where:* `backends/litellm.py:682` sets only `vertex_location`.
-*Fix:* thread a project config/env through to the LiteLLM call.
-
-### 5. GAP — no placeholder API key for Claude Code
-With a custom `ANTHROPIC_BASE_URL`, Claude Code needs *an* `ANTHROPIC_API_KEY` to
-start, even though the proxy uses Google creds upstream. `wrap claude` never sets a
-placeholder, so the user must.
-*Where:* `cli/wrap.py:2984-2988`.
-*Fix:* set a placeholder key (or `ANTHROPIC_AUTH_TOKEN`) when launching.
-
-### 6. BUG — region/host mismatch
-Headroom pins the Vertex host to one region (default `us-central1`) but throws away
-the region in the client's request path. If your client targets, say,
-`europe-west1` while Headroom is on the default host, the request goes to the wrong
-region unless you set `--vertex-api-url` to match.
-*Where:* `copilot_auth.py:936` (host = base + path, no region reconciliation),
-`providers/proxy_routes.py:647` (path `location` is discarded), `registry.py:16`.
-*Fix:* derive the upstream host from the request path's `location`, or validate they match.
-
-### 7. HOUSEKEEPING — the Rust Vertex proxy is correct but unwired
-There's a second, Rust proxy (`crates/headroom-proxy/src/vertex/`) that compresses
-Vertex traffic correctly. But `headroom proxy` and `headroom wrap` run the **Python**
-server and never call it — it's a separate binary you'd run by hand. This is a
-frequent source of "but I thought Vertex compression was added" confusion: it was,
-in Rust, on a path nobody runs by default.
-*Where:* `crates/headroom-proxy/Cargo.toml` (`[[bin]]`), no Python→Rust bridge to it.
-*Fix:* either document that the Rust proxy is separate, or wire/retire it.
-
-### 8. GAP — no tests for the Vertex compression paths
-No test instantiates the LiteLLM Vertex backend with a mocked Vertex call, and the
-native-Vertex compression route isn't covered against a real Vertex shape. The
-translation code is correct by inspection, but unproven by CI.
-*Fix:* add a mocked round-trip test (Anthropic in → compressed → Vertex call asserted → Anthropic out).
-
-### 9. HOUSEKEEPING — stale Rust doc comment
-`crates/headroom-proxy/src/vertex/mod.rs:42-47` describes a "synthetic model
-injection" strategy the code no longer implements. Doc only; behavior is correct.
-
----
-
-## What's actually solid (so we don't over-correct)
-
-These were verified and are **correct**:
-
-- **Native Vertex `:rawPredict` for `publisher=anthropic` compresses** and preserves
- the Vertex body shape (keeps `anthropic_version`, never injects `model`).
- `proxy_routes.py:648`, `anthropic.py:604-606,1941-1949`.
-- **LiteLLM translation is real and complete** (with the `vertex_ai` provider):
- response is rebuilt into Anthropic shape (`backends/litellm.py:575-628`), streaming
- emits proper Anthropic SSE events (`streaming.py:1344-1472`, `litellm.py:736-947`),
- and tool calls round-trip both directions (`litellm.py:525-565,593-602`).
-- **Compression runs before the backend dispatch** (`anthropic.py:1671` then
- `:1781`), so the backend always gets the compressed body.
-- **Auth is forwarded correctly** on the native path — the client's Google token is
- passed through untouched (`copilot_auth.py:1156-1157`).
-
----
-
-## Recommended fixes, smallest-first
-
-1. **Fix the backend name (Issue #1)** — one-line alias `vertex`→`vertex_ai`, then
- correct the help text. This is the highest-impact, lowest-effort fix; it turns the
- *documented* command from broken to working.
-2. **Add `--backend`/`--region` to `wrap claude` (Issue #2)** — copy from `aider`.
-3. **Add a Vertex mode to `wrap claude` (Issues #3, #5)** — detect/set
- `ANTHROPIC_VERTEX_BASE_URL` → proxy, set a placeholder API key, and configure the
- proxy's Vertex upstream — so Setup A becomes one command.
-4. **Pass the GCP project (Issue #4)** and **reconcile the region/host (Issue #6).**
-5. **Add a mocked round-trip test (Issue #8).**
-6. **Decide the Rust proxy's fate (Issue #7)** — document-as-separate or wire it in.
-
-After #1–#3, the honest customer message becomes: *"`headroom wrap claude` works
-with Vertex out of the box."* Until then, it's *"works with a documented manual
-setup."*
diff --git a/docs/rtk-loop-weighting.md b/docs/rtk-loop-weighting.md
deleted file mode 100644
index e0b580a90..000000000
--- a/docs/rtk-loop-weighting.md
+++ /dev/null
@@ -1,125 +0,0 @@
-# Loop weighting in Headroom Learn + RTK-loop eval
-
-**Status:** proposed (branch `purva/rtk-loop-evals`).
-**Context:** Tejas asked for (1) an eval that reproduces the RTK loop, runs it
-through Headroom Learn, and checks the generated rule prevents re-triggering,
-and (2) a change so Headroom Learn gives loops more weight.
-
-## The gap
-
-Before this change, `headroom learn` ranked every recommendation by a single
-LLM-guessed `estimated_tokens_saved`, with a flat hardcoded `confidence`
-(`0.9`/`0.7`). It had **no notion of a loop**. Two consequences:
-
-1. **RTK re-fetch loops were invisible.** RTK truncates a shell command's
- output (`grep foo` → `grep foo | head -50`, see `docs/rtk-architecture.md`).
- When the truncation drops what the agent needed, the agent re-runs a
- *variant* to fetch more. **Those calls succeed** (`is_error=False`), so the
- analyzer's failure-oriented path ignored them — and `analyze()` even
- early-returned when a session had no failures and no events.
-
-2. **Even when surfaced, a loop ranked no higher than a one-off.** A pattern
- that wastes 5,000 tokens by repeating 6× was ranked the same as a one-time
- 200-token mistake, because ranking trusted the LLM's per-rule guess.
-
-## The change
-
-A new module `headroom/learn/loops.py`:
-
-- **`detect_loops(sessions)`** groups tool calls within a session by a
- *canonical signature* that collapses RTK re-fetch variants (it strips
- pagination/limit fragments — `head -N`, `-n N`, `LIMIT N`, … — and bare
- integers), then flags any signature repeated `>= 3×`. It classifies each as
- an `error-loop` or an `rtk-refetch-loop` and computes **measured** wasted
- tokens (error loops waste every call; re-fetch loops credit the first,
- legitimate call and count the N−1 redundant re-fetches).
-- **`format_loops_for_digest(loops)`** prepends a `=== Detected Loops (HIGHEST
- PRIORITY) ===` block to the LLM digest, with each loop's measured waste.
-- **`apply_loop_weighting(recs, loops)`** raises a matching recommendation's
- `estimated_tokens_saved` to at least the loop's measured waste and tags it
- `is_loop_guardrail=True`. Because measured loop waste aggregates many
- repetitions, this reliably lifts loop guardrails above one-offs **without
- trusting the LLM** to have weighted them.
-
-Wiring in `analyzer.py`: loops are detected up front (so a no-failure re-fetch
-loop is now a first-class reason to analyze, fixing the early-return), surfaced
-in the digest, the system prompt makes loops the #1 priority, and weighting +
-re-sort run after parsing.
-
-### Why measured-waste weighting (vs. relying on the LLM's estimate)
-
-The LLM's `estimated_tokens_saved` is a free-form guess, not grounded in the
-transcript, so ranking on it alone is unreliable. Deriving the weight from
-*observed repetition* — the real output bytes summed across the repeated calls
-— is deterministic and auditable: the boost equals waste we actually counted.
-
-Honest caveat on the current implementation: we do BOTH — the digest also tells
-the model the measured waste and asks it to rank loops first. In real-LLM runs
-that prompt hint is doing much of the work (the model echoes the measured
-figure), while the post-hoc `apply_loop_weighting` boost is fuzzy-match-based
-and does not always fire. Making the measured-waste boost the deterministic,
-load-bearing mechanism — independent of the model's wording — is tracked as
-follow-up.
-
-## The eval
-
-`benchmarks/rtk_loop_learn_eval.py` (CI wrapper: `tests/test_learn/
-test_rtk_loop_eval.py`). Two phases:
-
-- **Phase 1 — trigger + learn:** reproduce the RTK re-fetch loop, run the
- analyzer, and score the guardrail: produced? ranked first? names the command?
- prescribes a fix? does its savings estimate reflect measured waste?
-- **Phase 2 — guardrail holds:** inject that guardrail as a prior pattern, feed
- a session where the agent *followed* it (one full-output fetch, no loop), and
- assert no new loop guardrail is re-emitted — i.e. once the rule exists and is
- honored, the loop does not re-trigger.
-
-Runs deterministically in CI (stubbed analyzer LLM) and against a real LLM with
-`--real` — via an API key or an installed CLI backend (`HEADROOM_LEARN_CLI=claude`).
-
-```
-$ python benchmarks/rtk_loop_learn_eval.py
- [PASS] loop_detected (1 loop(s), ~5,005 tok wasted)
- [PASS] guardrail_produced
- [PASS] ranked_first
- [PASS] names_command
- [PASS] prescribes_fix
- [PASS] weight_reflects_waste
- [PASS] guardrail_holds
- RESULT: PASS — loop caught, guardrail ranked first, and it holds.
-```
-
-### Real-LLM run (claude CLI backend)
-
-Running `--real` against the actual analyzer model proved the weighting works
-end-to-end *and* caught an over-brittle check. The model produced this rule,
-ranked **first** with the measured 5,005-token weight:
-
-> **Commands** — When grepping logs (or any large file), never loop with
-> increasing `| head -N` limits — tool output is capped at ~4 KB regardless of
-> N, so repeated attempts return identical bytes. Instead: redirect to a temp
-> file (`grep ... > /tmp/out.txt`) then read it, or use `grep -c` first…
-
-That rule is *more general* than the fixture's — it identifies the looping
-command (`grep` + `head -N`) without echoing the incidental search string. An
-early `names_command` check required the literal "TimeoutError" and wrongly
-failed; the real run exposed it, and the check now verifies the rule names the
-looping command, not an incidental literal. This is exactly why the governance
-treats real output — not mocks — as proof.
-
-## Honest limitations / open questions for review
-
-- **Phase 2 is a non-recurrence check, not a live agent.** It proves the
- guardrail is *adequate* (names the command, prescribes the fix) and that a
- guarded, non-looping session produces no new rule. It does **not** run a real
- agent that obeys the rule end-to-end — that needs a live agent harness and is
- the natural next step if we want a stronger claim.
-- **Loop signature is heuristic.** The pagination-stripping regex covers the
- common RTK truncation shapes (`head`/`tail`/`-n`/`LIMIT`/`OFFSET`); exotic
- truncations may not collapse to one signature. Easy to extend as we see real
- transcripts.
-- **`min_occurrences = 3`** treats a single retry as not-yet-a-loop. If we have
- data showing 2× re-fetches are already worth a rule, lower it.
-- **Matching rules to loops is fuzzy** (token overlap between the rule text and
- the looped command). A structured loop→rule id from the LLM would be tighter
- but adds prompt/parse surface.
diff --git a/docs/spec/001-vision.md b/docs/spec/001-vision.md
deleted file mode 100644
index 46860cb04..000000000
--- a/docs/spec/001-vision.md
+++ /dev/null
@@ -1,109 +0,0 @@
-# 001. Vision
-
-**Status:** done
-
-## What Headroom Is
-
-Headroom is a **context compression proxy** for AI provider APIs. It sits between AI coding tools (Claude Code, Copilot, Codex, etc.) and provider APIs (OpenAI, Anthropic, Google, Cohere), compressing context before it reaches the provider to reduce token usage and costs.
-
-### Core Value Proposition
-
-1. **Token Savings** — 30-90% reduction in tokens sent to providers through semantic compression
-2. **Cost Reduction** — Lower API costs via compression before provider transmission
-3. **Context Window Extension** — Effective 2-10x larger context windows via compression
-4. **Privacy** — Prompts never logged by default; all processing stays local
-5. **Compatibility** — Works with existing AI coding tools via proxy or SDK
-
-### What Headroom Is Not
-
-- A model provider — Headroom does not host or run AI models
-- A data store — No prompt storage by default (local SQLite is optional)
-- A logging service — No prompt logging by default
-- A billing service — Usage tracking is internal only
-
----
-
-## Design Principles
-
-### 1. Local-First Privacy
-
-**Principle:** Prompt data never leaves the proxy unless explicitly exported.
-
-**Implications:**
-- All compression happens locally or through the proxy
-- No third-party data sharing
-- Optional SQLite storage with user control
-- Export must be explicitly configured
-
-### 2. Transparent Compression
-
-**Principle:** Users see exactly what is being compressed and why.
-
-**Implications:**
-- Full observability into compression decisions
-- Metrics and logs show savings
-- Transform audit trail available
-- Dashboard visualizes all compression activity
-
-### 3. Composable Integration
-
-**Principle:** Headroom works alongside existing tools without requiring workflow changes.
-
-**Implications:**
-- Proxy mode: route traffic through Headroom
-- SDK mode: integrate into custom applications
-- CLI mode: wrap existing AI commands
-- Agent mode: MCP/LiteLLM/ASGI integrations
-
-### 4. Production-Ready Defaults
-
-**Principle:** Safe defaults that work out of the box.
-
-**Implications:**
-- Compression enabled by default
-- No logging by default
-- Cache enabled by default
-- Learning disabled by default
-
----
-
-## Core Guarantees
-
-| Guarantee | Description |
-|-----------|-------------|
-| **Never logs prompts** | No prompt data in logs unless exporter configured |
-| **Never leaves proxy** | All data stays local unless explicitly exported |
-| **Composable** | Works alongside Claude Code, Copilot, Codex, etc. |
-| **Transparent** | Full observability into compression decisions |
-| **Type-safe** | Full type annotations, mypy compliance |
-| **Test-covered** | Unit, integration, and E2E test coverage |
-
----
-
-## Target Users
-
-| User | Use Case |
-|------|----------|
-| **Individual Developers** | Reduce API costs for personal AI coding |
-| **Development Teams** | Shared compression with learn plugins |
-| **Enterprises** | Self-hosted deployment with security guarantees |
-| **Plugin Authors** | Extend Headroom via plugin ABI |
-
----
-
-## Success Metrics
-
-| Metric | Target | Measurement |
-|--------|--------|-------------|
-| Token savings | >30% | (tokens_before - tokens_after) / tokens_before |
-| Compression latency | <50ms | Per-request proxy overhead |
-| Cache hit rate | >60% | cache_hits / total_requests |
-| Zero data exfiltration | 100% | No prompts in logs by default |
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial vision document |
diff --git a/docs/spec/002-architecture.md b/docs/spec/002-architecture.md
deleted file mode 100644
index 742558d1f..000000000
--- a/docs/spec/002-architecture.md
+++ /dev/null
@@ -1,339 +0,0 @@
-# 002. Architecture
-
-**Status:** done
-
-## System Overview
-
-Headroom is a context compression proxy for LLM applications, featuring intelligent transforms, semantic caching, and CCR (Compress-Cache-Retrieve) architecture.
-
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ Headroom │
-├─────────────────────────────────────────────────────────────────┤
-│ │
-│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │
-│ │ Proxy │ │ SDK │ │ Wrap │ │ CCR MCP │ │
-│ │ Server │ │ (Python) │ │ CLI │ │ Server │ │
-│ │ (8787) │ │ │ │ │ │ │ │
-│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬──────┘ │
-│ │ │ │ │ │
-│ ┌────┴──────────────┴──────────────┴─────────────────┴──────┐ │
-│ │ Compression Layer │ │
-│ │ ┌────────────┐ ┌────────────┐ ┌────────────────────┐ │ │
-│ │ │SmartCrusher│ │CacheAligner│ │ RollingWindow │ │ │
-│ │ │(JSON array │ │(Prefix │ │ (Token cap) │ │ │
-│ │ │ crush) │ │ stabilization)│ │ │ │ │
-│ │ └────────────┘ └────────────┘ └────────────────────┘ │ │
-│ └───────────────────────────────────────────────────────────┘ │
-│ │
-│ ┌───────────────────────────────────────────────────────────┐ │
-│ │ Learn System │ │
-│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────────────┐ │ │
-│ │ │Claude │ │Codex │ │Gemini │ │ Generic │ │ │
-│ │ │Scanner │ │Scanner │ │Scanner │ │ Writer │ │ │
-│ │ └────────┘ └────────┘ └────────┘ └────────────────┘ │ │
-│ └───────────────────────────────────────────────────────────┘ │
-│ │
-│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
-│ │ Dashboard │ │ CCR │ │ TOIN │ │
-│ │ (HTML) │ │ (Compress- │ │ (Telemetry-based │ │
-│ │ │ │ Cache- │ │ Intelligence) │ │
-│ │ │ │ Retrieve) │ │ │ │
-│ └──────────────┘ └──────────────┘ └──────────────────────┘ │
-│ │
-└─────────────────────────────────────────────────────────────────┘
-```
-
----
-
-## Component Specifications
-
-### Proxy Server (`headroom/proxy/server.py`)
-
-**`HeadroomProxy` class** — Main proxy server (default port 8787):
-
-```python
-class HeadroomProxy:
- def __init__(self, config: ProxyConfig) -> None:
- self.config = config
- self.compression_cache = CompressionCache(...)
- self.transform_pipeline = [...]
- self.ccr_store = CompressionStore(...)
- self.prefix_freeze = PrefixFreeze(...)
-
- async def startup(self) -> None: ...
- async def shutdown(self) -> None: ...
- async def handle_request(request: Request) -> Response: ...
-```
-
-**`ProxyConfig` dataclass** (from `headroom/models/config.py`):
-```python
-@dataclass
-class ProxyConfig:
- store_url: str = "sqlite:///headroom.db"
- default_mode: HeadroomMode = HeadroomMode.AUDIT
- tool_crusher: ToolCrusherConfig = field(default_factory=ToolCrusherConfig)
- smart_crusher: SmartCrusherConfig = field(default_factory=SmartCrusherConfig)
- cache_aligner: CacheAlignerConfig = field(default_factory=CacheAlignerConfig)
- rolling_window: RollingWindowConfig = field(default_factory=RollingWindowConfig)
- cache_optimizer: CacheOptimizerConfig = field(default_factory=CacheOptimizerConfig)
- ccr: CCRConfig = field(default_factory=CCRConfig)
- prefix_freeze: PrefixFreezeConfig = field(default_factory=PrefixFreezeConfig)
-```
-
-**`HeadroomMode` enum** (actual modes):
-```python
-class HeadroomMode(str, Enum):
- AUDIT = "audit" # Observe only, no modifications
- OPTIMIZE = "optimize" # Apply deterministic transforms
- SIMULATE = "simulate" # Return transform plan without API call
-```
-
-**HTTP Endpoints (actual):**
-| Endpoint | Method | Description |
-|----------|--------|-------------|
-| `/v1/messages` | POST | Proxy chat completions |
-| `/v1/embeddings` | POST | Proxy embeddings |
-| `/health` | GET | Basic health check |
-| `/livez` | GET | Liveness check |
-| `/readyz` | GET | Readiness check |
-| `/metrics` | GET | Prometheus metrics |
-| `/v1/compress` | POST | Direct compression |
-| `/v1/retrieve` | POST | CCR retrieval |
-| `/stats` | GET | Compression statistics |
-
-**Default Port:** 8787 (not 8765)
-
----
-
-### Python SDK (`headroom/client.py`)
-
-**`HeadroomClient` class:**
-```python
-class HeadroomClient:
- def __init__(
- self,
- api_key: str | None = None,
- base_url: str = "http://localhost:8787",
- timeout: float = 60.0,
- fallback: bool = True,
- retries: int = 3,
- ) -> None:
- pass
-
- async def compress(
- self,
- messages: list[dict],
- options: CompressOptions | None = None,
- ) -> CompressResult: ...
-
- async def get_stats(self) -> Stats: ...
-
- async def close(self) -> None: ...
-```
-
----
-
-### Wrap CLI (`headroom/cli/wrap.py`)
-
-**Commands (all use default port 8787):**
-- `claude` — Wrap Claude Code
-- `copilot` — Wrap GitHub Copilot
-- `codex` — Wrap OpenAI Codex
-- `aider` — Wrap Aider
-- `cursor` — Wrap Cursor
-- `openclaw` — Wrap OpenClaw
-
-```python
-@click.command()
-@click.option("--port", "-p", default=8787, help="Proxy port")
-@click.argument("command", nargs=-1, required=True)
-def wrap(command: tuple, port: int) -> None:
- """Wrap a command with Headroom proxy."""
- ...
-```
-
----
-
-### CCR MCP Server (`headroom/ccr/mcp_server.py`)
-
-Model Context Protocol server for Claude Desktop integration.
-
-```python
-class CCRMcpServer:
- async def compress(messages: list[dict]) -> CompressResult: ...
- async def retrieve(hash: str, query: str) -> RetrieveResult: ...
- async def get_stats() -> Stats: ...
-```
-
-**MCP Tools:**
-- `headroom_compress` — Compress messages
-- `headroom_retrieve` — Retrieve cached content
-- `headroom_stats` — Get statistics
-
----
-
-### ASGI Middleware (`headroom/integrations/asgi.py`)
-
-ASGI-compatible middleware for Python web frameworks.
-
-```python
-class HeadroomMiddleware:
- def __init__(
- self,
- app: ASGIApplication,
- headroom_url: str = "http://localhost:8787",
- ) -> None: ...
-```
-
----
-
-### LiteLLM Callback (`headroom/integrations/litellm_callback.py`)
-
-Callback for LiteLLM proxy integration.
-
-```python
-class LiteLLMCallback:
- def on_completion(self, completion_response: dict) -> dict: ...
- def on_error(self, error: Exception) -> None: ...
-```
-
----
-
-## Compression Layer (`headroom/transforms/`)
-
-### SmartCrusher (`headroom/transforms/smart_crusher.py`)
-
-Statistical JSON array compression preserving schema.
-
-```python
-class SmartCrusher:
- def __init__(self, config: SmartCrusherConfig) -> None: ...
- def crush(self, content: str, context: TransformContext) -> TransformResult: ...
-```
-
-### CacheAligner (`headroom/transforms/cache_aligner.py`)
-
-Prefix stabilization for provider cache optimization.
-
-```python
-class CacheAligner:
- def __init__(self, config: CacheAlignerConfig) -> None: ...
- def align(self, messages: list[dict]) -> TransformResult: ...
-```
-
-### RollingWindow (`headroom/transforms/rolling_window.py`)
-
-Rolling window token cap.
-
-```python
-class RollingWindow:
- def __init__(self, config: RollingWindowConfig) -> None: ...
- def apply(self, messages: list[dict]) -> TransformResult: ...
-```
-
-### ContentRouter (`headroom/transforms/content_router.py`)
-
-Routes content to appropriate compressor based on type.
-
-```python
-class ContentRouter:
- def route(self, messages: list[dict]) -> list[dict]: ...
-```
-
----
-
-## Learn System (`headroom/learn/`)
-
-**`LearnPlugin` interface** (actual):
-
-```python
-class LearnPlugin(ConversationScanner):
- @property
- def name(self) -> str: ...
- @property
- def display_name(self) -> str: ...
- @abstractmethod
- def detect(self) -> bool: ...
- @abstractmethod
- def discover_projects(self) -> list[ProjectInfo]: ...
- @abstractmethod
- def scan_project(self, project: ProjectInfo, max_workers: int = 1) -> list[SessionData]: ...
- @abstractmethod
- def create_writer(self) -> ContextWriter: ...
-```
-
-**Scanner implementations:**
-- `ClaudeScanner` — Claude Code session parsing
-- `CodexScanner` — Codex session parsing
-- `CursorScanner` — Cursor session parsing
-
----
-
-## CCR System (`headroom/ccr/`)
-
-CCR (Compress-Cache-Retrieve) makes compression reversible.
-
-```python
-class CompressionStore:
- def store(self, hash: str, original: str, metadata: dict) -> None: ...
- def retrieve(self, hash: str) -> str | None: ...
-
-class ContextTracker:
- def track(self, session_id: str, messages: list[dict]) -> CCRContext: ...
- def get_context(self, session_id: str) -> CCRContext | None: ...
-```
-
-**CCRConfig fields:**
-- `enabled: bool = True`
-- `store_max_entries: int = 1000`
-- `store_ttl_seconds: int = 300`
-- `inject_retrieval_marker: bool = True`
-- `feedback_enabled: bool = True`
-
----
-
-## TOIN (`headroom/telemetry/toin.py`)
-
-Tool Output Intelligence Network — telemetry-based compression hints.
-
-```python
-class TOINCollector:
- def record_retrieval(self, tool_name: str, field: str, query: str) -> None: ...
- def get_hints(self, tool_name: str) -> dict[str, float]: ...
-```
-
----
-
-## Dashboard (`headroom/dashboard/`)
-
-Simple HTML dashboard served by the proxy.
-
-```python
-def get_dashboard_html() -> str:
- """Load the dashboard HTML template."""
- return (TEMPLATES_DIR / "dashboard.html").read_text()
-```
-
----
-
-## Data Flow
-
-```
-Client → Headroom Proxy → [ContentRouter] → [SmartCrusher/CacheAligner/RollingWindow]
- │ │ │
- │ [CCR Store] ←───────────────────────┘
- │
- │ [Telemetry/Metrics]
- │
- ▼
- Provider API
-```
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial architecture document |
diff --git a/docs/spec/003-adrs.md b/docs/spec/003-adrs.md
deleted file mode 100644
index d18b0a30c..000000000
--- a/docs/spec/003-adrs.md
+++ /dev/null
@@ -1,164 +0,0 @@
-# 003. Architecture Decision Records
-
-**Status:** done
-
-## ADR-001: Why a Proxy Instead of SDK Injection
-
-**Context:** Headroom could be implemented as an SDK that users import, or as a network proxy.
-
-**Decision:** Network proxy with SDK for complex use cases.
-
-**Rationale:**
-- Works with any HTTP client without code changes
-- No need to modify existing applications
-- Centralized configuration
-- Can intercept all traffic, not just explicit SDK calls
-
-**Consequences:**
-- Requires running a separate service (or using wrap mode)
-- Network latency added (~5-10ms)
-- Need to handle connection pooling
-
----
-
-## ADR-002: Why SQLite for Local Storage
-
-**Context:** Headroom needs to store compression cache, savings history, memory graphs.
-
-**Decision:** SQLite with optional external stores (Redis, PostgreSQL, etc.).
-
-**Rationale:**
-- Zero configuration — works out of the box
-- Single file, easy backup
-- ACID compliant transactions
-- Good performance for single-node deployments
-- sqlite-vec for vector similarity search
-- FTS5 for full-text search
-
-**Consequences:**
-- Not distributed by default
-- Must configure external stores for multi-node deployments
-- Cloud-hosted databases require additional setup
-
----
-
-## ADR-003: Why CCR (Compress-Cache-Retrieve) Pattern
-
-**Context:** Compression alone doesn't leverage repeated context patterns.
-
-**Decision:** CCR pattern for semantic caching and retrieval.
-
-**Rationale:**
-- Semantic similarity enables cache hits across different phrasings
-- Retrieves relevant compressed context for new requests
-- Reduces provider API calls for similar patterns
-- Enables cross-session learning
-
-**Consequences:**
-- Requires storing compressed content
-- Semantic hashing adds latency
-- Cache invalidation is complex
-
----
-
-## ADR-004: Why Per-Agent Plugins for Learn System
-
-**Context:** Different AI agents (Claude, Codex, Gemini) have different context patterns.
-
-**Decision:** Plugin architecture with agent-specific analyzers.
-
-**Rationale:**
-- Tailored compression per agent type
-- Extensible for new agents
-- Clear interface contract
-- Independent versioning
-
-**Consequences:**
-- Plugin API must be stable
-- Multiple plugins may conflict
-- Testing complexity increases
-
----
-
-## ADR-005: Why ONNX for TOIN
-
-**Context:** TOIN (Tenant-specific ONNX) requires ML inference.
-
-**Decision:** Use ONNX Runtime for portable ML inference.
-
-**Rationale:**
-- Hardware acceleration (CPU/GPU)
-- Cross-platform (Windows, Linux, macOS)
-- Model interchange format
-- Single model file deployment
-
-**Consequences:**
-- ONNX model files must be hosted
-- Version compatibility issues
-- Larger package size
-
----
-
-## ADR-006: Why Python for Core Implementation
-
-**Context:** Language choice for the main implementation.
-
-**Decision:** Python as the primary language.
-
-**Rationale:**
-- Primary language for AI/ML ecosystem
-- Easy integration with provider APIs
-- Rich async ecosystem (asyncio, httpx)
-- Strong type annotation support (mypy)
-- Good testing infrastructure
-
-**Consequences:**
-- GIL limitations for threading
-- Slower than compiled languages
-- Type checking adds build time
-
----
-
-## ADR-007: Why TypeScript SDK for npm
-
-**Context:** JavaScript/TypeScript ecosystem for frontend integrations.
-
-**Decision:** Official TypeScript SDK published to npm.
-
-**Rationale:**
-- Node.js compatibility
-- TypeScript type safety
-- Wide adoption in AI tooling
-- ESM and CommonJS support
-
-**Consequences:**
-- Dual language maintenance
-- Must keep SDK in sync with Python core
-- Additional CI/CD pipeline needed
-
----
-
-## ADR-008: Why HierarchicalMemory with SQLite + vec + FTS5
-
-**Context:** Memory system needs to store, search, and reason over context.
-
-**Decision:** Hierarchical memory using SQLite + sqlite-vec + FTS5.
-
-**Rationale:**
-- SQLite: ACID transactions, single file
-- sqlite-vec: Vector similarity for semantic search
-- FTS5: Full-text search for keyword matching
-- Hierarchical: Session < Conversation < Message structure
-
-**Consequences:**
-- Memory hierarchy adds complexity
-- SQLite limitations for concurrent writes
-- Vector search accuracy depends on embedding quality
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial ADRs |
diff --git a/docs/spec/004-domain-model.md b/docs/spec/004-domain-model.md
deleted file mode 100644
index 450ba15cb..000000000
--- a/docs/spec/004-domain-model.md
+++ /dev/null
@@ -1,363 +0,0 @@
-# 004. Domain Model
-
-**Status:** done
-
-## Core Entities
-
-### Session
-
-A session represents a conversation context between a user and an AI agent.
-
-**Fields:**
-- `session_id: UUID` — Unique identifier
-- `created_at: datetime` — Creation time
-- `updated_at: datetime` — Last modification
-- `agent_type: str` — "claude", "codex", "gemini", etc.
-- `messages: list[Message]` — Conversation history
-- `metadata: dict` — Agent-specific metadata
-
-```python
-@dataclass
-class Session:
- session_id: UUID
- created_at: datetime
- updated_at: datetime
- agent_type: str
- messages: list[Message] = field(default_factory=list)
- metadata: dict = field(default_factory=dict)
-```
-
----
-
-### Message
-
-A single message in a conversation.
-
-**Fields:**
-- `message_id: UUID` — Unique identifier
-- `session_id: UUID` — Associated session
-- `role: str` — "user", "assistant", "system", "tool"
-- `content: str` — Message content
-- `tokens: int | None` — Token count (if known)
-- `created_at: datetime` — Creation time
-- `attachments: list[Attachment] | None` — Optional attachments
-
-```python
-@dataclass
-class Message:
- message_id: UUID
- session_id: UUID
- role: str
- content: str
- tokens: int | None = None
- created_at: datetime = field(default_factory=datetime.utcnow)
- attachments: list[Attachment] | None = None
-```
-
----
-
-### Request
-
-A single API request to an AI provider.
-
-**Fields:**
-- `request_id: UUID` — Unique identifier
-- `session_id: UUID` — Associated session
-- `provider: str` — "anthropic", "openai", "google", etc.
-- `model: str` — Model identifier
-- `input_tokens: int` — Tokens in request
-- `output_tokens: int` — Tokens in response
-- `compressed: bool` — Whether compression was applied
-- `savings_percentage: float` — Savings as decimal
-- `timestamp: datetime` — Request time
-- `duration_ms: int` — Request duration
-- `error: str | None` — Error message if failed
-
-```python
-@dataclass
-class Request:
- request_id: UUID
- session_id: UUID
- provider: str
- model: str
- input_tokens: int
- output_tokens: int
- compressed: bool = False
- savings_percentage: float = 0.0
- timestamp: datetime = field(default_factory=datetime.utcnow)
- duration_ms: int = 0
- error: str | None = None
-```
-
----
-
-### Savings
-
-A record of token savings from a compressed request.
-
-**Fields:**
-- `savings_id: UUID` — Unique identifier
-- `request_id: UUID` — Associated request
-- `original_tokens: int` — Tokens before compression
-- `compressed_tokens: int` — Tokens after compression
-- `savings_percentage: float` — Savings as decimal
-- `savings_amount: float` — Absolute token savings
-- `provider: str` — Provider name
-- `model: str` — Model used
-- `window_start: datetime | None` — Billing window start
-
-```python
-@dataclass
-class Savings:
- savings_id: UUID
- request_id: UUID
- original_tokens: int
- compressed_tokens: int
- savings_percentage: float
- savings_amount: float
- provider: str
- model: str
- window_start: datetime | None = None
-```
-
----
-
-### CacheEntry
-
-A cached compression result.
-
-**Fields:**
-- `cache_key: str` — Hash of input
-- `input_hash: str` — Hash of original content
-- `output: str` — Compressed output
-- `compression_type: str` — "semantic", "summary", "ccr"
-- `tokens_before: int` — Tokens before compression
-- `tokens_after: int` — Tokens after compression
-- `created_at: datetime` — Creation time
-- `ttl: int` — Time to live in seconds
-- `hit_count: int` — Number of cache hits
-- `last_accessed: datetime` — Last access time
-
-```python
-@dataclass
-class CacheEntry:
- cache_key: str
- input_hash: str
- output: str
- compression_type: str
- tokens_before: int
- tokens_after: int
- created_at: datetime = field(default_factory=datetime.utcnow)
- ttl: int = 3600
- hit_count: int = 0
- last_accessed: datetime = field(default_factory=datetime.utcnow)
-```
-
----
-
-### ToolDefinition
-
-A tool/function definition available to an AI agent.
-
-**Fields:**
-- `tool_id: UUID` — Unique identifier
-- `name: str` — Tool name
-- `description: str` — Tool description
-- `parameters: dict` — JSON Schema for parameters
-- `provider: str` — Provider that defined this tool
-- `created_at: datetime` — Creation time
-
-```python
-@dataclass
-class ToolDefinition:
- tool_id: UUID
- name: str
- description: str
- parameters: dict
- provider: str
- created_at: datetime = field(default_factory=datetime.utcnow)
-```
-
----
-
-### PluginInterface
-
-A learn plugin for agent-specific compression.
-
-**Fields:**
-- `plugin_id: UUID` — Unique identifier
-- `name: str` — Plugin name
-- `agent_type: str` — Supported agent type
-- `version: str` — Plugin version
-- `entry_point: str` — Import path or file path
-- `config: dict` — Plugin configuration
-- `enabled: bool` — Whether plugin is active
-
-```python
-@dataclass
-class PluginInterface:
- plugin_id: UUID
- name: str
- agent_type: str
- version: str
- entry_point: str
- config: dict = field(default_factory=dict)
- enabled: bool = True
-```
-
----
-
-### TOINTenant
-
-A tenant configuration for TOIN (Tenant-specific ONNX).
-
-**Fields:**
-- `tenant_id: UUID` — Unique identifier
-- `name: str` — Tenant name
-- `model_path: str | Path` — Path to ONNX model
-- `model_version: str` — Model version
-- `config: dict` — Tenant-specific configuration
-- `created_at: datetime` — Creation time
-- `updated_at: datetime` — Last modification
-
-```python
-@dataclass
-class TOINTenant:
- tenant_id: UUID
- name: str
- model_path: str | Path
- model_version: str
- config: dict = field(default_factory=dict)
- created_at: datetime = field(default_factory=datetime.utcnow)
- updated_at: datetime = field(default_factory=datetime.utcnow)
-```
-
----
-
-### CCRContext
-
-Claude Code Relay context tracking.
-
-**Fields:**
-- `context_id: UUID` — Unique identifier
-- `session_id: UUID` — Associated session
-- `agent_type: str` — "claude", "claude-desktop", etc.
-- `window_start: datetime` — Context window start
-- `window_end: datetime` — Context window end
-- `messages_tracked: int` — Number of messages
-- `compressed_content: str | None` — Compressed context
-
-```python
-@dataclass
-class CCRContext:
- context_id: UUID
- session_id: UUID
- agent_type: str
- window_start: datetime
- window_end: datetime
- messages_tracked: int = 0
- compressed_content: str | None = None
-```
-
----
-
-### SubscriptionState
-
-Subscription/quota tracking state.
-
-**Fields:**
-- `subscription_id: UUID` — Unique identifier
-- `provider: str` — Provider name
-- `plan_name: str` — Plan name
-- `window_start: datetime` — Billing window start
-- `window_end: datetime` — Billing window end
-- `max_tokens: int | None` — Maximum tokens in window
-- `tokens_used: int` — Tokens used in window
-- `tokens_remaining: int | None` — Tokens remaining
-- `is_active: bool` — Whether subscription is active
-- `last_updated: datetime` — Last update time
-
-```python
-@dataclass
-class SubscriptionState:
- subscription_id: UUID
- provider: str
- plan_name: str
- window_start: datetime
- window_end: datetime
- max_tokens: int | None = None
- tokens_used: int = 0
- tokens_remaining: int | None = None
- is_active: bool = True
- last_updated: datetime = field(default_factory=datetime.utcnow)
-```
-
----
-
-## Relationships
-
-```
-Session 1───N Message
-Session 1───N Request
-Request 1───1 Savings
-Request 1───1 CacheEntry
-Session 1───N CCRContext
-TOINTenant 1───N Request
-ToolDefinition N───N Session (via tool_use)
-```
-
----
-
-## Value Objects
-
-### CompressResult
-
-```python
-@dataclass
-class CompressResult:
- messages: list[dict]
- tokens_before: int
- tokens_after: int
- tokens_saved: int
- compression_ratio: float
- transforms_applied: list[str]
- content_type: ContentType
- model: str | None
- ccr_hash: str | None
- cached: bool
-```
-
-### ContentType (Enum)
-
-```python
-class ContentType(Enum):
- PLAINTEXT = "text/plain"
- MARKDOWN = "text/markdown"
- JSON = "application/json"
- HTML = "text/html"
- XML = "text/xml"
- PYTHON = "text/x-python"
- JAVASCRIPT = "text/javascript"
- TYPESCRIPT = "text/typescript"
- YAML = "text/yaml"
- MARKDOWN_SNAPSHOT = "text/markdown-snapshot"
- UNKNOWN = "application/octet-stream"
-```
-
-### ProxyMode (Enum)
-
-```python
-class ProxyMode(Enum):
- PASSTHROUGH = "passthrough"
- COMPRESS = "compress"
- LEARN = "learn"
- DETACHED = "detached"
-```
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial domain model |
diff --git a/docs/spec/005-integrations.md b/docs/spec/005-integrations.md
deleted file mode 100644
index 8ba09b538..000000000
--- a/docs/spec/005-integrations.md
+++ /dev/null
@@ -1,353 +0,0 @@
-# 005. Integrations
-
-**Status:** done
-
-## Supported Agents
-
-### Claude (`headroom/learn/plugins/claude/`)
-
-**Plugin:** `ClaudeLearnPlugin`
-
-**Capabilities:**
-- Session branch comparison
-- Token headroom mode detection
-- Tool use tracking
-- Multi-modal support (images)
-
-**Interface:**
-```python
-class ClaudeLearnPlugin(LearnPlugin, ConversationScanner):
- @property
- def name(self) -> str:
- return "claude"
-
- @property
- def display_name(self) -> str:
- return "Claude Code"
-
- def detect(self) -> bool:
- """Check if Claude Code has data on the current machine."""
- pass
-
- def discover_projects(self) -> list[ProjectInfo]:
- """Discover all projects with Claude sessions."""
- pass
-
- def scan_project(self, project: ProjectInfo, max_workers: int = 1) -> list[SessionData]:
- """Scan all sessions for a project."""
- pass
-
- def create_writer(self) -> ContextWriter:
- """Return Claude-specific ContextWriter."""
- pass
-```
-
-**Configuration:**
-```bash
-HEADROOM_LEARN_CLI=claude
-```
-
----
-
-### Codex (OpenAI) (`headroom/learn/plugins/codex/`)
-
-**Plugin:** `CodexLearnPlugin`
-
-**Capabilities:**
-- Rate limit handling
-- Code completion optimization
-- Batch request support
-
-**Interface:**
-```python
-class CodexLearnPlugin(LearnPlugin, ConversationScanner):
- @property
- def name(self) -> str:
- return "codex"
-
- @property
- def display_name(self) -> str:
- return "OpenAI Codex"
-
- def detect(self) -> bool:
- pass
-
- def discover_projects(self) -> list[ProjectInfo]:
- pass
-
- def scan_project(self, project: ProjectInfo, max_workers: int = 1) -> list[SessionData]:
- pass
-
- def create_writer(self) -> ContextWriter:
- pass
-```
-
-**Configuration:**
-```bash
-HEADROOM_LEARN_CLI=codex
-```
-
----
-
-### Gemini (Google) (`headroom/learn/plugins/gemini/`)
-
-**Plugin:** `GeminiLearnPlugin`
-
-**Capabilities:**
-- Multimodal inputs
-- Function calling support
-- Context caching API
-
-**Interface:**
-```python
-class GeminiLearnPlugin(LearnPlugin, ConversationScanner):
- @property
- def name(self) -> str:
- return "gemini"
-
- @property
- def display_name(self) -> str:
- return "Google Gemini"
-
- def detect(self) -> bool:
- pass
-
- def discover_projects(self) -> list[ProjectInfo]:
- pass
-
- def scan_project(self, project: ProjectInfo, max_workers: int = 1) -> list[SessionData]:
- pass
-
- def create_writer(self) -> ContextWriter:
- pass
-```
-
-**Configuration:**
-```bash
-HEADROOM_LEARN_CLI=gemini
-```
-
----
-
-## Integration Points
-
-### LiteLLM Callback (`headroom/integrations/litellm_callback.py`)
-
-LiteLLM proxy callback for integrating with LiteLLM-based setups.
-
-**`LiteLLMCallback` class:**
-```python
-class LiteLLMCallback:
- def __init__(
- self,
- headroom_url: str = "http://localhost:8787",
- api_key: str | None = None,
- ) -> None:
- self.headroom_url = headroom_url
- self.api_key = api_key
-
- def on_completion(self, completion_response: dict) -> dict:
- """Called after completion. Can modify response."""
- pass
-
- def on_error(self, error: Exception) -> None:
- """Called on error."""
- pass
-```
-
-**Usage:**
-```python
-from headroom.integrations import LiteLLMCallback
-
-callback = LiteLLMCallback(headroom_url="http://localhost:8787")
-# Register with LiteLLM proxy
-```
-
----
-
-### ASGI Middleware (`headroom/integrations/asgi.py`)
-
-ASGI-compatible middleware for Python web frameworks (FastAPI, Starlette, etc.).
-
-**`HeadroomMiddleware` class:**
-```python
-class HeadroomMiddleware:
- def __init__(
- self,
- app: ASGIApplication,
- headroom_url: str = "http://localhost:8787",
- mode: ProxyMode = ProxyMode.COMPRESS,
- ) -> None:
- self.app = app
- self.headroom_url = headroom_url
- self.mode = mode
-
- async def __call__(
- self,
- scope: Scope,
- receive: Receive,
- send: Send,
- ) -> None:
- """ASGI application interface."""
- pass
-```
-
-**Usage:**
-```python
-from headroom.integrations import HeadroomMiddleware
-from fastapi import FastAPI
-
-app = FastAPI()
-app.add_middleware(
- HeadroomMiddleware,
- headroom_url="http://localhost:8787",
- mode=ProxyMode.COMPRESS,
-)
-```
-
----
-
-### MCP integration helpers (`headroom/integrations/mcp/server.py`)
-
-Helpers for MCP-aware host applications and custom wrappers. This module does
-not currently ship a standalone `HeadroomMCPProxy` server implementation.
-
-**`HeadroomMCPCompressor` class:**
-```python
-class HeadroomMCPCompressor:
- def __init__(
- self,
- config: HeadroomConfig | None = None,
- profiles: list[MCPToolProfile] | None = None,
- token_counter: Callable[[str], int] | None = None,
- ) -> None:
- ...
-
- def compress(
- self,
- content: str,
- tool_name: str,
- tool_args: dict[str, Any] | None = None,
- user_query: str = "",
- ) -> MCPCompressionResult:
- """Compress an MCP tool result."""
- pass
-```
-
-**Companion helpers:**
-- `compress_tool_result(...)` — standalone helper for host applications
-- `HeadroomMCPClientWrapper` — wraps an MCP client and compresses tool results
-- `create_headroom_mcp_proxy(...)` — returns config for a custom wrapper/proxy
-
-**Ready-to-run MCP tools server:**
-```bash
-headroom mcp serve
-```
-
----
-
-### Strands (`headroom/integrations/strands/`)
-
-Strands framework integration.
-
-**Usage:**
-```python
-from headroom.integrations.strands import HeadroomStrandsPlugin
-
-plugin = HeadroomStrandsPlugin()
-```
-
----
-
-### LangChain (`headroom/integrations/langchain/`)
-
-LangChain callback handler integration.
-
-**`HeadroomLangChainCallback` class:**
-```python
-class HeadroomLangChainCallback(BaseCallbackHandler):
- def __init__(
- self,
- headroom_url: str = "http://localhost:8787",
- api_key: str | None = None,
- ) -> None:
- self.headroom_url = headroom_url
- self.api_key = api_key
-
- async def on_llm_start(self, serialized, prompts, **kwargs) -> None:
- pass
-
- async def on_llm_end(self, response, **kwargs) -> None:
- pass
-```
-
-**Usage:**
-```python
-from langchain.callbacks import HeadroomLangChainCallback
-
-callback = HeadroomLangChainCallback()
-# Pass to LangChain chain
-```
-
----
-
-## Agent Contract
-
-All learn plugins must implement the `LearnPlugin` interface:
-
-```python
-from abc import ABC, abstractmethod
-from headroom.learn.base import ConversationScanner, ContextWriter
-from headroom.learn.models import ProjectInfo, SessionData
-
-class LearnPlugin(ConversationScanner):
- """A self-contained learn plugin for a single coding agent."""
-
- @property
- @abstractmethod
- def name(self) -> str:
- """Short lowercase identifier (e.g., 'claude', 'cursor')."""
- ...
-
- @property
- @abstractmethod
- def display_name(self) -> str:
- """Human-readable name (e.g., 'Claude Code', 'Cursor')."""
- ...
-
- @abstractmethod
- def detect(self) -> bool:
- """Return True if this agent has data on the current machine."""
- ...
-
- @abstractmethod
- def discover_projects(self) -> list[ProjectInfo]:
- """Discover all projects with conversation data."""
- ...
-
- @abstractmethod
- def scan_project(self, project: ProjectInfo, max_workers: int = 1) -> list[SessionData]:
- """Scan all sessions for a project."""
- ...
-
- @abstractmethod
- def create_writer(self) -> ContextWriter:
- """Return the appropriate ContextWriter for this agent."""
- ...
-```
-
-**Plugin Registration:**
-```python
-# Module-level instance for auto-discovery
-plugin = MyAgentPlugin()
-```
-
-Plugins are auto-discovered from `headroom.learn.plugins.*` or via `headroom.learn_plugin` entry points.
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial integrations document |
diff --git a/docs/spec/006-actors.md b/docs/spec/006-actors.md
deleted file mode 100644
index c9fe2053d..000000000
--- a/docs/spec/006-actors.md
+++ /dev/null
@@ -1,230 +0,0 @@
-# 006. Actors
-
-**Status:** done
-
-## Actor Types
-
-### End User
-
-The developer using an AI coding agent with Headroom.
-
-**Interactions:**
-- Configures Headroom via environment variables or config file
-- Uses wrapped CLI commands or SDK
-- Views savings in dashboard
-- Optionally enables learn mode
-
-**Needs:**
-- Transparent compression (doesn't break workflows)
-- Clear savings metrics
-- Easy opt-out of specific features
-
-**Configuration:**
-```bash
-# Minimal setup
-export ANTHROPIC_API_KEY=sk-...
-
-# Optional overrides
-export HEADROOM_MODE=token
-```
-
----
-
-### Operator
-
-The person deploying and managing Headroom in production.
-
-**Interactions:**
-- Deploys Headroom (Docker, native, or embedded)
-- Configures profiles and presets
-- Monitors health endpoints
-- Reviews metrics and logs
-- Manages upgrades
-
-**Needs:**
-- Clear deployment documentation
-- Health and readiness checks
-- Metrics for capacity planning
-- Upgrade and rollback procedures
-
-**Configuration:**
-```yaml
-# ~/.headroom/config.yaml
-proxy:
- host: 0.0.0.0
- port: 8787
-
-compression:
- enabled: true
- cache:
- enabled: true
- ttl: 3600
-
-telemetry:
- metrics:
- enabled: true
-```
-
-**Health Endpoints:**
-```bash
-curl http://localhost:8787/health
-curl http://localhost:8787/livez
-curl http://localhost:8787/readyz
-curl http://localhost:8787/metrics
-```
-
----
-
-### Plugin Author
-
-The developer creating a custom learn plugin for a specific agent.
-
-**Interactions:**
-- Implements `LearnPlugin` interface
-- Plugins auto-discovered from `headroom/learn/plugins/` directory
-- Contributes to Headroom
-
-**Needs:**
-- Clear plugin interface documentation
-- Example plugins to reference
-- Test utilities
-
-**Plugin Template:**
-```python
-from headroom.learn.base import LearnPlugin, ConversationScanner
-
-class MyAgentPlugin(LearnPlugin):
- @property
- def name(self) -> str:
- return "my_agent"
-
- @property
- def display_name(self) -> str:
- return "My Agent"
-
- def detect(self) -> bool:
- # Check if this agent has data on the current machine
- pass
-
- def discover_projects(self) -> list[ProjectInfo]:
- # Discover all projects with conversation data
- pass
-
- def scan_project(self, project: ProjectInfo, max_workers: int = 1) -> list[SessionData]:
- # Scan all sessions for a project
- pass
-
- def create_writer(self) -> ContextWriter:
- # Return the appropriate ContextWriter for this agent
- pass
-```
-
----
-
-### Enterprise Evaluator
-
-The person assessing Headroom for organizational adoption.
-
-**Interactions:**
-- Reviews security documentation
-- Assesses compliance guarantees
-- Evaluates operational characteristics
-
-**Needs:**
-- Clear data handling guarantees
-- Security and privacy documentation
-- Compliance certifications (if any)
-- SOC2/GDPR considerations
-
-**Security Configuration:**
-```bash
-# Maximum privacy settings
-HEADROOM_TELEMETRY=off
-HEADROOM_STATELESS=true
-headroom proxy --no-cache --no-optimize
-```
-
----
-
-## Interaction Patterns
-
-### User → Headroom
-
-```
-┌──────────────┐ ┌────────────────┐ ┌─────────────┐
-│ User's AI │──────▶│ Headroom │──────▶│ Provider │
-│ Agent │ │ Proxy │ │ API │
-└──────────────┘ └───────┬────────┘ └─────────────┘
- │
- ▼
- ┌──────────────┐
- │ Dashboard │
- │ (optional) │
- └──────────────┘
-```
-
-**Flow:**
-1. User's AI agent sends request to Headroom proxy
-2. Headroom compresses context
-3. Compressed request sent to provider API
-4. Response returned to agent
-5. Optional: savings logged to dashboard
-
----
-
-### Operator → Headroom
-
-```
-┌──────────┐ ┌────────────────┐ ┌─────────────┐
-│ Operator │──────▶│ Health │──────▶│ Metrics │
-│ │ │ Endpoints │ │ Server │
-└──────────┘ └────────────────┘ └─────────────┘
- │
- ▼
-┌────────────────┐
-│ Logs │
-│ (stdout/file) │
-└────────────────┘
-```
-
-**Flow:**
-1. Operator checks health endpoints
-2. Reviews Prometheus metrics
-3. Monitors logs for errors
-4. Manages configuration
-
----
-
-### Plugin Author → Headroom
-
-```
-┌──────────────┐ ┌────────────────┐ ┌─────────────┐
-│ Plugin │──────▶│ Plugin │──────▶│ Registry │
-│ Author │ │ Interface │ │ + Tests │
-└──────────────┘ └────────────────┘ └─────────────┘
-```
-
-**Flow:**
-1. Plugin author implements LearnPlugin
-2. Plugins are auto-discovered from `headroom/learn/plugins/` directory
-3. Writes unit tests
-4. Submits contribution
-
----
-
-## Permissions Model
-
-| Actor | Config | Read Metrics | Admin | Plugin |
-|-------|--------|--------------|-------|--------|
-| End User | ✓ (own) | ✓ (own) | - | - |
-| Operator | ✓ (full) | ✓ (all) | ✓ | - |
-| Plugin Author | - | - | - | ✓ (write) |
-| Enterprise Evaluator | - | ✓ (security) | - | - |
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial actors document |
diff --git a/docs/spec/007-behavior.md b/docs/spec/007-behavior.md
deleted file mode 100644
index b0bcabbb7..000000000
--- a/docs/spec/007-behavior.md
+++ /dev/null
@@ -1,178 +0,0 @@
-# 007. Behavior
-
-**Status:** done
-
-## Proxy Modes
-
-### Passthrough
-
-Headroom forwards requests without modification.
-
-**Behavior:**
-- All requests pass through unchanged
-- Response headers may be modified for telemetry
-- No compression applied
-- Useful for testing or debugging
-
-**Configuration:** `headroom proxy --no-optimize`
-
-**Request Flow:**
-```
-Client → Proxy → Provider API → Response
-```
-
----
-
-### Token Mode
-
-Headroom applies deterministic transforms to requests.
-
-**Behavior:**
-- SmartCrusher compresses JSON tool outputs
-- CacheAligner stabilizes prefixes
-- RollingWindow caps context tokens
-- CCR caching enabled
-- Token budget enforced
-
-**Configuration:** `HEADROOM_MODE=token` or `headroom proxy --mode token`
-
-**Request Flow:**
-```
-Client → Proxy → [SmartCrusher] → [CacheAligner]
- → [RollingWindow] → [CCR Cache]
- → Provider API → Response
-```
-
----
-
-### Cache Mode
-
-Headroom preserves prior turns where possible to maximize provider prefix-cache hit rate.
-
-**Behavior:**
-- Freezes provider-confirmed cached prefixes
-- Compresses the mutable tail of the request
-- Trades some token savings for better cache stability
-
-**Configuration:** `HEADROOM_MODE=cache` or `headroom proxy --mode cache`
-
----
-
-## Session Modes
-
-Session modes control how Headroom handles context windows.
-
-| Mode | Description | Use Case |
-|------|-------------|----------|
-| `token` | Prioritize token removal | Default proxy mode |
-| `cache` | Preserve prior turns for provider prefix-cache stability | Long Claude/Codex sessions |
-| passthrough | Disable optimization with `--no-optimize` | Debugging |
-
----
-
-## Request Lifecycle
-
-```
-1. Request received at proxy endpoint
- │
- ▼
-2. Session lookup/creation
- │ - Extract session ID from headers
- │ - Create new session if not found
- │
- ▼
-3. Mode determination
- │ - Check HEADROOM_MODE
- │ - Check runtime headers
- │ - Determine active plugins
- │
- ▼
-4. Compression pipeline execution
- │ a. Token counting
- │ b. Semantic cache check
- │ c. Content type detection
- │ d. Transform selection
- │ e. Summary compression (if eligible)
- │ f. Token budget enforcement
- │
- ▼
-5. Forward to provider API
- │ - Route to correct provider
- │ - Apply API key from config
- │ - Handle timeouts
- │
- ▼
-6. Response capture
- │ - Log request/response metadata
- │ - Calculate savings
- │
- ▼
-7. Savings calculation
- │ - tokens_before - tokens_after
- │ - percentage = savings / tokens_before
- │
- ▼
-8. Telemetry emission
- │ - Prometheus metrics
- │ - Optional tracing
- │
- ▼
-9. Response returned to client
- - X-Headroom-Savings header
- - X-Headroom-Original-Tokens header
- - X-Headroom-Compressed-Tokens header
-```
-
----
-
-## Error Handling
-
-| Error Type | HTTP Code | Behavior |
-|------------|----------|----------|
-| Provider timeout | 504 | Retry up to 3 times with exponential backoff |
-| Invalid request | 400 | Return error details in body |
-| Compression failure | 500 | Fall back to passthrough mode |
-| Provider error | Provider code | Return provider error to client |
-| Internal error | 500 | Return 500, log details |
-| Rate limited | 429 | Return retry-after header |
-
-**Retry Configuration:**
-```python
-@dataclass
-class RetryConfig:
- max_retries: int = 3
- base_delay: float = 1.0
- max_delay: float = 60.0
- exponential_base: float = 2.0
-```
-
----
-
-## Response Headers
-
-Headroom adds headers to all compressed responses:
-
-```
-X-Headroom-Savings: 0.35
-X-Headroom-Original-Tokens: 8192
-X-Headroom-Compressed-Tokens: 5325
-X-Headroom-Compression-Type: semantic,summary
-X-Headroom-Request-Id: abc123
-X-Headroom-Cache-Hit: false
-```
-
-**Header Descriptions:**
-- `X-Headroom-Savings` — Token savings percentage (0.35 = 35%)
-- `X-Headroom-Original-Tokens` — Token count before compression
-- `X-Headroom-Compressed-Tokens` — Token count after compression
-- `X-Headroom-Compression-Type` — Types of compression applied
-- `X-Headroom-Request-Id` — Unique request identifier
-- `X-Headroom-Cache-Hit` — Whether result was from cache
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial behavior document |
diff --git a/docs/spec/008-capabilities.md b/docs/spec/008-capabilities.md
deleted file mode 100644
index fabf11305..000000000
--- a/docs/spec/008-capabilities.md
+++ /dev/null
@@ -1,254 +0,0 @@
-# 008. Capabilities
-
-**Status:** done
-
-## Feature Matrix
-
-| Capability | Proxy | SDK | Wrap | MCP | ASGI | LiteLLM |
-|------------|:-----:|:---:|:----:|:---:|:----:|:-------:|
-| Semantic compression | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Summary compression | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Token budget management | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Learn mode | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Session tracking | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
-| CCR feedback | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
-| TOIN tagging | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Savings tracking | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Dashboard | ✓ | - | ✓ | - | - | - |
-| Health endpoints | ✓ | - | - | - | - | - |
-| Metrics (Prometheus) | ✓ | - | - | - | - | - |
-
----
-
-## Compression Capabilities
-
-### Proxy Cache
-
-**Description:** The proxy has semantic cache support and CCR-backed retrieval, controlled by CLI configuration.
-
-**Configuration:**
-```bash
-headroom proxy # cache enabled by default
-headroom proxy --no-cache
-```
-
-**Behavior:**
-1. Hash input content
-2. Check cache for similar entries (configurable threshold)
-3. Return cached response if match found (CCR retrieval)
-4. Update cache on miss
-5. Store compressed content for future retrieval
-
-**CCR Configuration:**
-```python
-@dataclass
-class CCRConfig:
- enabled: bool = True
- storage: ContentStorage | None = None
- cache_ttl: int = 3600
- similarity_threshold: float = 0.85
- max_results: int = 10
-```
-
----
-
-### Summary Compression
-
-**Description:** Compresses long context using summarization.
-
-**Configuration:**
-```bash
-# Note: HEADROOM_SUMMARY_* env vars are not yet implemented.
-# Summary compression is currently configured programmatically only.
-```
-
-**Behavior:**
-1. Count input tokens
-2. If over threshold, apply summary compression
-3. Preserve key information (configurable priority)
-4. Track summary statistics
-
-**Summary Pipeline:**
-```python
-class SummaryCompressor:
- def __init__(
- self,
- threshold: int = 5000,
- target_ratio: float = 0.3,
- priority_preservation: bool = True,
- ) -> None:
- pass
-
- def compress(
- self,
- content: str,
- context: TransformContext,
- ) -> TransformResult:
- pass
-```
-
----
-
-### Token Budget Manager
-
-**Description:** Enforces token budget limits per session via RollingWindow.
-
-**Configuration:**
-```python
-@dataclass
-class RollingWindowConfig:
- enabled: bool = True
- keep_system: bool = True # Never drop system prompt
- keep_last_turns: int = 2 # Never drop last N turns
- output_buffer_tokens: int = 4000 # Reserve for output
-```
-
-**Behavior:**
-1. Track token usage per session
-2. Enforce budget limits via rolling window
-3. Preserve system prompt and last N turns
-4. Reserve output buffer tokens
-
----
-
-## Intelligent Context Management
-
-**Description:** Semantic-aware context management with TOIN integration.
-
-```python
-@dataclass
-class IntelligentContextConfig:
- enabled: bool = True
- use_importance_scoring: bool = True
- scoring_weights: ScoringWeights = field(default_factory=ScoringWeights)
- toin_integration: bool = True
- toin_confidence_threshold: float = 0.3
-```
-
-**Scoring Weights:**
-```python
-@dataclass
-class ScoringWeights:
- recency: float = 0.20
- semantic_similarity: float = 0.20
- toin_importance: float = 0.25
- error_indicator: float = 0.15
- forward_reference: float = 0.15
- token_density: float = 0.05
-```
-
----
-
-## CCR Configuration
-
-**Description:** Compress-Cache-Retrieve makes compression reversible.
-
-```python
-@dataclass
-class CCRConfig:
- enabled: bool = True
- store_max_entries: int = 1000
- store_ttl_seconds: int = 300
- inject_retrieval_marker: bool = True
- feedback_enabled: bool = True
- min_items_to_cache: int = 20
- inject_tool: bool = True
- inject_system_instructions: bool = False
-```
-
----
-
-## SmartCrusher (Statistical JSON Compression)
-
-**Description:** Preserves JSON schema while reducing array size via statistical analysis.
-
-```python
-@dataclass
-class SmartCrusherConfig:
- enabled: bool = True
- min_items_to_analyze: int = 5
- min_tokens_to_crush: int = 200
- variance_threshold: float = 2.0
- uniqueness_threshold: float = 0.1
- similarity_threshold: float = 0.8
- max_items_after_crush: int = 15
- preserve_change_points: bool = True
- use_feedback_hints: bool = True
- toin_confidence_threshold: float = 0.3
- relevance: RelevanceScorerConfig = field(default_factory=RelevanceScorerConfig)
- anchor: AnchorConfig = field(default_factory=AnchorConfig)
- dedup_identical_items: bool = True
- first_fraction: float = 0.3
- last_fraction: float = 0.15
-```
-
-**Relevance Scoring:**
-```python
-@dataclass
-class RelevanceScorerConfig:
- tier: Literal["bm25", "embedding", "hybrid"] = "hybrid"
- bm25_k1: float = 1.5
- bm25_b: float = 0.75
- embedding_model: str = field(default_factory=lambda: ML_MODEL_DEFAULTS.sentence_transformer)
- hybrid_alpha: float = 0.5
- adaptive_alpha: bool = True
- relevance_threshold: float = 0.25
-```
-
-**Anchor Allocation:**
-```python
-@dataclass
-class AnchorConfig:
- anchor_budget_pct: float = 0.25
- min_anchor_slots: int = 3
- max_anchor_slots: int = 12
- default_front_weight: float = 0.5
- default_back_weight: float = 0.4
- default_middle_weight: float = 0.1
- search_front_weight: float = 0.75
- logs_back_weight: float = 0.75
-```
-
----
-
-## Agent-Specific Capabilities
-
-### Claude
-
-- Session branch comparison
-- Token headroom mode
-- Tool use tracking
-- Multi-modal support (images)
-
-### Codex
-
-- Rate limit handling
-- Code completion optimization
-- Batch request support
-
-### Gemini
-
-- Multi-modal inputs
-- Function calling support
-- Context caching API
-
----
-
-## Deployment Capabilities
-
-| Feature | Docker | Native | Embedded |
-|---------|:------:|:------:|:--------:|
-| Standalone proxy | ✓ | ✓ | - |
-| Health endpoints | ✓ | ✓ | - |
-| Prometheus metrics | ✓ | ✓ | - |
-| Dashboard | ✓ | ✓ | - |
-| Volume mounts | ✓ | - | - |
-| Environment overrides | ✓ | ✓ | ✓ |
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial capabilities document |
diff --git a/docs/spec/009-compliance.md b/docs/spec/009-compliance.md
deleted file mode 100644
index d7046c68a..000000000
--- a/docs/spec/009-compliance.md
+++ /dev/null
@@ -1,82 +0,0 @@
-# 009. Compliance
-
-**Status:** done
-
-## Data Handling Guarantees
-
-### Default Behavior (No Export)
-
-| Data Type | Stored | Exported | Logged |
-|-----------|:------:|:--------:|:------:|
-| Prompts | Optional (cache) | Never | Never |
-| Responses | Optional (cache) | Never | Never |
-| Savings metrics | Yes | Never | Never |
-| Session metadata | Yes | Never | Never |
-| Telemetry | Aggregated | Never | Never |
-
----
-
-### With Exporters Configured
-
-**Warning:** Enabling exporters may send data outside your infrastructure.
-
-| Exporter | Data Sent | Destination |
-|----------|-----------|-------------|
-| Prometheus | Metrics only | Prometheus server |
-| OpenTelemetry | Traces/spans | OTLP endpoint |
-| Custom webhook | Configurable | HTTP endpoint |
-
----
-
-## Privacy Commitments
-
-1. **No prompt logging by default** — Headroom never logs prompt content unless explicitly configured
-2. **No data leaves proxy by default** — All processing happens locally
-3. **User control** — All data handling is configurable via environment variables
-4. **Transparency** — Response headers indicate compression was applied
-5. **No telemetry to Headroom project** — No data sent to external servers without explicit opt-in
-
----
-
-## Compliance Considerations
-
-### SOC 2
-
-*To be documented if applicable.*
-
-### GDPR
-
-| Requirement | Headroom Support |
-|-------------|:----------------:|
-| Data minimization | ✓ Default no-logging |
-| Right to deletion | ✓ Cache can be cleared |
-| Data portability | Export available via API |
-| Breach notification | N/A (no external data) |
-
-### HIPAA
-
-*To be documented if applicable.*
-
----
-
-## Configuration for Maximum Privacy
-
-```bash
-HEADROOM_TELEMETRY=off
-HEADROOM_STATELESS=true
-headroom proxy --no-cache --no-optimize
-```
-
-This configuration results in:
-- No prompt data stored
-- No data exported
-- No analytics collected
-- Headroom acts as a passthrough proxy
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial compliance document |
diff --git a/docs/spec/010-data.md b/docs/spec/010-data.md
deleted file mode 100644
index c1a75234d..000000000
--- a/docs/spec/010-data.md
+++ /dev/null
@@ -1,174 +0,0 @@
-# 010. Data
-
-**Status:** done
-
-## Storage Overview
-
-| Store | Location | Type | Purpose |
-|-------|----------|------|---------|
-| SQLite | `headroom.db` (cwd or `~/.headroom/`) | Local file | Metrics, sessions, compression store |
-| Memory DB | `~/.headroom/headroom_memory.db` | Local file | Memory system (optional) |
-| Vector Index | `~/.headroom/headroom_memory_vectors.db` | Local file | Semantic search (optional, requires sqlite-vec) |
-| Graph Store | `~/.headroom/headroom_memory_graph.db` | Local file | Memory relationships |
-| Compression cache | `~/.headroom/cache/` | Directory | Semantic + summary cache |
-
-**Note:** Default store URL is `sqlite:///headroom.db` (relative to working directory).
-
----
-
-## SQLite Schema
-
-### Core Tables
-
-**sessions:**
-```sql
-CREATE TABLE sessions (
- session_id TEXT PRIMARY KEY,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- metadata TEXT -- JSON
-);
-```
-
-**requests:**
-```sql
-CREATE TABLE requests (
- id TEXT PRIMARY KEY,
- timestamp TEXT NOT NULL,
- model TEXT NOT NULL,
- stream INTEGER NOT NULL,
- mode TEXT NOT NULL,
- tokens_input_before INTEGER NOT NULL,
- tokens_input_after INTEGER NOT NULL,
- tokens_output INTEGER,
- block_breakdown TEXT NOT NULL, -- JSON
- waste_signals TEXT NOT NULL, -- JSON
- stable_prefix_hash TEXT,
- cache_alignment_score REAL,
- cached_tokens INTEGER,
- transforms_applied TEXT NOT NULL, -- JSON
- tool_units_dropped INTEGER DEFAULT 0,
- turns_dropped INTEGER DEFAULT 0,
- messages_hash TEXT,
- error TEXT
-);
-
-CREATE INDEX idx_timestamp ON requests(timestamp);
-CREATE INDEX idx_model ON requests(model);
-CREATE INDEX idx_mode ON requests(mode);
-```
-
-**cache_entries:**
-```sql
-CREATE TABLE cache_entries (
- cache_key TEXT PRIMARY KEY,
- input_hash TEXT NOT NULL,
- output TEXT NOT NULL,
- compression_type TEXT NOT NULL,
- tokens_before INTEGER NOT NULL,
- tokens_after INTEGER NOT NULL,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- ttl INTEGER DEFAULT 3600,
- hit_count INTEGER DEFAULT 0,
- last_accessed TIMESTAMP DEFAULT CURRENT_TIMESTAMP
-);
-```
-
-**compression_store (CCR):**
-```sql
-CREATE TABLE compression_store (
- hash TEXT PRIMARY KEY,
- original TEXT NOT NULL,
- metadata TEXT, -- JSON
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- expires_at TIMESTAMP NOT NULL
-);
-```
-
----
-
-## Environment Variables
-
-### Database
-
-| Variable | Default | Description |
-|----------|---------|-------------|
-| `HEADROOM_WORKSPACE_DIR` | `~/.headroom` | Workspace root; all DBs live under this directory |
-| `HEADROOM_CONFIG_DIR` | `~/.headroom/config` | Config root (read-mostly: models.json, per-plugin config) |
-
-### Cache
-
-| Variable | Default | Description |
-|----------|---------|-------------|
-| CLI `--no-cache` | unset | Disable semantic cache for the proxy process |
-| `HEADROOM_WORKSPACE_DIR` | `~/.headroom` | Workspace root for proxy state, logs, memory, and savings |
-| `HEADROOM_STATELESS` | `false` | Disable filesystem writes and keep runtime state in memory |
-
----
-
-## Data Retention
-
-| Data Type | Retention | Auto-cleanup |
-|-----------|-----------|:------------:|
-| Savings history | Forever | No |
-| Session history | 30 days | Yes (configurable) |
-| Compression cache | 7 days | Yes |
-| Telemetry | 90 days | Yes |
-| Dashboard state | 30 days | Yes |
-
----
-
-## Data Export
-
-### Savings Export
-
-```bash
-curl http://localhost:8787/stats
-```
-
-Response:
-```json
-{
- "savings": [
- {
- "date": "2026-04-16",
- "original_tokens": 8192,
- "compressed_tokens": 5325,
- "savings_percentage": 0.35
- }
- ],
- "total_savings": 1234567
-}
-```
-
-### Session Export
-
-```bash
-curl http://localhost:8787/stats
-```
-
----
-
-## Backup
-
-### Manual Backup
-
-```bash
-tar -czf headroom-backup.tar.gz ~/.headroom/
-```
-
-### Storage Location
-
-Relocate all storage by setting the workspace root:
-
-```bash
-export HEADROOM_WORKSPACE_DIR=/mnt/state
-```
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial data document |
diff --git a/docs/spec/011-deployment.md b/docs/spec/011-deployment.md
deleted file mode 100644
index b9be6f433..000000000
--- a/docs/spec/011-deployment.md
+++ /dev/null
@@ -1,177 +0,0 @@
-# 011. Deployment
-
-**Status:** done
-
-## Deployment Profiles
-
-### Docker Profile
-
-**Image:** `headroom-ai/headroom:latest`
-
-**Dockerfile:**
-```dockerfile
-FROM python:3.12-slim
-
-RUN pip install headroom-ai
-
-EXPOSE 8787
-
-ENTRYPOINT ["headroom", "proxy"]
-CMD ["--host", "0.0.0.0", "--port", "8787"]
-```
-
-**docker-compose.yml:**
-```yaml
-version: '3.8'
-services:
- headroom:
- image: headroom-ai/headroom:latest
- ports:
- - "8787:8787"
- environment:
- - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- - HEADROOM_MODE=token
- volumes:
- - headroom-data:/root/.headroom
-
-volumes:
- headroom-data:
-```
-
-**Run:**
-```bash
-docker-compose up -d
-```
-
----
-
-### Native Profile
-
-**Installation:**
-```bash
-pip install headroom-ai
-```
-
-**Run:**
-```bash
-headroom proxy --host 0.0.0.0 --port 8787
-```
-
----
-
-### Embedded Profile
-
-**Usage:**
-```python
-from headroom import HeadroomClient
-
-client = HeadroomClient(
- api_key="your-api-key",
- base_url="http://localhost:8787"
-)
-
-result = await client.compress(messages)
-```
-
----
-
-## Cloud Presets
-
-### AWS (EC2/ECS)
-
-```yaml
-# ~/.headroom/config.yaml
-deployment:
- profile: aws
- instance_type: t3.medium
-
-compression:
- enabled: true
- max_tokens: 8192
-
-cache:
- backend: redis
- redis_url: redis://localhost:6379
-```
-
-### Google Cloud (Cloud Run)
-
-```yaml
-deployment:
- profile: gcp
- region: us-central1
- memory: 512Mi
- cpu: 1
-```
-
-### Azure (Container Apps)
-
-```yaml
-deployment:
- profile: azure
- resource_group: headroom-rg
-```
-
----
-
-## Runtime Configuration
-
-### Environment Variables
-
-| Variable | Default | Description |
-|----------|---------|-------------|
-| `HEADROOM_MODE` | `token` | Proxy mode (`token` or `cache`) |
-| `HEADROOM_PORT` | `8787` | Proxy port |
-| `HEADROOM_HOST` | `127.0.0.1` | Proxy host |
-| `ANTHROPIC_API_KEY` | - | Anthropic API key |
-| `OPENAI_API_KEY` | - | OpenAI API key |
-| `HEADROOM_TELEMETRY` | `off` (opt-in) | Set to `on` to opt in to telemetry |
-
-### Config File
-
-```yaml
-# ~/.headroom/config.yaml
-proxy:
- host: 0.0.0.0
- port: 8787
-
-compression:
- enabled: true
- max_tokens: 4096
- overlap_tokens: 512
- content_sensitivity: 0.5
- preserve_system_messages: true
- priority_tokens: 1024
-
-cache:
- enabled: true
- ttl: 3600
- max_size: 10000
-
-telemetry:
- metrics:
- enabled: true
- tracing:
- enabled: false
-
-learn:
- enabled: false
-```
-
----
-
-## Resource Requirements
-
-| Deployment | CPU | Memory | Storage |
-|------------|-----|--------|---------|
-| Minimal | 0.5 core | 512MB | 1GB |
-| Default | 1 core | 1GB | 5GB |
-| Enterprise | 2 cores | 2GB | 20GB |
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial deployment document |
diff --git a/docs/spec/012-diagrams.md b/docs/spec/012-diagrams.md
deleted file mode 100644
index d471b5021..000000000
--- a/docs/spec/012-diagrams.md
+++ /dev/null
@@ -1,140 +0,0 @@
-# 012. Diagrams
-
-**Status:** done
-
-## Component Diagram
-
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ Headroom │
-├─────────────────────────────────────────────────────────────────┤
-│ │
-│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │
-│ │ Proxy │ │ SDK │ │ Wrap │ │ MCP │ │
-│ │ Server │ │ (Python) │ │ CLI │ │ Server │ │
-│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬──────┘ │
-│ │ │ │ │ │
-│ ┌────┴──────────────┴──────────────┴─────────────────┴──────┐ │
-│ │ Compression Layer │ │
-│ │ ┌────────────┐ ┌────────────┐ ┌────────────────────┐ │ │
-│ │ │ Semantic │ │ Summary │ │ Token Budget │ │ │
-│ │ │ Cache │ │ Compress │ │ Manager │ │ │
-│ │ └────────────┘ └────────────┘ └────────────────────┘ │ │
-│ └───────────────────────────────────────────────────────────┘ │
-│ │
-│ ┌───────────────────────────────────────────────────────────┐ │
-│ │ Learn System │ │
-│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────────────┐ │ │
-│ │ │Claude │ │ Codex │ │ Gemini │ │ ...more │ │ │
-│ │ │Plugin │ │ Plugin │ │ Plugin │ │ plugins │ │ │
-│ │ └────────┘ └────────┘ └────────┘ └────────────────┘ │ │
-│ └───────────────────────────────────────────────────────────┘ │
-│ │
-│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
-│ │ Dashboard │ │ CCR │ │ TOIN │ │
-│ │ (Next.js) │ │ (Claude │ │ (Tenant-specific │ │
-│ │ │ │ Code Relay)│ │ ONNX) │ │
-│ └──────────────┘ └──────────────┘ └──────────────────────┘ │
-│ │
-└─────────────────────────────────────────────────────────────────┘
-```
-
----
-
-## Request Flow Sequence Diagram
-
-```
-Client Headroom Compression CCR Provider
- Proxy Layer Cache API
- │ │ │ │ │
- │──POST /v1/msg──▶│ │ │ │
- │ │ │ │ │
- │ │──Count tokens──▶│ │ │
- │ │ │ │ │
- │ │────Cache check────▶│ │ │
- │ │ │◀───hit──────│ │
- │ │ │◀───CCR retrieval───────│
- │ │ │ │ │
- │ │───Summary compression───▶│ │
- │ │ │◀──budget enforcement─────│
- │ │ │ │ │
- │ │─────Forward compressed─────▶│ │
- │ │ │ │◀──Response──│
- │ │◀──────────────────────────────────────│
- │◀──Response──│ │ │ │
-```
-
----
-
-## CCR Cache Flow
-
-```
-Request Headroom CCR Storage
- │ Proxy Cache
- │ │ │
- │──compress──▶│ │
- │ │──hash────▶│
- │ │ │──store──▶│
- │ │◀──stored──│ │
- │ │──CCR hash │
- │◀──Response──│ │
- │ │ │
-```
-
----
-
-## Learn System Flow
-
-```
-Session Headroom Learn Plugin
- Data Proxy System Registry
- │ │ │ │
- │──session──▶│ │ │
- │ │──analyze──▶│ │
- │ │ │──load────▶│
- │ │ │◀─Result───│
- │ │◀──Feedback──│ │
- │ │──Improve compression │
- │◀───────────│ │ │
-```
-
----
-
-## Data Flow
-
-```
-┌──────────────┐
-│ User's │
-│ AI Agent │
-└──────┬───────┘
- │ HTTP
- ▼
-┌──────────────┐ ┌─────────────────────────────────────┐
-│ Headroom │────▶│ Compression Layer │
-│ Proxy │ │ │
-└──────┬───────┘ │ ┌─────────┐ ┌──────────────┐ │
- │ │ │ Semantic│ │ Summary │ │
- │ │ │ Cache │ │ Compression │ │
- │ │ └────┬───┘ └──────┬───────┘ │
- │ │ │ │ │
- │ │ ┌────┴─────────────┴──────┐ │
- │ │ │ Token Budget │ │
- │ │ │ Manager │ │
- │ │ └────────────┬───────────┘ │
- │ └───────────────┼─────────────────┘
- │ │
- │ │ Compressed request
- ▼ ▼
-┌──────────────┐ ┌──────────────┐
-│ Dashboard │ │ Provider │
-│ (optional) │ │ API │
-└──────────────┘ └──────────────┘
-```
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial diagrams document |
diff --git a/docs/spec/013-disaster-recovery.md b/docs/spec/013-disaster-recovery.md
deleted file mode 100644
index dcc5f6a08..000000000
--- a/docs/spec/013-disaster-recovery.md
+++ /dev/null
@@ -1,159 +0,0 @@
-# 013. Disaster Recovery
-
-**Status:** done
-
-## Failure Modes
-
-### Proxy Failures
-
-| Failure | Impact | Recovery |
-|---------|--------|----------|
-| Proxy crash | Service unavailable | Restart or failover |
-| OOM | Service unavailable | Restart with more memory |
-| Network partition | Cannot reach providers | Retry with backoff |
-
-### Compression Failures
-
-| Failure | Impact | Recovery |
-|---------|--------|----------|
-| Compression timeout | Request delayed | Retry with passthrough |
-| Transform error | Compression skipped | Log error, passthrough |
-| Budget exceeded | Truncation | Notify via headers |
-
-### Storage Failures
-
-| Failure | Impact | Recovery |
-|---------|--------|----------|
-| SQLite corruption | Data loss | Restore from backup |
-| Cache full | CCR disabled | Clear old entries |
-| Disk full | Write failures | Expand storage |
-
----
-
-## Backup Strategies
-
-### Manual Backup
-
-```bash
-# Full backup
-tar -czf headroom-backup-$(date +%Y%m%d).tar.gz ~/.headroom/
-
-# Incremental (last 24h)
-sqlite3 ~/.headroom/headroom_memory.db ".backup /tmp/headroom_incremental.db"
-```
-
-### Automated Backup
-
-```bash
-# Cron job (daily at 2am)
-0 2 * * * tar -czf /backup/headroom-$(date +\%Y\%m\%d).tar.gz ~/.headroom/
-```
-
-### External Storage
-
-> **Note:** External PostgreSQL/Redis storage is not yet implemented. Headroom uses SQLite at `~/.headroom/` (configurable via `HEADROOM_WORKSPACE_DIR`). The `HEADROOM_DB_URL` and `HEADROOM_CACHE_BACKEND` vars do not exist.
-
----
-
-## Recovery Procedures
-
-### Proxy Recovery
-
-1. **Restart proxy:**
-```bash
-# Docker
-docker-compose restart headroom
-
-# Native
-pkill headroom && headroom proxy &
-```
-
-2. **Check health:**
-```bash
-curl http://localhost:8787/health
-curl http://localhost:8787/readyz
-```
-
-### Database Recovery
-
-1. **Restore from backup:**
-```bash
-# Stop headroom
-pkill headroom
-
-# Restore SQLite
-rm ~/.headroom/headroom_memory.db
-tar -xzf headroom-backup-20260416.tar.gz -C ~/
-
-# Restart headroom
-headroom proxy &
-```
-
-2. **Verify data:**
-```bash
-curl http://localhost:8787/stats
-```
-
----
-
-## Data Migration
-
-### Schema Migration
-
-```python
-async def migrate_v1_to_v2():
- async with aiosqlite.connect(DB_PATH) as db:
- await db.execute("""
- ALTER TABLE sessions
- ADD COLUMN agent_version TEXT
- """)
- await db.commit()
-```
-
-### Data Export/Import
-
-```bash
-# Export
-curl http://localhost:8787/api/v1/export > backup.json
-
-# Import
-curl -X POST http://localhost:8787/api/v1/import \
- -H "Content-Type: application/json" \
- -d @backup.json
-```
-
----
-
-## High Availability
-
-### Active-Active
-
-```yaml
-services:
- headroom-1:
- image: headroom-ai/headroom:latest
- ports:
- - "8787:8787"
-
- headroom-2:
- image: headroom-ai/headroom:latest
- ports:
- - "8788:8787"
-
- redis:
- image: redis:latest
-```
-
-### Health Check Failover
-
-```bash
-curl http://primary:8787/health || curl http://backup:8787/health
-```
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial disaster recovery document |
diff --git a/docs/spec/014-governance.md b/docs/spec/014-governance.md
deleted file mode 100644
index 03640193a..000000000
--- a/docs/spec/014-governance.md
+++ /dev/null
@@ -1,129 +0,0 @@
-# 014. Governance
-
-**Status:** done
-
-## Project Structure
-
-- **Repository:** `github.com/JerrettDavis/headroom`
-- **License:** Apache 2.0
-- **Main Languages:** Python (core), TypeScript (SDK/dashboard)
-
----
-
-## Release Cadence
-
-| Channel | Frequency | Stability |
-|---------|-----------|-----------|
-| Stable | Monthly | Production-ready |
-| Beta | As needed | May have issues |
-| Nightly | Daily | Unstable |
-
----
-
-## Semantic Versioning
-
-Headroom follows semver:
-
-- **MAJOR:** Breaking changes to API, CLI, or core behavior
-- **MINOR:** New features, backwards-compatible
-- **PATCH:** Bug fixes, backwards-compatible
-
----
-
-## Decision Making
-
-### RFC Process
-
-1. Open GitHub issue with `[RFC]` prefix
-2. Gather community feedback (2 weeks minimum)
-3. Core team reviews
-4. Decision documented in ADRs
-5. Implementation proceeds
-
-### Criteria for Core Team Approval
-
-- Consistent with project vision
-- Does not break existing guarantees
-- Implementation is feasible
-- Tests can be written
-
----
-
-## Spec-Driven Development
-
-This specification is the **canonical source of truth** for Headroom behavior:
-
-| Rule | Description |
-|------|-------------|
-| **Canonical** | When code and spec diverge, the spec is the target |
-| **Living** | Spec updates required for behavior-changing changes |
-| **Comprehensive** | Spec covers every user-visible surface |
-| **Language-agnostic** | Enables complete rewrite in any language |
-
-### Spec Change Process
-
-1. Propose change in GitHub issue
-2. Discuss in RFC format
-3. Update relevant spec section
-4. Update SPEC.md version and change log
-5. Implement code change
-6. Verify implementation matches spec
-
----
-
-## Supply Chain Posture
-
-| Component | Policy |
-|-----------|--------|
-| Dependencies | Pin versions, audit regularly |
-| Build artifacts | Reproducible builds |
-| Signing | Code signed for releases |
-| Vulnerability reporting | See SECURITY.md |
-
----
-
-## Contributing
-
-### Development Setup
-
-```bash
-# Clone repository
-git clone https://github.com/JerrettDavis/headroom.git
-cd headroom
-
-# Create virtual environment
-python -m venv venv
-source venv/bin/activate
-
-# Install dependencies
-pip install -e ".[dev]"
-
-# Run tests
-pytest
-```
-
-### Code Style
-
-- Format: `ruff format`
-- Lint: `ruff check`
-- Type check: `mypy`
-
----
-
-## Code of Conduct
-
-See `CODE_OF_CONDUCT.md`.
-
----
-
-## Security
-
-See `SECURITY.md` for vulnerability reporting and response timeline.
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial governance document |
diff --git a/docs/spec/015-interfaces.md b/docs/spec/015-interfaces.md
deleted file mode 100644
index 3972cd87e..000000000
--- a/docs/spec/015-interfaces.md
+++ /dev/null
@@ -1,351 +0,0 @@
-# 015. Interfaces
-
-**Status:** done
-
-## CLI Surface
-
-### `headroom proxy`
-
-Start the Headroom proxy server.
-
-```bash
-headroom proxy [OPTIONS]
-```
-
-**Options:**
-| Flag | Default | Description |
-|------|---------|-------------|
-| `--host` | `127.0.0.1` | Bind host |
-| `--port` | `8787` | Bind port |
-| `--mode` | `token` | Optimization mode: `token` or `cache` |
-| `--workers` | `1` | Uvicorn worker processes |
-| `--limit-concurrency` | `1000` | Maximum concurrent connections before 503 |
-| `--no-optimize` | `false` | Passthrough mode |
-| `--no-cache` | `false` | Disable semantic cache |
-| `--no-rate-limit` | `false` | Disable rate limiting |
-| `--memory` | `false` | Enable persistent memory |
-| `--learn` | `false` | Enable live traffic learning |
-| `--backend` | `anthropic` | Backend: anthropic, bedrock, openrouter, anyllm, or litellm-* |
-| `--telemetry` | `false` | Opt in to anonymous telemetry (off by default) |
-| `--no-telemetry` | `false` | Force anonymous telemetry off (already the default) |
-| `--stateless` | `false` | Disable filesystem writes |
-
----
-
-### `headroom evals`
-
-Run evaluation suite.
-
-```bash
-headroom evals [OPTIONS]
-```
-
-**Options:**
-| Flag | Default | Description |
-|------|---------|-------------|
-| `--suite` | `all` | Evaluation suite to run |
-| `--output` | - | Output file for results |
-
----
-
-### `headroom install`
-
-Install agent integrations.
-
-```bash
-headroom install [OPTIONS]
-```
-
-**Options:**
-| Flag | Default | Description |
-|------|---------|-------------|
-| `--agent` | - | Agent type (claude/copilot/codex/aider/cursor/openclaw) |
-
----
-
-### `headroom mcp`
-
-Manage the Headroom MCP server.
-
-```bash
-headroom mcp [OPTIONS] COMMAND [ARGS]...
-```
-
-**Commands:**
-- `install` — Install the MCP server into detected coding agents
-- `serve` — Start the stdio MCP server
-- `status` — Check configuration status
-- `uninstall` — Remove Headroom MCP config
-
----
-
-### `headroom perf`
-
-Run performance tests.
-
-```bash
-headroom perf [OPTIONS]
-```
-
----
-
-### `headroom wrap`
-
-Wrap a command with Headroom proxy.
-
-```bash
-headroom wrap [OPTIONS] -- [args...]
-```
-
-**Options:**
-| Flag | Default | Description |
-|------|---------|-------------|
-| `--port` | `8787` | Proxy port |
-| `--no-context-tool` / `--no-rtk` | `false` | Skip CLI context-tool setup |
-
-**Supported Commands:**
-- `claude` — Wrap Claude Code
-- `copilot` — Wrap GitHub Copilot
-- `codex` — Wrap OpenAI Codex
-- `aider` — Wrap Aider
-- `cursor` — Wrap Cursor
-- `openclaw` — Wrap OpenClaw
-
----
-
-### `headroom memory`
-
-Memory system management (requires numpy/hnswlib).
-
-```bash
-headroom memory [OPTIONS]
-```
-
-**Commands:**
-- `list` — List stored memories
-- `stats` — Show memory statistics
-- `search QUERY` — Search memories
-
----
-
-### `headroom learn`
-
-Run learn mode analysis.
-
-```bash
-headroom learn [OPTIONS]
-```
-
-**Options:**
-| Flag | Default | Description |
-|------|---------|-------------|
-| `--project` | current directory | Project directory to analyze |
-| `--all` | `false` | Analyze all discovered projects |
-| `--apply` | `false` | Write recommendations instead of dry-run |
-| `--agent` | `auto` | Agent to analyze: auto, claude, codex, gemini, or plugin |
-| `--model` | auto | LLM model for analysis |
-| `--workers` | auto | Parallel workers for session scanning |
-
----
-
-### `headroom stats`
-
-Show savings statistics.
-
-```bash
-headroom stats [OPTIONS]
-```
-
-**Options:**
-| Flag | Default | Description |
-|------|---------|-------------|
-| `--period` | `24h` | Time period |
-| `--format` | `table` | Output format (table, json, csv) |
-
----
-
-### `headroom config`
-
-Manage configuration.
-
-```bash
-headroom config [COMMAND] [OPTIONS]
-```
-
-**Commands:**
-- `get KEY` — Get config value
-- `set KEY VALUE` — Set config value
-- `list` — List all config
-- `export` — Export config to file
-
----
-
-## HTTP API
-
-### Endpoints
-
-| Method | Path | Description |
-|--------|------|-------------|
-| `GET` | `/health` | Health check |
-| `GET` | `/livez` | Liveness check |
-| `GET` | `/readyz` | Readiness check |
-| `POST` | `/v1/messages` | Proxy chat completions |
-| `POST` | `/v1/embeddings` | Proxy embeddings |
-| `POST` | `/v1/compress` | Direct compression |
-| `POST` | `/v1/retrieve` | CCR retrieval |
-| `GET` | `/stats` | Compression statistics |
-| `GET` | `/metrics` | Prometheus metrics |
-
-### Request/Response Examples
-
-**POST /v1/messages:**
-```bash
-curl -X POST http://localhost:8787/v1/messages \
- -H "Content-Type: application/json" \
- -H "Authorization: Bearer sk-..." \
- -d '{
- "model": "gpt-4o",
- "messages": [{"role": "user", "content": "Hello"}]
- }'
-```
-
-**Response headers:**
-```
-X-Headroom-Savings: 0.35
-X-Headroom-Original-Tokens: 8192
-X-Headroom-Compressed-Tokens: 5325
-```
-
----
-
-## Environment Variables
-
-### Core
-
-| Variable | Default | Description |
-|----------|---------|-------------|
-| `HEADROOM_MODE` | `token` | Proxy optimization mode (`token` or `cache`) |
-| `HEADROOM_PORT` | `8787` | Proxy port |
-| `HEADROOM_HOST` | `127.0.0.1` | Proxy host |
-| `HEADROOM_WORKERS` | `1` | Uvicorn worker count |
-| `HEADROOM_LIMIT_CONCURRENCY` | `1000` | Maximum concurrent connections before 503 |
-| `HEADROOM_MAX_CONNECTIONS` | `500` | Maximum upstream HTTP connections |
-| `HEADROOM_MAX_KEEPALIVE` | `100` | Maximum upstream keep-alive connections |
-| `HEADROOM_BUDGET` | - | Daily budget limit in USD |
-| `HEADROOM_TELEMETRY` | `off` (opt-in) | Set to `on` to opt in to anonymous telemetry |
-| `HEADROOM_STATELESS` | `false` | Disable filesystem writes |
-
-### Provider
-
-| Variable | Default | Description |
-|----------|---------|-------------|
-| `ANTHROPIC_API_KEY` | - | Anthropic API key |
-| `OPENAI_API_KEY` | - | OpenAI API key |
-| `GOOGLE_API_KEY` | - | Google AI API key |
-| `COHERE_API_KEY` | - | Cohere API key |
-
-### Features
-
-| Variable | Default | Description |
-|----------|---------|-------------|
-| `HEADROOM_TELEMETRY` | `off` (opt-in) | Set to `on` to opt in to telemetry |
-| `HEADROOM_MIN_EVIDENCE` | `5` | Minimum observations before live learning persists a pattern |
-| `HEADROOM_PROXY_EXTENSIONS` | - | Comma-separated proxy extensions to enable |
-| `HEADROOM_STATELESS` | `false` | Disable filesystem writes |
-| `HEADROOM_MODEL_LIMITS` | - | Model limits override as JSON or file path |
-
-### Compression
-
-| Variable | Default | Description |
-|----------|---------|-------------|
-| `HEADROOM_MAX_TOKENS` | `4096` | Max tokens per request |
-| `HEADROOM_TARGET_TOKENS` | - | Target tokens after compression |
-| `HEADROOM_OVERLAP_TOKENS` | `512` | Overlap tokens for chunking |
-| `HEADROOM_CONTENT_SENSITIVITY` | `0.5` | Content sensitivity (0-1) |
-| `HEADROOM_PRESERVE_SYSTEM` | `true` | Preserve system messages |
-
----
-
-## Plugin ABI
-
-### Plugin Interface
-
-```python
-from abc import ABC, abstractmethod
-from headroom.learn.base import ConversationScanner, ContextWriter
-from headroom.learn.models import ProjectInfo, SessionData
-
-class LearnPlugin(ConversationScanner):
- """A self-contained learn plugin for a single coding agent."""
-
- @property
- @abstractmethod
- def name(self) -> str:
- """Short lowercase identifier (e.g., 'claude', 'cursor')."""
- ...
-
- @property
- @abstractmethod
- def display_name(self) -> str:
- """Human-readable name (e.g., 'Claude Code', 'Cursor')."""
- ...
-
- @abstractmethod
- def detect(self) -> bool:
- """Return True if this agent has data on the current machine."""
- ...
-
- @abstractmethod
- def discover_projects(self) -> list[ProjectInfo]:
- """Discover all projects with conversation data."""
- ...
-
- @abstractmethod
- def scan_project(self, project: ProjectInfo, max_workers: int = 1) -> list[SessionData]:
- """Scan all sessions for a project."""
- ...
-
- @abstractmethod
- def create_writer(self) -> ContextWriter:
- """Return the appropriate ContextWriter for this agent."""
- ...
-```
-
-### Plugin Registration
-
-Plugins are auto-discovered from `headroom/learn/plugins/` directory.
-
-**Manual registration:**
-```python
-from headroom.learn import plugin_registry
-
-plugin_registry.register(MyPlugin())
-```
-
-### Plugin Config
-
-```yaml
-# ~/.headroom/config.yaml
-learn:
- enabled: true
- plugins:
- - name: claude
- enabled: true
- config:
- session_modes:
- - auto
- - learn
- - disabled
- - name: my_plugin
- enabled: true
- config:
- custom_option: value
-```
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial interfaces document |
diff --git a/docs/spec/016-observability.md b/docs/spec/016-observability.md
deleted file mode 100644
index fae8b5fcf..000000000
--- a/docs/spec/016-observability.md
+++ /dev/null
@@ -1,173 +0,0 @@
-# 016. Observability
-
-**Status:** done
-
-## Telemetry
-
-### Metrics
-
-Headroom exposes Prometheus metrics at `/metrics`.
-
-**Key Metrics:**
-
-| Metric | Type | Description |
-|--------|------|-------------|
-| `headroom_requests_total` | Counter | Total requests |
-| `headroom_tokens_original` | Counter | Original token count |
-| `headroom_tokens_compressed` | Counter | Compressed token count |
-| `headroom_savings_percent` | Histogram | Savings distribution |
-| `headroom_cache_hits_total` | Counter | Cache hits |
-| `headroom_cache_misses_total` | Counter | Cache misses |
-| `headroom_compression_duration_seconds` | Histogram | Compression latency |
-| `headroom_request_duration_seconds` | Histogram | Total request latency |
-
-**Prometheus scrape config:**
-```yaml
-scrape_configs:
- - job_name: 'headroom'
- static_configs:
- - targets: ['localhost:8787']
- metrics_path: '/metrics'
-```
-
----
-
-### Tracing
-
-OpenTelemetry tracing support.
-
-**Configuration (Langfuse):**
-```bash
-LANGFUSE_PUBLIC_KEY=pk-lf-...
-LANGFUSE_SECRET_KEY=sk-lf-...
-HEADROOM_LANGFUSE_ENABLED=1
-# Optional: override endpoint and service name
-# LANGFUSE_BASE_URL=https://cloud.langfuse.com
-# HEADROOM_LANGFUSE_SERVICE_NAME=headroom
-```
-
-**Spans:**
-| Span | Description |
-|------|-------------|
-| `headroom.proxy.request` | Full request lifecycle |
-| `headroom.compression` | Compression operation |
-| `headroom.cache.lookup` | Cache check |
-| `headroom.provider.call` | Provider API call |
-
----
-
-### Logging
-
-**Log Levels:**
-
-| Level | Use Case |
-|-------|----------|
-| `DEBUG` | Detailed debugging |
-| `INFO` | General operation |
-| `WARNING` | Degraded operation |
-| `ERROR` | Failures |
-
-**Log Format (JSON):**
-```json
-{
- "timestamp": "2026-04-16T12:00:00Z",
- "level": "INFO",
- "message": "Request completed",
- "request_id": "abc123",
- "savings": 0.45,
- "duration_ms": 120
-}
-```
-
-**Configuration:**
-```bash
-# Logging level is controlled via the --log-level CLI flag (headroom proxy --log-level debug)
-# or RUST_LOG env var for the Rust proxy. No HEADROOM_LOG_LEVEL env var exists.
-```
-
-Or in config:
-```yaml
-logging:
- level: INFO
- format: json
-```
-
----
-
-## Dashboard
-
-**URL:** `http://localhost:8787/dashboard`
-
-**Metrics Shown:**
-- Total savings over time
-- Requests per day
-- Cache hit rate
-- Top compressed endpoints
-- Session overview
-
-**Requires:** the proxy process to be running. The dashboard is served by default at `/dashboard`.
-
----
-
-## Alerting
-
-### Recommended Alerts
-
-| Alert | Condition | Severity |
-|-------|-----------|----------|
-| HighErrorRate | error_rate > 5% | warning |
-| LowSavings | savings < 20% | warning |
-| CacheDown | cache_hits < 10% for 1h | critical |
-| ProxyDown | health check fails | critical |
-
-**Alert rule example (Prometheus):**
-```yaml
-groups:
- - name: headroom
- rules:
- - alert: HighErrorRate
- expr: rate(headroom_errors_total[5m]) / rate(headroom_requests_total[5m]) > 0.05
- for: 5m
- labels:
- severity: warning
- annotations:
- summary: "High error rate in Headroom"
-```
-
----
-
-## Health Endpoints
-
-| Endpoint | Method | Description |
-|----------|--------|-------------|
-| `/health` | GET | Basic health check |
-| `/livez` | GET | Liveness check (process alive) |
-| `/readyz` | GET | Readiness check (can serve traffic) |
-
-**Health response:**
-```json
-{
- "status": "healthy",
- "version": "1.0.0"
-}
-```
-
-**Readiness response:**
-```json
-{
- "ready": true,
- "checks": {
- "database": true,
- "cache": true,
- "provider": true
- }
-}
-```
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial observability document |
diff --git a/docs/spec/017-operations.md b/docs/spec/017-operations.md
deleted file mode 100644
index ec429ba10..000000000
--- a/docs/spec/017-operations.md
+++ /dev/null
@@ -1,176 +0,0 @@
-# 017. Operations
-
-**Status:** done
-
-## Health Endpoints
-
-### `GET /health`
-
-Basic health check. Returns 200 if process is running.
-
-```bash
-curl http://localhost:8787/health
-```
-
-**Response:**
-```json
-{
- "status": "healthy",
- "version": "1.0.0"
-}
-```
-
----
-
-### `GET /livez`
-
-Liveness check. Returns 200 if process is alive.
-
-```bash
-curl http://localhost:8787/livez
-```
-
----
-
-### `GET /readyz`
-
-Readiness check. Returns 200 if ready to serve traffic.
-
-```bash
-curl http://localhost:8787/readyz
-```
-
-**Response:**
-```json
-{
- "ready": true,
- "checks": {
- "database": true,
- "cache": true,
- "provider": true
- }
-}
-```
-
----
-
-## Logs
-
-### Log Locations
-
-| Installation | Location |
-|-------------|----------|
-| Docker | `docker logs headroom` |
-| Native | `~/.headroom/logs/` |
-| Systemd | `journalctl -u headroom` |
-
-### Log Levels
-
-Set via CLI flag or `RUST_LOG` env var for the Rust proxy:
-```bash
-# Python proxy
-headroom proxy --log-level debug
-
-# Rust proxy
-RUST_LOG=debug headroom-proxy --upstream http://...
-```
-
----
-
-## Metrics
-
-### Prometheus
-
-**Scrape Config:**
-```yaml
-scrape_configs:
- - job_name: 'headroom'
- static_configs:
- - targets: ['localhost:8787']
- metrics_path: '/metrics'
-```
-
----
-
-## Upgrade Procedure
-
-### Docker
-
-```bash
-docker pull headroom-ai/headroom:latest
-docker-compose down
-docker-compose up -d
-```
-
-### Native
-
-```bash
-pip install --upgrade headroom-ai
-# Restart headroom service
-```
-
-### Embedded
-
-```bash
-pip install --upgrade headroom-ai
-# Restart application
-```
-
----
-
-## Rollback
-
-### Docker
-
-```bash
-docker-compose down
-docker tag headroom-ai/headroom:latest headroom-ai/headroom:rollback
-# Edit docker-compose.yml to use rollback tag
-docker-compose up -d
-```
-
----
-
-## Monitoring
-
-### Key Metrics to Watch
-
-1. **Request rate** — requests per second
-2. **Error rate** — 4xx + 5xx / total
-3. **Savings rate** — average savings percentage
-4. **Latency** — p50, p95, p99
-5. **Cache hit rate** — hits / total
-
-**Prometheus queries:**
-```promql
-# Request rate
-rate(headroom_requests_total[5m])
-
-# Error rate
-rate(headroom_errors_total[5m]) / rate(headroom_requests_total[5m])
-
-# Average savings
-rate(headroom_tokens_original[5m] - headroom_tokens_compressed[5m]) / rate(headroom_tokens_original[5m])
-
-# Cache hit rate
-rate(headroom_cache_hits_total[5m]) / (rate(headroom_cache_hits_total[5m]) + rate(headroom_cache_misses_total[5m]))
-```
-
----
-
-## Runbook
-
-| Symptom | Cause | Solution |
-|---------|-------|----------|
-| "Connection refused" | Proxy not running | Start it with `headroom proxy` |
-| "Cache miss on every request" | Cache disabled | Start without `--no-cache` |
-| "No savings shown" | Database locked | Check file permissions |
-| "Provider timeout" | Network issue | Check firewall/proxy |
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial operations document |
diff --git a/docs/spec/018-policies.md b/docs/spec/018-policies.md
deleted file mode 100644
index 6a989351f..000000000
--- a/docs/spec/018-policies.md
+++ /dev/null
@@ -1,118 +0,0 @@
-# 018. Policies
-
-**Status:** done
-
-## Default Behaviors
-
-### Compression
-
-| Setting | Default | Description |
-|---------|---------|-------------|
-| Compression enabled | `true` | Apply compression by default |
-| Cache enabled | `true` | Use semantic cache |
-| Summary enabled | `true` | Use summary compression |
-| Token budget enforced | `false` | No budget limit by default |
-
-### Telemetry
-
-| Setting | Default | Description |
-|---------|---------|-------------|
-| Metrics enabled | `true` | Emit Prometheus metrics |
-| Tracing enabled | `false` | No OTEL tracing |
-| Dashboard enabled | `false` | No built-in dashboard |
-
-### Learn
-
-| Setting | Default | Description |
-|---------|---------|-------------|
-| Learn enabled | `false` | Learning disabled |
-| Plugin auto-detect | `true` | Auto-load plugins |
-| Feedback collection | `false` | No CCR feedback |
-
----
-
-## Override Mechanisms
-
-### Environment Variables
-
-All settings can be overridden via environment variables:
-```bash
-HEADROOM_MODE=token
-headroom proxy --no-cache
-```
-
-### Config File
-
-```yaml
-# ~/.headroom/config.yaml
-proxy:
- host: 0.0.0.0
- port: 8787
-
-compression:
- enabled: true
- cache:
- enabled: true
- ttl: 3600
-
-telemetry:
- metrics:
- enabled: true
- tracing:
- enabled: false
-
-learn:
- enabled: false
-```
-
-### Runtime API
-
-```bash
-# Disable compression for single request
-curl -X POST http://localhost:8787/v1/messages \
- -H "X-Headroom-Compress: false"
-```
-
-### Runtime Headers
-
-| Header | Description |
-|--------|-------------|
-| `X-Headroom-Compress` | Override compression (true/false) |
-| `X-Headroom-Mode` | Override mode (passthrough/compress/learn) |
-| `X-Headroom-Cache` | Override cache (true/false) |
-
----
-
-## Policy Hierarchy
-
-Settings are evaluated in this order (highest wins):
-
-1. **Runtime headers** — Per-request overrides
-2. **Environment variables** — Process-level
-3. **Config file** — Persistent settings
-4. **Defaults** — Built-in defaults
-
----
-
-## Per-Tenant Policies (TOIN)
-
-TOIN tenants can have custom policies:
-
-```yaml
-tenant:
- id: "acme-corp"
- policies:
- compression:
- enabled: true
- threshold: 3000
- budget:
- daily_limit: 1000000
-```
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial policies document |
diff --git a/docs/spec/019-quality.md b/docs/spec/019-quality.md
deleted file mode 100644
index 0cd0af1bd..000000000
--- a/docs/spec/019-quality.md
+++ /dev/null
@@ -1,111 +0,0 @@
-# 019. Quality
-
-**Status:** done
-
-## Test Pyramid
-
-```
- ┌─────────────┐
- │ E2E │ ← Few, slow, comprehensive
- │ Tests │
- └──────┬──────┘
- │
- ┌──────┴──────┐
- │ Integration │ ← Medium, moderate
- │ Tests │
- └──────┬──────┘
- │
- ┌────────────┴────────────┐
- │ │
-┌────┴────┐ ┌────┴────┐
-│ Unit │ │ Unit │
-│ Tests │ │ Tests │
-└─────────┘ └─────────┘
-Many, fast, isolated
-```
-
----
-
-## Test Coverage
-
-| Surface | Unit | Integration | E2E |
-|---------|:----:|:------------:|:---:|
-| Proxy Server | ✓ | ✓ | ✓ |
-| SDK | ✓ | ✓ | - |
-| Compression | ✓ | ✓ | ✓ |
-| Cache | ✓ | ✓ | - |
-| Learn | ✓ | ✓ | - |
-| CCR | ✓ | ✓ | ✓ |
-| TOIN | ✓ | ✓ | - |
-| Dashboard | ✓ | - | ✓ |
-
----
-
-## Coverage Targets
-
-| Metric | Target | Threshold |
-|--------|--------|-----------|
-| Line coverage | 80% | 70% |
-| Branch coverage | 70% | 60% |
-| Critical path | 100% | 100% |
-
----
-
-## Critical Paths
-
-These must always pass:
-
-1. **Compression pipeline** — Input → Compress → Output
-2. **Cache hit path** — Input → Cache check → Return
-3. **Provider proxy** — Request → Proxy → Provider → Response
-4. **Learn feedback** — Session → Analyze → Compress → Store
-
----
-
-## Performance Benchmarks
-
-| Operation | Target | Threshold |
-|-----------|--------|-----------|
-| Compression | < 50ms | < 200ms |
-| Cache lookup | < 5ms | < 20ms |
-| Proxy latency | +10ms | +50ms |
-
----
-
-## CI/CD
-
-### Required Checks
-
-| Check | Command | Timeout |
-|-------|---------|---------|
-| Lint | `ruff check` | 2m |
-| Type check | `mypy` | 5m |
-| Unit tests | `pytest tests/unit/` | 10m |
-| Integration | `pytest tests/ -k integration` | 15m |
-| E2E | `pytest e2e/` | 30m |
-
-### Workflow (`.github/workflows/`)
-
-1. **Lint** — `ruff check` + `ruff format --check`
-2. **Type check** — `mypy src/`
-3. **Unit tests** — `pytest tests/unit/ --cov`
-4. **Integration** — `pytest tests/ -k integration`
-5. **E2E** — `pytest e2e/ --api-key=$ANTHROPIC_API_KEY`
-
----
-
-## Quality Gates
-
-PRs must pass:
-- All tests green
-- Type checking passes (`mypy`)
-- Lint passes (`ruff`)
-- Coverage maintained or improved
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial quality document |
diff --git a/docs/spec/020-security.md b/docs/spec/020-security.md
deleted file mode 100644
index 8c5477c61..000000000
--- a/docs/spec/020-security.md
+++ /dev/null
@@ -1,120 +0,0 @@
-# 020. Security
-
-**Status:** done
-
-## Threat Model
-
-### Threats
-
-| Threat | Impact | Mitigation |
-|--------|--------|------------|
-| Prompt data exfiltration | High | No logging, local-only |
-| API key theft | High | Key rotation, secrets management |
-| Cache poisoning | Medium | Input validation |
-| DoS via large prompts | Medium | Token limits |
-| SSRF via redirects | Medium | URL validation |
-
----
-
-### Trust Boundaries
-
-```
-┌──────────────────┐ ┌──────────────────┐
-│ User's App │────▶│ Headroom Proxy │
-└──────────────────┘ └────────┬─────────┘
- │
- ┌────────┴─────────┐
- │ │
- ┌─────▼─────┐ ┌──────▼──────┐
- │ Provider │ │ Database │
- │ APIs │ │ (SQLite) │
- └───────────┘ └─────────────┘
-```
-
----
-
-## Security Controls
-
-### Authentication
-
-| Surface | Auth Method |
-|---------|-------------|
-| Proxy | API key (optional) |
-| Dashboard | None by default |
-| Health endpoints | None |
-| Metrics | None |
-
-### Authorization
-
-- **No multi-user support** — Single-tenant by design
-- **API keys** — For proxy authentication
-- **CORS** — Configurable origins
-
----
-
-## Data Protection
-
-| Data | At Rest | In Transit |
-|------|---------|------------|
-| Prompts | Encrypted (if DB encrypted) | TLS |
-| Responses | Encrypted (if DB encrypted) | TLS |
-| API keys | Encrypted | TLS |
-| Metrics | Plain text | TLS |
-
----
-
-## Input Validation
-
-- **Prompt length** — Enforced via token budget
-- **URL validation** — For provider redirects
-- **Schema validation** — For all API inputs
-
----
-
-## Secrets Management
-
-### Environment Variables
-
-```bash
-ANTHROPIC_API_KEY=sk-...
-OPENAI_API_KEY=sk-...
-```
-
-### Secrets Management Systems
-
-Headroom supports:
-- AWS Secrets Manager
-- HashiCorp Vault
-- Azure Key Vault
-
----
-
-## Supply Chain Security
-
-### Dependencies
-
-- **Pinned versions** — All dependencies pinned
-- **Audit** — Regular `pip audit`
-- **SBOM** — Software Bill of Materials generated
-
-### Build
-
-- **Reproducible** — Docker builds are reproducible
-- **Signed releases** — Code signed
-
----
-
-## Vulnerability Reporting
-
-See `SECURITY.md` for:
-- Reporting process
-- Response timeline
-- Disclosure policy
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial security document |
diff --git a/docs/spec/021-testing.md b/docs/spec/021-testing.md
deleted file mode 100644
index 47e9e8a31..000000000
--- a/docs/spec/021-testing.md
+++ /dev/null
@@ -1,162 +0,0 @@
-# 021. Testing
-
-**Status:** done
-
-## Test Strategy by Surface
-
-### Proxy Server
-
-**Unit Tests:**
-- Request routing
-- Response header injection
-- Mode switching
-- Error handling
-
-**Integration Tests:**
-- Full request/response cycle
-- Provider mocking
-- Cache integration
-
-**E2E Tests:**
-- Against real provider APIs (with API keys)
-
----
-
-### Compression
-
-**Unit Tests:**
-- Token counting
-- Semantic hashing
-- Summary compression
-- Budget enforcement
-
-**Integration Tests:**
-- Cache round-trip
-- Multi-stage compression
-
-**Benchmarks:**
-- Latency at scale
-- Memory usage
-
----
-
-### Learn System
-
-**Unit Tests:**
-- Plugin interface compliance
-- Error classification
-- Session analysis
-
-**Integration Tests:**
-- Plugin discovery
-- Cross-plugin interaction
-
-**E2E Tests:**
-- Real session analysis
-
----
-
-### CCR (Claude Code Relay)
-
-**Unit Tests:**
-- Context tracking
-- Feedback collection
-- Batch processing
-
-**Integration Tests:**
-- Tool injection
-- Response handling
-
-**E2E Tests:**
-- Full CCR workflow
-
----
-
-## Test Utilities
-
-### Fixtures
-
-Located in `tests/conftest.py`:
-- `mock_provider` — Mock AI provider
-- `sample_session` — Sample conversation
-- `temp_db` — Temporary database
-
-### Mock Libraries
-
-- `responses` — HTTP mocking
-- `pytest-mock` — Function mocking
-- `aioresponses` — Async HTTP mocking
-
----
-
-## Running Tests
-
-### All Tests
-
-```bash
-pytest
-```
-
-### By Surface
-
-```bash
-pytest tests/test_proxy/
-pytest tests/test_compression/
-pytest tests/test_learn/
-```
-
-### With Coverage
-
-```bash
-pytest --cov=headroom --cov-report=html
-```
-
-### E2E Tests
-
-```bash
-# Requires API keys
-pytest e2e/ --api-key=$ANTHROPIC_API_KEY
-```
-
----
-
-## Test Data
-
-### Sample Sessions
-
-Stored in `tests/fixtures/sessions/`:
-- `claude_code_short.json` — Short Claude Code session
-- `claude_code_long.json` — Long session with tool use
-- `codex_completion.json` — Codex completion
-- `gemini_multimodal.json` — Gemini with images
-
----
-
-## Continuous Integration
-
-### Required Checks
-
-| Check | Command | Timeout |
-|-------|---------|---------|
-| Lint | `ruff check` | 2m |
-| Type check | `mypy` | 5m |
-| Unit tests | `pytest tests/` | 10m |
-| Integration | `pytest tests/ -k integration` | 15m |
-| E2E | `pytest e2e/` | 30m |
-
----
-
-## Test Maintenance
-
-- **Fixtures** — Keep realistic but small
-- **Mocks** — Don't over-mock providers
-- **Flaky tests** — Mark with `@pytest.mark.flaky`
-- **Coverage drops** — PR blocked if coverage drops
-
----
-
-## Version History
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial testing document |
diff --git a/docs/spec/022-rust-migration.md b/docs/spec/022-rust-migration.md
deleted file mode 100644
index dadc03089..000000000
--- a/docs/spec/022-rust-migration.md
+++ /dev/null
@@ -1,98 +0,0 @@
-# 022. Rust Migration
-
-**Status:** in-progress (Stage 0 complete)
-
-Headroom is evolving from a pure-Python proxy into a Rust engine with a Python SDK layer. This document describes the motivation, target architecture, and phased execution plan. It is the source of truth for the migration; the Discord announcement and contributor docs are derived from it.
-
-## Why Rust
-
-Three forces push us toward Rust:
-
-1. **Latency.** Every LLM request flows through compression transforms on the hot path. Rust runs that math 2–10× faster than Python, with negligible interpreter overhead and near-instant cold starts.
-2. **Deployment.** A Rust proxy is a single static binary (~10 MB). No Python interpreter, no pip, no wheel matrix, no model downloads at startup. It drops cleanly into containers, serverless runtimes, or bare hosts.
-3. **Non-Python consumers.** Integrations like the TypeScript OpenClaw plugin talk to Headroom over HTTP. A faster proxy makes every downstream client faster without changing any client code.
-
-The Python code is not being thrown away. Rust lives alongside Python in the same repository, the HTTP contract stays stable, and existing users see no breaking changes.
-
-## Target architecture
-
-Two new artifacts, built over time:
-
-- **`headroom-proxy`** — a standalone Rust binary that speaks the existing Headroom HTTP API and contains native implementations of the proxy's hot-path logic (routing, streaming, compression, telemetry). This is the deployable artifact.
-- **`headroom-core`** — a Rust library with the compression transforms (CCR, log compressor, diff compressor, tokenizer, code compressor, content router, etc.). Consumed by `headroom-proxy` directly; optionally exposed to Python via a PyO3 binding if/when embedded SDK use warrants it.
-
-Both live in a Cargo workspace under `crates/` at the repo root. They are built, tested, and released together with the Python package.
-
-## Migration strategy
-
-**Trunk-based, no long-lived branch.** Every Rust change ships as a small PR to `main`. Rust and Python live side by side. CI enforces parity on every PR — if the Rust port diverges from the Python reference, the build fails.
-
-**Proxy-first, not transforms-first.** We build the Rust proxy binary as the primary deliverable, starting from a pure HTTP passthrough that forwards upstream to the existing Python proxy. Native Rust implementations of individual routes then replace passthroughs one at a time, gated by feature flags. This lets us ship a deployable Rust binary on day one and iterate without modifying Python internals.
-
-**Feature-flagged cutover.** Each native Rust route is toggled by config. Default is passthrough-to-Python until a route has been shadow-tested and validated. Rollback is a flag flip, not a redeploy.
-
-**Parity by shadow traffic.** Recorded input/output fixtures give us a unit-test-level parity check. Shadow mode — running both proxies on live traffic and diffing outputs — gives us the real validation gate before any cutover.
-
-## Stages
-
-### Stage 0 — Foundation ✅
-
-Cargo workspace with four crates (`headroom-core`, `headroom-proxy`, `headroom-py`, `headroom-parity`), CI, build tooling (Makefile, GitHub Actions), and a parity test harness seeded with 125 recorded fixtures across 5 leaf transforms. No production behavior changed.
-
-### Stage 1 — Rust proxy as passthrough
-
-`headroom-proxy` accepts requests on the same HTTP contract as the Python proxy and forwards everything upstream to Python. No transforms yet, no intelligence. The point is a deployable binary that can run in front of the existing stack with zero risk.
-
-### Stage 2 — First native route
-
-Replace the passthrough for `/v1/chat/completions` (OpenAI) with a native Rust implementation: Rust transforms, direct provider call, streamed response. Feature-flagged. Python proxy handles everything else unchanged.
-
-### Stage 3 — Shadow mode validation
-
-Run both proxies on real traffic. Diff outputs with tolerance for chunk timing (SSE). Gate: one week of ≤ 0.1% content divergence before flipping the flag for real.
-
-### Stage 4 — Provider expansion
-
-Anthropic, Google, Cohere, Mistral, Bedrock, others. Each provider goes through its own shadow period before cutover.
-
-### Stage 5 — Code-aware transforms
-
-Port `code_compressor` (tree-sitter, already Rust-native upstream), `content_router`, `content_detector`. These are larger transforms but have no ML dependencies.
-
-### Stage 6 — Storage layer
-
-SQLite (`rusqlite` + `sqlite-vec`), HNSW vector index (`instant-distance`), graph store (`neo4rs`). Feature-flagged backend for the memory subsystem.
-
-### Stage 7 — ONNX migration
-
-Remove the torch-dependent LLMLingua compressor. Convert remaining ML models (SmartCrusher, IntelligentContext, memory embedders) to ONNX with fixed opset. Run via the `ort` crate. Remove `torch`, `transformers`, `sentence-transformers`, `llmlingua` from runtime dependencies.
-
-### Stage 8 — Retire the Python proxy
-
-Delete `headroom/proxy/server.py` and the Python HTTP routes. The Python package (`import headroom`) continues to exist for SDK users and integration adapters (LangChain, Agno, MCP, Strands), which talk HTTP and don't care which proxy implementation is behind the endpoint.
-
-## What does not change
-
-- `pip install headroom` continues to work.
-- The HTTP API contract is preserved.
-- LangChain, Agno, MCP, Strands integrations keep working unchanged.
-- The CLI, dashboard, eval framework, examples, and documentation site are all unaffected.
-- Python contributions remain welcome for integrations, tooling, examples, and any code paths not yet ported.
-
-## Contributing
-
-- **Python contributors** do not need to learn Rust. CI will flag a PR if a Python change diverges from a Rust-ported counterpart; in that case either update both implementations or disable the feature flag for the affected route.
-- **Rust contributors** should read `RUST_DEV.md` for workspace setup, then pick a transform or proxy route from the open issues.
-
-## Risks and open questions
-
-- **ONNX export parity** for embedding models: numerical reproducibility must be validated per model before cutover. Some models may resist clean export and require keeping a Python inference path behind PyO3 as a fallback.
-- **LLMLingua removal** is a feature removal visible to users relying on it; deprecation timing will be announced on Discord before Stage 7 begins.
-- **PyO3 binding scope**: we may ultimately not need a PyO3-exposed `headroom._core` at all, if existing Python SDK users are happy with the HTTP contract. Decision deferred to Stage 8.
-
-## References
-
-- `RUST_DEV.md` — developer setup and workspace reference
-- `crates/` — Rust sources
-- `tests/parity/` — fixtures and parity harness
-- `Makefile` — `make test`, `make test-parity`, `make build-proxy`, `make build-wheel`, `make fmt`, `make lint`
diff --git a/docs/spec/SPEC.md b/docs/spec/SPEC.md
deleted file mode 100644
index 4005d99d3..000000000
--- a/docs/spec/SPEC.md
+++ /dev/null
@@ -1,88 +0,0 @@
-# Headroom Living Specification
-
-**Version:** 1.0.0-draft
-**Date:** 2026-04-16
-**Status:** Draft — In Progress
-**Related Issue:** GitHub #183
-
----
-
-## Constitution
-
-This specification is the **canonical source of truth** for how Headroom is designed to behave. It serves:
-
-1. **New contributors** — One place to understand how Headroom works
-2. **Enterprises evaluating adoption** — Clear guarantees about behavior, privacy, security
-3. **Operators running managed deployments** — Operational guidance for all surfaces
-4. **Plugin authors** — Clear contracts for extension points
-5. **PR review** — A checklist target: "does the code match the spec?"
-
-### Spec Governance
-
-| Rule | Description |
-|------|-------------|
-| **Canonical** | When code and spec diverge, the spec is the target; the code needs updating |
-| **Living** | Spec updates are required for behavior-changing changes (PR checklist) |
-| **Comprehensive** | Spec covers every user-visible surface, behavior, and guarantee |
-| **Language-agnostic** | Spec enables complete rewrite in any language with parity |
-| **Versioned** | Changes increment version; breaking changes require major version bump |
-
-### Spec Sections
-
-| # | Section | Status | Description |
-|---|---------|:------:|-------------|
-| 001 | [Vision](001-vision.md) | done | What Headroom is, what it is not |
-| 002 | [Architecture](002-architecture.md) | done | Component diagram + descriptions |
-| 003 | [ADRs](003-adrs.md) | done | Architecture Decision Records |
-| 004 | [Domain Model](004-domain-model.md) | done | Core entities |
-| 005 | [Integrations](005-integrations.md) | done | Agent contracts |
-| 006 | [Actors](006-actors.md) | done | User types + interactions |
-| 007 | [Behavior](007-behavior.md) | done | Mode-by-mode specification |
-| 008 | [Capabilities](008-capabilities.md) | done | Feature matrix |
-| 009 | [Compliance](009-compliance.md) | done | Data guarantees, privacy |
-| 010 | [Data](010-data.md) | done | Storage, retention, env vars |
-| 011 | [Deployment](011-deployment.md) | done | Profiles, presets, runtimes |
-| 012 | [Diagrams](012-diagrams.md) | done | Component, sequence, data-flow |
-| 013 | [Disaster Recovery](013-disaster-recovery.md) | done | Failure modes + recovery |
-| 014 | [Governance](014-governance.md) | done | Decision-making, releases |
-| 015 | [Interfaces](015-interfaces.md) | done | CLI, HTTP, env var, plugin ABI |
-| 016 | [Observability](016-observability.md) | done | Telemetry, metrics, logs |
-| 017 | [Operations](017-operations.md) | done | Health, logs, upgrades |
-| 018 | [Policies](018-policies.md) | done | Defaults + overrides |
-| 019 | [Quality](019-quality.md) | done | Test pyramid coverage |
-| 020 | [Security](020-security.md) | done | Threat model, supply-chain |
-| 021 | [Testing](021-testing.md) | done | Test strategy per surface |
-
----
-
-## Quick Reference
-
-### What Headroom Is
-
-- A **context compression proxy** for AI provider APIs
-- A **Python package** (`headroom-ai`) with proxy, SDK, and CLI
-- A **TypeScript SDK** (`@headroom/sdk`) for Node.js
-- A **dashboard** for visualizing savings
-- A **learn system** with per-agent plugins
-
-### What Headroom Is Not
-
-- A model provider
-- A data store for prompts (by default)
-- A logging service (by default)
-- A billing service
-
-### Core Guarantees
-
-1. **Never logs prompts by default** — No prompt data leaves the proxy unless an exporter is configured
-2. **Never leaves the proxy by default** — All data stays local unless explicitly exported
-3. **Composable** — Works alongside existing tools (Claude Code, Copilot, etc.)
-4. **Transparent** — Full observability into what's being compressed and why
-
----
-
-## Change Log
-
-| Version | Date | Changes |
-|---------|------|---------|
-| 1.0.0-draft | 2026-04-16 | Initial draft — 21 sections outlined |
diff --git a/docs/superpowers/plans/2026-06-19-deepseek-pricing.md b/docs/superpowers/plans/2026-06-19-deepseek-pricing.md
deleted file mode 100644
index 9c6a5458b..000000000
--- a/docs/superpowers/plans/2026-06-19-deepseek-pricing.md
+++ /dev/null
@@ -1,699 +0,0 @@
-# DeepSeek V4 Pricing Implementation Plan
-
-> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
-
-**Goal:** Add `deepseek-v4-flash` and `deepseek-v4-pro` pricing to Headroom so cost estimation works when routing through `--anthropic-api-url https://api.deepseek.com/anthropic`.
-
-**Architecture:** Four independent layers — (1) a new pricing data module following the `anthropic_prices.py` pattern, (2) runtime injection into `litellm.model_cost` so the primary cost-per-token path resolves DeepSeek V4, (3) a fallback in the Anthropic provider's `_get_pricing()` when LiteLLM is unavailable, and (4) vendored JSON entries for Rust-side context window lookups.
-
-**Tech Stack:** Python 3.12+, LiteLLM, Rust (vendored JSON), pytest
-
-## Global Constraints
-
-- All prices in USD per 1 million tokens (`ModelPricing` dataclass convention)
-- LiteLLM injection must not overwrite upstream entries if litellm already has DeepSeek V4
-- Provider field must be `"deepseek"` for all DeepSeek models
-- Follow exact patterns from `anthropic_prices.py` / `openai_prices.py` / `test_anthropic.py`
-- Vendored JSON entries at `crates/headroom-proxy/data/model_prices_and_context_window.json`
-
----
-
-### Task 1: DeepSeek Pricing Data Module
-
-**Files:**
-- Create: `headroom/pricing/deepseek_prices.py`
-- Modify: `headroom/pricing/__init__.py`
-- Test: `tests/test_providers/test_deepseek.py` (first test class)
-
-**Interfaces:**
-- Consumes: `ModelPricing`, `PricingRegistry` from `headroom.pricing.registry`
-- Produces: `DEEPSEEK_PRICES: dict[str, ModelPricing]`, `get_deepseek_registry() -> PricingRegistry`, exported via `headroom.pricing`
-
-- [ ] **Step 1: Write the failing tests for the pricing data module**
-
-Create `tests/test_providers/test_deepseek.py`:
-
-```python
-"""Tests for DeepSeek model pricing and cost estimation."""
-
-from headroom.pricing.deepseek_prices import (
- DEEPSEEK_PRICES,
- get_deepseek_registry,
-)
-from headroom.pricing.registry import PricingRegistry
-
-
-class TestDeepSeekPricingModule:
- """Tests for the DeepSeek pricing data module."""
-
- def test_deepseek_pricing_contains_v4_models(self):
- assert "deepseek-v4-flash" in DEEPSEEK_PRICES
- assert "deepseek-v4-pro" in DEEPSEEK_PRICES
- assert len(DEEPSEEK_PRICES) == 2
-
- def test_deepseek_v4_flash_pricing(self):
- pricing = DEEPSEEK_PRICES["deepseek-v4-flash"]
- assert pricing.input_per_1m == 0.14
- assert pricing.output_per_1m == 0.28
- assert pricing.cached_input_per_1m == 0.0028
- assert pricing.context_window == 1_000_000
- assert pricing.provider == "deepseek"
- assert pricing.notes is not None
-
- def test_deepseek_v4_pro_pricing(self):
- pricing = DEEPSEEK_PRICES["deepseek-v4-pro"]
- assert pricing.input_per_1m == 0.435
- assert pricing.output_per_1m == 0.87
- assert pricing.cached_input_per_1m == 0.003625
- assert pricing.context_window == 1_000_000
- assert pricing.provider == "deepseek"
- assert pricing.notes is not None
-
- def test_get_deepseek_registry(self):
- registry = get_deepseek_registry()
- assert isinstance(registry, PricingRegistry)
- assert registry.get_price("deepseek-v4-flash") is not None
- assert registry.get_price("deepseek-v4-pro") is not None
- assert registry.get_price("nonexistent") is None
-
- def test_registry_staleness_and_source_url(self):
- registry = get_deepseek_registry()
- assert registry.source_url == "https://api-docs.deepseek.com/quick_start/pricing"
- assert not registry.is_stale()
-
- def test_deepseek_registry_estimate_cost(self):
- registry = get_deepseek_registry()
- cost = registry.estimate_cost("deepseek-v4-flash", input_tokens=1_000_000)
- assert cost.cost_usd == 0.14
- assert "input" in cost.breakdown
- assert cost.pricing_date is not None
-
- def test_deepseek_registry_estimate_cost_with_cached(self):
- registry = get_deepseek_registry()
- cost = registry.estimate_cost(
- "deepseek-v4-flash",
- input_tokens=1_000_000,
- cached_input_tokens=1_000_000,
- )
- assert cost.cost_usd == 0.14 + 0.0028
-```
-
-- [ ] **Step 2: Run tests to verify they fail**
-
-```bash
-cd D:/headroom && python -m pytest tests/test_providers/test_deepseek.py::TestDeepSeekPricingModule -v
-```
-
-Expected: ModuleNotFoundError or ImportError — `deepseek_prices` doesn't exist yet.
-
-- [ ] **Step 3: Create the pricing data module**
-
-Create `headroom/pricing/deepseek_prices.py`:
-
-```python
-"""DeepSeek model pricing information."""
-
-from datetime import date
-
-from .registry import ModelPricing, PricingRegistry
-
-# Last verified date for pricing information
-LAST_UPDATED = date(2026, 6, 19)
-
-# Official pricing page
-SOURCE_URL = "https://api-docs.deepseek.com/quick_start/pricing"
-
-# All prices are in USD per 1 million tokens
-DEEPSEEK_PRICES: dict[str, ModelPricing] = {
- "deepseek-v4-flash": ModelPricing(
- model="deepseek-v4-flash",
- provider="deepseek",
- input_per_1m=0.14,
- output_per_1m=0.28,
- cached_input_per_1m=0.0028,
- context_window=1_000_000,
- notes="DeepSeek V4 Flash - 13B active params; non-thinking + thinking modes",
- ),
- "deepseek-v4-pro": ModelPricing(
- model="deepseek-v4-pro",
- provider="deepseek",
- input_per_1m=0.435,
- output_per_1m=0.87,
- cached_input_per_1m=0.003625,
- context_window=1_000_000,
- notes="DeepSeek V4 Pro - 49B active params",
- ),
-}
-
-
-def get_deepseek_registry() -> PricingRegistry:
- """Create and return a DeepSeek pricing registry.
-
- Returns:
- PricingRegistry configured with DeepSeek model prices.
- """
- return PricingRegistry(
- last_updated=LAST_UPDATED,
- source_url=SOURCE_URL,
- prices=DEEPSEEK_PRICES.copy(),
- )
-```
-
-- [ ] **Step 4: Wire into `__init__.py`**
-
-Edit `headroom/pricing/__init__.py` — add these imports after the existing OpenAI imports:
-
-```python
-from .deepseek_prices import (
- DEEPSEEK_PRICES,
- get_deepseek_registry,
-)
-from .deepseek_prices import (
- LAST_UPDATED as DEEPSEEK_LAST_UPDATED,
-)
-```
-
-And add to `__all__`:
-
-```python
- # DeepSeek
- "DEEPSEEK_LAST_UPDATED",
- "DEEPSEEK_PRICES",
- "get_deepseek_registry",
-```
-
-- [ ] **Step 5: Run tests to verify they pass**
-
-```bash
-cd D:/headroom && python -m pytest tests/test_providers/test_deepseek.py::TestDeepSeekPricingModule -v
-```
-
-Expected: 7 passed
-
-- [ ] **Step 6: Commit**
-
-```bash
-git add headroom/pricing/deepseek_prices.py headroom/pricing/__init__.py tests/test_providers/test_deepseek.py
-git commit -m "feat(pricing): add DeepSeek V4 pricing data module
-
-Add deepseek-v4-flash and deepseek-v4-pro ModelPricing entries and
-registry factory, following the pattern of anthropic_prices.py.
-Wire into pricing/__init__.py exports.
-
-Co-Authored-By: Claude "
-```
-
----
-
-### Task 2: LiteLLM Runtime Injection
-
-**Files:**
-- Modify: `headroom/pricing/litellm_pricing.py` (add injection after `LITELLM_AVAILABLE` block)
-- Test: `tests/test_providers/test_deepseek.py` (add `TestDeepSeekLiteLLMInjection` class)
-
-**Interfaces:**
-- Consumes: `litellm.model_cost` dict (available after import)
-- Produces: `"deepseek-v4-flash"`, `"deepseek/deepseek-v4-flash"`, `"deepseek-v4-pro"`, `"deepseek/deepseek-v4-pro"` keys in `litellm.model_cost`
-- Depends on: DEEPSEEK_V4_PRICING constant defined within litellm_pricing.py
-
-- [ ] **Step 1: Write failing injection tests**
-
-Append to `tests/test_providers/test_deepseek.py`:
-
-```python
-import pytest
-
-
-class TestDeepSeekLiteLLMInjection:
- """Tests for DeepSeek V4 pricing injection into litellm."""
-
- def test_deepseek_v4_models_in_litellm_model_cost(self):
- from headroom.pricing.litellm_pricing import litellm, LITELLM_AVAILABLE
- if not LITELLM_AVAILABLE:
- pytest.skip("litellm not available")
- assert "deepseek-v4-flash" in litellm.model_cost
- assert "deepseek-v4-pro" in litellm.model_cost
-
- def test_deepseek_v4_prefixed_models_in_litellm_model_cost(self):
- from headroom.pricing.litellm_pricing import litellm, LITELLM_AVAILABLE
- if not LITELLM_AVAILABLE:
- pytest.skip("litellm not available")
- assert "deepseek/deepseek-v4-flash" in litellm.model_cost
- assert "deepseek/deepseek-v4-pro" in litellm.model_cost
-
- def test_deepseek_v4_flash_litellm_pricing(self):
- from headroom.pricing.litellm_pricing import litellm, LITELLM_AVAILABLE
- if not LITELLM_AVAILABLE:
- pytest.skip("litellm not available")
- flash = litellm.model_cost["deepseek-v4-flash"]
- assert flash["input_cost_per_token"] == 0.14 / 1_000_000
- assert flash["output_cost_per_token"] == 0.28 / 1_000_000
- assert flash["cache_read_input_token_cost"] == 0.0028 / 1_000_000
- assert flash["litellm_provider"] == "deepseek"
-
- def test_deepseek_v4_pro_litellm_pricing(self):
- from headroom.pricing.litellm_pricing import litellm, LITELLM_AVAILABLE
- if not LITELLM_AVAILABLE:
- pytest.skip("litellm not available")
- pro = litellm.model_cost["deepseek-v4-pro"]
- assert pro["input_cost_per_token"] == 0.435 / 1_000_000
- assert pro["output_cost_per_token"] == 0.87 / 1_000_000
- assert pro["cache_read_input_token_cost"] == 0.003625 / 1_000_000
- assert pro["litellm_provider"] == "deepseek"
-
- def test_cost_per_token_resolves_deepseek_v4_flash(self):
- from headroom.pricing.litellm_pricing import litellm, LITELLM_AVAILABLE
- if not LITELLM_AVAILABLE:
- pytest.skip("litellm not available")
- input_cost, output_cost = litellm.cost_per_token(
- model="deepseek-v4-flash",
- prompt_tokens=1_000_000,
- completion_tokens=1_000_000,
- )
- assert input_cost == pytest.approx(0.14, rel=0.01)
- assert output_cost == pytest.approx(0.28, rel=0.01)
-
- def test_injection_does_not_overwrite_existing_upstream_entries(self):
- """If litellm upstream already has these, our injection is a no-op."""
- from headroom.pricing.litellm_pricing import litellm, LITELLM_AVAILABLE
- if not LITELLM_AVAILABLE:
- pytest.skip("litellm not available")
- # Force-inject with wrong value, then verify the injection guard
- litellm.model_cost["deepseek-v4-flash"] = {"input_cost_per_token": 999}
- # Reimport to trigger _inject_deepseek_pricing — but it should NOT overwrite
- import importlib
- import headroom.pricing.litellm_pricing as lp
- importlib.reload(lp)
- assert litellm.model_cost["deepseek-v4-flash"]["input_cost_per_token"] == 999
- # Reset to correct value
- litellm.model_cost["deepseek-v4-flash"] = {
- "input_cost_per_token": 0.14 / 1_000_000,
- "output_cost_per_token": 0.28 / 1_000_000,
- "cache_read_input_token_cost": 0.0028 / 1_000_000,
- "litellm_provider": "deepseek",
- "max_tokens": 384_000,
- "max_input_tokens": 1_000_000,
- }
-```
-
-- [ ] **Step 2: Run the injection tests to verify they fail**
-
-```bash
-cd D:/headroom && python -m pytest tests/test_providers/test_deepseek.py::TestDeepSeekLiteLLMInjection -v
-```
-
-Expected: Tests fail because `litellm.model_cost` doesn't have DeepSeek V4 entries yet.
-
-- [ ] **Step 3: Add the runtime injection to `litellm_pricing.py`**
-
-At the end of `headroom/pricing/litellm_pricing.py`, before the `_resolved_model_cache` and function definitions, add:
-
-```python
-# ============================================================
-# DeepSeek V4 pricing injection
-# ============================================================
-# Vendored LiteLLM JSON predates DeepSeek V4 models. Inject pricing at
-# import time so the primary cost-per-token path resolves them. Once
-# upstream litellm adds these entries, injection becomes a no-op.
-# ============================================================
-
-_DEEPSEEK_V4_PRICING: dict[str, dict[str, float | str | int]] = {
- "deepseek-v4-flash": {
- "input_cost_per_token": 0.14 / 1_000_000,
- "output_cost_per_token": 0.28 / 1_000_000,
- "cache_read_input_token_cost": 0.0028 / 1_000_000,
- "litellm_provider": "deepseek",
- "max_tokens": 384_000,
- "max_input_tokens": 1_000_000,
- },
- "deepseek-v4-pro": {
- "input_cost_per_token": 0.435 / 1_000_000,
- "output_cost_per_token": 0.87 / 1_000_000,
- "cache_read_input_token_cost": 0.003625 / 1_000_000,
- "litellm_provider": "deepseek",
- "max_tokens": 384_000,
- "max_input_tokens": 1_000_000,
- },
-}
-
-
-def _inject_deepseek_pricing() -> None:
- """Inject DeepSeek V4 pricing into litellm's model_cost dict.
-
- Only injects entries not already present, so upstream litellm additions
- (once available) take precedence. Both bare and provider-prefixed keys
- are added so resolve_litellm_model() catches them via its deepseek/
- prefix loop.
- """
- if not LITELLM_AVAILABLE:
- return
- for model_name, pricing in _DEEPSEEK_V4_PRICING.items():
- if model_name not in litellm.model_cost:
- litellm.model_cost[model_name] = pricing
- prefixed = f"deepseek/{model_name}"
- if prefixed not in litellm.model_cost:
- litellm.model_cost[prefixed] = pricing
-
-
-_inject_deepseek_pricing()
-```
-
-- [ ] **Step 4: Run tests to verify they pass**
-
-```bash
-cd D:/headroom && python -m pytest tests/test_providers/test_deepseek.py::TestDeepSeekLiteLLMInjection -v
-```
-
-Expected: All 6 tests pass (or some skip if litellm is unavailable — that's acceptable).
-
-- [ ] **Step 5: Commit**
-
-```bash
-git add headroom/pricing/litellm_pricing.py tests/test_providers/test_deepseek.py
-git commit -m "feat(pricing): inject DeepSeek V4 pricing into litellm model_cost
-
-Add runtime injection so litellm.cost_per_token() resolves
-deepseek-v4-flash and deepseek-v4-pro pricing. Includes both bare
-and provider-prefixed keys. No-ops if entries already exist.
-
-Co-Authored-By: Claude "
-```
-
----
-
-### Task 3: Anthropic Provider DeepSeek Fallback
-
-**Files:**
-- Modify: `headroom/providers/anthropic.py` (add `_get_deepseek_pricing()` helper and call in `_get_pricing()`)
-- Test: `tests/test_providers/test_deepseek.py` (add `TestDeepSeekAnthropicProviderFallback` class)
-
-**Interfaces:**
-- Consumes: `_get_pricing(self, model: str) -> dict | None` (inside `AnthropicProvider`)
-- Produces: DeepSeek pricing dicts from `_get_pricing("deepseek-*")` and `estimate_cost("deepseek-*")`
-
-- [ ] **Step 1: Write failing fallback tests**
-
-Append to `tests/test_providers/test_deepseek.py`:
-
-```python
-class TestDeepSeekAnthropicProviderFallback:
- """Tests that Anthropic provider's _get_pricing handles DeepSeek models."""
-
- def test_deepseek_v4_flash_fallback(self):
- from headroom.providers.anthropic import AnthropicProvider
- provider = AnthropicProvider()
- pricing = provider._get_pricing("deepseek-v4-flash")
- assert pricing is not None
- assert pricing["input"] == 0.14
- assert pricing["output"] == 0.28
- assert pricing["cached_input"] == 0.0028
-
- def test_deepseek_v4_pro_fallback(self):
- from headroom.providers.anthropic import AnthropicProvider
- provider = AnthropicProvider()
- pricing = provider._get_pricing("deepseek-v4-pro")
- assert pricing is not None
- assert pricing["input"] == 0.435
- assert pricing["output"] == 0.87
- assert pricing["cached_input"] == 0.003625
-
- def test_deepseek_unknown_model_returns_none(self):
- from headroom.providers.anthropic import AnthropicProvider
- provider = AnthropicProvider()
- pricing = provider._get_pricing("deepseek-unknown-model")
- assert pricing is None
-
- def test_deepseek_partial_match_v4_flash_alias(self):
- from headroom.providers.anthropic import AnthropicProvider
- provider = AnthropicProvider()
- # Should match via partial match (flash in v4-flash)
- pricing = provider._get_pricing("deepseek-v4-flash-v1")
- assert pricing is not None
-
- def test_estimate_cost_deepseek_v4_flash(self):
- from headroom.providers.anthropic import AnthropicProvider
- provider = AnthropicProvider()
- cost = provider.estimate_cost(
- input_tokens=1_000_000,
- output_tokens=0,
- model="deepseek-v4-flash",
- )
- assert cost is not None
- assert cost == 0.14
-
- def test_estimate_cost_deepseek_v4_flash_with_cache(self):
- from headroom.providers.anthropic import AnthropicProvider
- provider = AnthropicProvider()
- cost = provider.estimate_cost(
- input_tokens=1_000_000,
- output_tokens=0,
- model="deepseek-v4-flash",
- cached_tokens=1_000_000,
- )
- assert cost is not None
- assert cost == 0.14 + 0.0028
-```
-
-- [ ] **Step 2: Run fallback tests to verify they fail**
-
-```bash
-cd D:/headroom && python -m pytest tests/test_providers/test_deepseek.py::TestDeepSeekAnthropicProviderFallback -v
-```
-
-Expected: Fail because `_get_pricing()` returns `None` for `deepseek-*` models.
-
-- [ ] **Step 3: Add DeepSeek fallback to Anthropic provider**
-
-In `headroom/providers/anthropic.py`, add a new helper function after the `_UNKNOWN_CLAUDE_DEFAULT` dict (around line 151) and modify `_get_pricing()`:
-
-Add the helper (after `_UNKNOWN_CLAUDE_DEFAULT` at line 151):
-
-```python
-# DeepSeek fallback pricing for --anthropic-api-url deepseek routing
-_DEEPSEEK_FALLBACK_PRICING: dict[str, dict[str, float]] = {
- "deepseek-v4-flash": {"input": 0.14, "output": 0.28, "cached_input": 0.0028},
- "deepseek-v4-pro": {"input": 0.435, "output": 0.87, "cached_input": 0.003625},
-}
-
-
-def _get_deepseek_pricing(model: str) -> dict[str, float] | None:
- """Get fallback pricing for a DeepSeek model.
-
- Used when the Anthropic provider encounters a deepseek-* model name
- (via --anthropic-api-url pointing at DeepSeek's Anthropic-compatible
- endpoint) and LiteLLM is unavailable.
-
- Args:
- model: The model name to look up.
-
- Returns:
- Pricing dict with input/output/cached_input keys, or None.
- """
- # Direct match
- if model in _DEEPSEEK_FALLBACK_PRICING:
- return cast(dict[str, float], _DEEPSEEK_FALLBACK_PRICING[model])
- # Partial match
- for known_model, prices in _DEEPSEEK_FALLBACK_PRICING.items():
- if model in known_model or known_model in model:
- return cast(dict[str, float], prices)
- return None
-```
-
-Modify `_get_pricing()` in the `AnthropicProvider` class. Add after the Claude default check (line 698):
-
-```python
- # Default for unknown Claude models
- if model.startswith("claude"):
- return cast(dict[str, float], _UNKNOWN_CLAUDE_DEFAULT["pricing"])
-
- # DeepSeek model fallback (via --anthropic-api-url)
- if model.startswith("deepseek"):
- return _get_deepseek_pricing(model)
-
- return None
-```
-
-- [ ] **Step 4: Run tests to verify they pass**
-
-```bash
-cd D:/headroom && python -m pytest tests/test_providers/test_deepseek.py::TestDeepSeekAnthropicProviderFallback -v
-```
-
-Expected: All 6 tests pass.
-
-- [ ] **Step 5: Run full test suite for pricing-related tests**
-
-```bash
-cd D:/headroom && python -m pytest tests/test_providers/test_anthropic.py tests/test_providers/test_deepseek.py tests/test_pricing.py tests/test_pricing_litellm.py tests/test_litellm_optional.py -v
-```
-
-Expected: All existing tests still pass, plus new tests pass.
-
-- [ ] **Step 6: Commit**
-
-```bash
-git add headroom/providers/anthropic.py tests/test_providers/test_deepseek.py
-git commit -m "feat(providers): add DeepSeek pricing fallback to Anthropic provider
-
-When routing through --anthropic-api-url with a DeepSeek endpoint,
-_get_pricing() now handles deepseek-* model names. Falls back to
-hardcoded V4 pricing when LiteLLM is unavailable.
-
-Co-Authored-By: Claude "
-```
-
----
-
-### Task 4: Vendored Rust JSON Entries
-
-**Files:**
-- Modify: `crates/headroom-proxy/data/model_prices_and_context_window.json`
-
-**Interfaces:**
-- Consumes: The existing DeepSeek JSON entry structure around line 12516
-- Produces: `"deepseek-v4-flash"` and `"deepseek-v4-pro"` entries in the JSON
-
-- [ ] **Step 1: Add DeepSeek V4 entries to the vendored JSON**
-
-Open `crates/headroom-proxy/data/model_prices_and_context_window.json` and insert the following after the `"deepseek/deepseek-v3.2"` entry (after line 12516):
-
-```json
- "deepseek-v4-flash": {
- "input_cost_per_token": 1.4e-07,
- "output_cost_per_token": 2.8e-07,
- "cache_read_input_token_cost": 2.8e-09,
- "litellm_provider": "deepseek",
- "max_input_tokens": 1000000,
- "max_output_tokens": 384000,
- "max_tokens": 384000,
- "mode": "chat",
- "supports_function_calling": true,
- "supports_native_streaming": true,
- "supports_prompt_caching": true,
- "source": "https://api-docs.deepseek.com/quick_start/pricing"
- },
- "deepseek-v4-pro": {
- "input_cost_per_token": 4.35e-07,
- "output_cost_per_token": 8.7e-07,
- "cache_read_input_token_cost": 3.625e-09,
- "litellm_provider": "deepseek",
- "max_input_tokens": 1000000,
- "max_output_tokens": 384000,
- "max_tokens": 384000,
- "mode": "chat",
- "supports_function_calling": true,
- "supports_native_streaming": true,
- "supports_prompt_caching": true,
- "source": "https://api-docs.deepseek.com/quick_start/pricing"
- },
-```
-
-Also add provider-prefixed variants after the bare entries (following the pattern where `deepseek/deepseek-v3.2` exists alongside `deepseek-v3-2-251201`):
-
-```json
- "deepseek/deepseek-v4-flash": {
- "input_cost_per_token": 1.4e-07,
- "output_cost_per_token": 2.8e-07,
- "cache_read_input_token_cost": 2.8e-09,
- "input_cost_per_token_cache_hit": 2.8e-09,
- "litellm_provider": "deepseek",
- "max_input_tokens": 1000000,
- "max_output_tokens": 384000,
- "max_tokens": 384000,
- "mode": "chat",
- "supports_function_calling": true,
- "supports_native_streaming": true,
- "supports_prompt_caching": true,
- "supports_assistant_prefill": true,
- "source": "https://api-docs.deepseek.com/quick_start/pricing"
- },
- "deepseek/deepseek-v4-pro": {
- "input_cost_per_token": 4.35e-07,
- "output_cost_per_token": 8.7e-07,
- "cache_read_input_token_cost": 3.625e-09,
- "input_cost_per_token_cache_hit": 3.625e-09,
- "litellm_provider": "deepseek",
- "max_input_tokens": 1000000,
- "max_output_tokens": 384000,
- "max_tokens": 384000,
- "mode": "chat",
- "supports_function_calling": true,
- "supports_native_streaming": true,
- "supports_prompt_caching": true,
- "supports_assistant_prefill": true,
- "source": "https://api-docs.deepseek.com/quick_start/pricing"
- },
-```
-
-Note: The prefixed variants use `input_cost_per_token_cache_hit` (LiteLLM modern field) alongside `cache_read_input_token_cost` (legacy field) following the convention of existing entries like `deepseek/deepseek-v3.2`.
-
-- [ ] **Step 2: Validate the JSON is still well-formed**
-
-```bash
-cd D:/headroom && python -m json.tool crates/headroom-proxy/data/model_prices_and_context_window.json > /dev/null && echo "Valid JSON"
-```
-
-Expected: "Valid JSON"
-
-- [ ] **Step 3: Run full test suite to confirm no regressions**
-
-```bash
-cd D:/headroom && python -m pytest tests/test_pricing.py tests/test_pricing_litellm.py tests/test_providers/test_deepseek.py -v
-```
-
-Expected: All tests pass.
-
-- [ ] **Step 4: Commit**
-
-```bash
-git add crates/headroom-proxy/data/model_prices_and_context_window.json
-git commit -m "feat(proxy): add DeepSeek V4 context window entries to vendored JSON
-
-Add bare and provider-prefixed JSON entries for deepseek-v4-flash
-and deepseek-v4-pro so Rust-side context window lookups work.
-
-Co-Authored-By: Claude "
-```
-
----
-
-### Task 5: Run All Tests and Final Verification
-
-- [ ] **Step 1: Run all pricing-related tests**
-
-```bash
-cd D:/headroom && python -m pytest tests/test_pricing.py tests/test_pricing_litellm.py tests/test_litellm_optional.py tests/test_providers/test_anthropic.py tests/test_providers/test_openai.py tests/test_providers/test_deepseek.py tests/test_providers/test_universal.py tests/test_cost_tracker_counterfactual.py tests/test_proxy_savings_history.py tests/test_provider_model_fallback.py -v
-```
-
-Expected: All tests pass. Note any skips (some may require litellm installed).
-
-- [ ] **Step 2: Verify imports work cleanly**
-
-```bash
-cd D:/headroom && python -c "from headroom.pricing import DEEPSEEK_PRICES, get_deepseek_registry; print('Direct import OK:', list(DEEPSEEK_PRICES.keys()))"
-cd D:/headroom && python -c "from headroom.pricing.litellm_pricing import get_model_pricing; p = get_model_pricing('deepseek-v4-flash'); print('LiteLLM pricing OK:', p.input_cost_per_1m if p else 'None')"
-cd D:/headroom && python -c "from headroom.providers.anthropic import AnthropicProvider; p = AnthropicProvider(); print('Anthropic fallback OK:', p._get_pricing('deepseek-v4-flash'))"
-```
-
-Expected: All three commands print correct pricing values without errors.
-
-- [ ] **Step 3: Verify the full proxy cost tracker end-to-end**
-
-```bash
-cd D:/headroom && python -c "
-from headroom.proxy.cost import CostTracker
-t = CostTracker()
-cost = t.estimate_cost('deepseek-v4-flash', input_tokens=1000000, output_tokens=1000000)
-print(f'CostTracker estimate: \${cost:.4f}' if cost else 'CostTracker returned None')
-"
-```
-
-Expected: Prints `CostTracker estimate: $0.4200` (0.14 input + 0.28 output, may vary if litellm is available).
-
-- [ ] **Step 4: Final commit if any fixes were needed**
-
-```bash
-git log --oneline -5
-```
-
-Expected: Shows the 4 commit history for this feature.
diff --git a/docs/superpowers/specs/2026-06-25-kompress-finetune-design.md b/docs/superpowers/specs/2026-06-25-kompress-finetune-design.md
deleted file mode 100644
index f2588f9c2..000000000
--- a/docs/superpowers/specs/2026-06-25-kompress-finetune-design.md
+++ /dev/null
@@ -1,169 +0,0 @@
-# Kompress Fine-Tune Design
-
-**Date:** 2026-06-25
-**Status:** Approved
-**Owner:** peterlodri-sec
-
-## Goal
-
-Fine-tune `chopratejas/kompress-v2-base` (ModernBERT ~149M) to:
-
-- **B — Quality push:** lower keep_rate from 0.81 toward 0.72–0.75 while holding must_keep_recall above 0.97
-- **C2 — Domain profiles:** teach domain-specific compression intuitions for five input types (code diffs, log streams, JSON blobs, prose/markdown, file trees)
-- **C3 — Self-distillation:** use headroom's own proxy compression logs as labeled training data
-
-Deliverables: fine-tuned model + ONNX artifacts, a blog post, and a Jupyter notebook with a Colab quick-start path and a vast.ai production path.
-
----
-
-## 1. Data Pipeline
-
-### 1.1 Domain-tagged datasets
-
-Each input sequence is prefixed with a domain token so the model builds per-domain compression intuitions rather than one global policy.
-
-| Domain | Prefix | Source | Keep signal | Drop signal |
-|--------|--------|--------|-------------|-------------|
-| Code diffs | `[CODE]` | `codeparrot/github-code` + open PR diffs | `+`/`-` lines, function/class signatures, imports | whitespace, unchanged context, comments |
-| Log streams | `[LOG]` | Loghub (Apache/HDFS/Linux) | ERROR/WARN/EXCEPTION, stack frames, unique messages | repeated INFO, timestamps, DEBUG noise |
-| JSON blobs | `[JSON]` | headroom test data + synthetic API responses | non-null leaf values, rare keys (<5% frequency) | null, empty arrays, boilerplate schema |
-| Prose/markdown | `[PROSE]` | HuggingFace docs, GitHub READMEs | key claims, numbers, definitions (TF-IDF top-20%) | transition sentences, repeated examples |
-| File trees | `[TREE]` | synthetic from real filesystem structures | non-standard paths, recently modified indicators | `.git/`, stdlib paths, permission columns |
-
-**Total:** ~50k samples. Colab subset: ~3k (one domain).
-**Split:** 80/10/10 train/val/test, stratified by domain.
-
-### 1.2 C3 — Headroom self-distillation
-
-headroom's proxy compression logs contain (original_text, compressed_text) pairs from real production requests. Token-level keep/drop labels are recovered by diffing the token sequences. These are real usage decisions — the strongest training signal for the model's actual deployment context.
-
-Extraction script: reads from headroom's local proxy log directory, tokenizes both sides with the kompress tokenizer, aligns, and outputs labeled sequences tagged `[HDR]`.
-
-### 1.3 Labeling heuristics
-
-Heuristics generate weak labels for the five domain datasets. They are intentionally conservative — false positives (keep too much) are preferred over false negatives (drop something important). The model learns to be more aggressive; the heuristics just establish the floor.
-
----
-
-## 2. Training Setup
-
-**Platform:** RTX 4090 24GB on vast.ai. ~$0.50/hr. Full run costs ~$0.70–1.00. Budget ($6–7) covers 6–10 experiments.
-
-**Full fine-tune, no LoRA.** ModernBERT at 149M sits at ~4GB in bf16. A 4090 has 24GB — no reason to constrain.
-
-### 2.1 Hyperparameters
-
-| Setting | Value | Reason |
-|---------|-------|--------|
-| Base model | `chopratejas/kompress-v2-base` | existing checkpoint |
-| Task | token classification, binary (0=drop, 1=keep) | same as kompress v2 |
-| Loss | weighted cross-entropy, keep_weight=2.5 | penalizes false drops to protect recall |
-| Learning rate | 2e-5, cosine decay | standard for BERT-class fine-tune |
-| Warmup | 10% of total steps | |
-| Batch size | 32 sequences, seq_len=512 | fits 4090; matches kompress inference window |
-| Epochs | 3 with early stopping on val must_keep_recall | |
-| Optimizer | AdamW, weight_decay=0.01 | |
-| Precision | bf16 | |
-
-### 2.2 B — Threshold calibration (post-training)
-
-After training, sweep the classification threshold from 0.3 to 0.7 in steps of 0.02. For each threshold compute keep_rate and must_keep_recall on the validation set. Select the highest-compression threshold (lowest keep_rate) where must_keep_recall stays above 0.97. One forward pass — no retraining.
-
-### 2.3 Evaluation
-
-Metrics reported per domain and blended:
-
-- **f1** — overall classification quality
-- **must_keep_recall** — fraction of ground-truth keep tokens that are kept; hard floor 0.97
-- **keep_rate** — fraction of tokens kept; target 0.72–0.75 (down from 0.81)
-
-Compared against kompress-v2-base baseline on the same held-out test splits.
-
-### 2.4 ONNX export
-
-Two artifacts, matching headroom's existing naming:
-
-- `kompress-int8-wo.onnx` — weight-only int8 (MatMulNBits), drop-in replacement for the current 261MB artifact
-- `kompress-fp32.onnx` — lossless reference
-
-Both pushed to HuggingFace Hub as a new model repo.
-
----
-
-## 3. Blog Post
-
-**Title:** "Language Immersion at 149M Parameters"
-**Published to:** `pocoo.vaked.dev` (existing post format)
-
-**Framing:** The Sapir-Whorf hypothesis says the language you speak shapes the thoughts you can have. Kompress is trained to think in compressed language — not filtering noise but internalizing a new grammar where redundant tokens don't exist. Domain fine-tuning is immersion: the model develops native compression intuitions per dialect (code, logs, JSON, prose, trees) instead of one blunt global policy.
-
-**Structure:**
-
-1. **Hook** — the hypothesis; one paragraph; "what if the way an AI reads context determines what it's capable of thinking?"
-2. **The problem** — tool output noise filling context; kompress's token classification job
-3. **What kompress does** — ModernBERT architecture, current metrics (f1=0.913, keep_rate=0.81)
-4. **Domain immersion** — why code diffs compress differently than log streams; the domain prefix token trick
-5. **The dogfood loop** — headroom proxy traffic as teacher; self-distillation; eating your own cooking
-6. **The training run** — vast.ai, the numbers, total cost (~$0.70)
-7. **Results** — before/after metrics table per domain; threshold calibration curve
-8. **Notebook** — link + how to reproduce on Colab or your own GPU
-
----
-
-## 4. Jupyter Notebook
-
-**File:** `kompress-finetune.ipynb`
-**Hosted:** HuggingFace Hub alongside the model, linked from the blog post.
-
-### Part 1: Quick Start (Colab / Kaggle, T4, ~15 min)
-
-- Install deps (`transformers`, `datasets`, `torch`)
-- Load `kompress-v2-base`
-- Load 3k-sample subset (one domain, pre-labeled)
-- Fine-tune 1 epoch
-- Threshold calibration sweep
-- Eval: f1 / must_keep_recall / keep_rate
-
-### Part 2: Production Run (vast.ai / self-hosted 4090)
-
-- Rent instance walkthrough (vast.ai CLI commands)
-- Full 5-domain data pipeline
-- Headroom log extraction (C3 self-distillation)
-- Full fine-tune (3 epochs)
-- Per-domain eval
-- ONNX export (int8-wo + fp32)
-- Push to HuggingFace Hub
-
-Both parts share the same training cell. Only the dataset loading and export differ. A Colab reader sees the full pipeline structure and can swap in their own data later.
-
----
-
-## 5. File Layout
-
-```
-headroom/
- scripts/
- kompress_finetune/
- data/
- build_dataset.py # domain dataset builder + headroom log extractor
- label_heuristics.py # weak labeling per domain
- train.py # training entry point (HF Trainer)
- calibrate.py # threshold sweep post-training
- export_onnx.py # int8-wo + fp32 ONNX export
- eval.py # per-domain metrics
- notebooks/
- kompress-finetune.ipynb # the split notebook
-
-pocoo.vaked.dev/
- src/posts/
- kompress-finetune-sapir-whorf.md # blog post
-```
-
----
-
-## 6. Out of Scope
-
-- LoRA / adapter-per-domain (full fine-tune is sufficient at 149M)
-- Contrastive training objective (deferred to a future run)
-- Deploying the new model to headroom main branch (separate PR, after eval)
-- Training on GPU larger than 4090 (A100 is overkill and burns budget)
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.bin/esbuild b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.bin/esbuild
deleted file mode 120000
index c83ac0707..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.bin/esbuild
+++ /dev/null
@@ -1 +0,0 @@
-../esbuild/bin/esbuild
\ No newline at end of file
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.bin/tsc b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.bin/tsc
deleted file mode 120000
index 0863208a6..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.bin/tsc
+++ /dev/null
@@ -1 +0,0 @@
-../typescript/bin/tsc
\ No newline at end of file
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.bin/tsserver b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.bin/tsserver
deleted file mode 120000
index f8f8f1a0c..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.bin/tsserver
+++ /dev/null
@@ -1 +0,0 @@
-../typescript/bin/tsserver
\ No newline at end of file
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.bin/tsx b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.bin/tsx
deleted file mode 120000
index f7282dd89..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.bin/tsx
+++ /dev/null
@@ -1 +0,0 @@
-../tsx/dist/cli.mjs
\ No newline at end of file
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.package-lock.json b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.package-lock.json
deleted file mode 100644
index 15855a50c..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/.package-lock.json
+++ /dev/null
@@ -1,324 +0,0 @@
-{
- "name": "@example/node-headroom-compression",
- "version": "0.0.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "node_modules/@ai-sdk/anthropic": {
- "version": "3.0.64",
- "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-3.0.64.tgz",
- "integrity": "sha512-rwLi/Rsuj2pYniQXIrvClHvXDzgM4UQHHnvHTWEF14efnlKclG/1ghpNC+adsRujAbCTr6gRsSbDE2vEqriV7g==",
- "license": "Apache-2.0",
- "dependencies": {
- "@ai-sdk/provider": "3.0.8",
- "@ai-sdk/provider-utils": "4.0.21"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "zod": "^3.25.76 || ^4.1.8"
- }
- },
- "node_modules/@ai-sdk/gateway": {
- "version": "3.0.80",
- "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.80.tgz",
- "integrity": "sha512-uM7kpZB5l977lW7+2X1+klBUxIZQ78+1a9jHlaHFEzcOcmmslTl3sdP0QqfuuBcO0YBM2gwOiqVdp8i4TRQYcw==",
- "license": "Apache-2.0",
- "dependencies": {
- "@ai-sdk/provider": "3.0.8",
- "@ai-sdk/provider-utils": "4.0.21",
- "@vercel/oidc": "3.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "zod": "^3.25.76 || ^4.1.8"
- }
- },
- "node_modules/@ai-sdk/openai": {
- "version": "3.0.48",
- "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-3.0.48.tgz",
- "integrity": "sha512-ALmj/53EXpcRqMbGpPJPP4UOSWw0q4VGpnDo7YctvsynjkrKDmoneDG/1a7VQnSPYHnJp6tTRMf5ZdxZ5whulg==",
- "license": "Apache-2.0",
- "dependencies": {
- "@ai-sdk/provider": "3.0.8",
- "@ai-sdk/provider-utils": "4.0.21"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "zod": "^3.25.76 || ^4.1.8"
- }
- },
- "node_modules/@ai-sdk/provider": {
- "version": "3.0.8",
- "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.8.tgz",
- "integrity": "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "json-schema": "^0.4.0"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@ai-sdk/provider-utils": {
- "version": "4.0.21",
- "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.21.tgz",
- "integrity": "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw==",
- "license": "Apache-2.0",
- "dependencies": {
- "@ai-sdk/provider": "3.0.8",
- "@standard-schema/spec": "^1.1.0",
- "eventsource-parser": "^3.0.6"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "zod": "^3.25.76 || ^4.1.8"
- }
- },
- "node_modules/@esbuild/darwin-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz",
- "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@opentelemetry/api": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
- "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
- "license": "Apache-2.0",
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/@standard-schema/spec": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
- "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
- "license": "MIT"
- },
- "node_modules/@vercel/oidc": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.1.0.tgz",
- "integrity": "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==",
- "license": "Apache-2.0",
- "engines": {
- "node": ">= 20"
- }
- },
- "node_modules/ai": {
- "version": "6.0.138",
- "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.138.tgz",
- "integrity": "sha512-49OfPe0f5uxJ6jUdA5BBXjIinP6+ZdYfAtpF2aEH64GA5wPcxH2rf/TBUQQ0bbamBz/D+TLMV18xilZqOC+zaA==",
- "license": "Apache-2.0",
- "dependencies": {
- "@ai-sdk/gateway": "3.0.80",
- "@ai-sdk/provider": "3.0.8",
- "@ai-sdk/provider-utils": "4.0.21",
- "@opentelemetry/api": "1.9.0"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "zod": "^3.25.76 || ^4.1.8"
- }
- },
- "node_modules/dotenv": {
- "version": "17.3.1",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz",
- "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==",
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://dotenvx.com"
- }
- },
- "node_modules/esbuild": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz",
- "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "bin": {
- "esbuild": "bin/esbuild"
- },
- "engines": {
- "node": ">=18"
- },
- "optionalDependencies": {
- "@esbuild/aix-ppc64": "0.27.4",
- "@esbuild/android-arm": "0.27.4",
- "@esbuild/android-arm64": "0.27.4",
- "@esbuild/android-x64": "0.27.4",
- "@esbuild/darwin-arm64": "0.27.4",
- "@esbuild/darwin-x64": "0.27.4",
- "@esbuild/freebsd-arm64": "0.27.4",
- "@esbuild/freebsd-x64": "0.27.4",
- "@esbuild/linux-arm": "0.27.4",
- "@esbuild/linux-arm64": "0.27.4",
- "@esbuild/linux-ia32": "0.27.4",
- "@esbuild/linux-loong64": "0.27.4",
- "@esbuild/linux-mips64el": "0.27.4",
- "@esbuild/linux-ppc64": "0.27.4",
- "@esbuild/linux-riscv64": "0.27.4",
- "@esbuild/linux-s390x": "0.27.4",
- "@esbuild/linux-x64": "0.27.4",
- "@esbuild/netbsd-arm64": "0.27.4",
- "@esbuild/netbsd-x64": "0.27.4",
- "@esbuild/openbsd-arm64": "0.27.4",
- "@esbuild/openbsd-x64": "0.27.4",
- "@esbuild/openharmony-arm64": "0.27.4",
- "@esbuild/sunos-x64": "0.27.4",
- "@esbuild/win32-arm64": "0.27.4",
- "@esbuild/win32-ia32": "0.27.4",
- "@esbuild/win32-x64": "0.27.4"
- }
- },
- "node_modules/eventsource-parser": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz",
- "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==",
- "license": "MIT",
- "engines": {
- "node": ">=18.0.0"
- }
- },
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/get-tsconfig": {
- "version": "4.13.7",
- "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz",
- "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "resolve-pkg-maps": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
- }
- },
- "node_modules/headroom-ai": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/headroom-ai/-/headroom-ai-0.1.0.tgz",
- "integrity": "sha512-SM5i2kptwsO+KnQqpaLThZVx1ZrmobVw5JRXwF5OvnMvhV/3WbwUI+VvXHTwTCvVq+AAyhkhuVcNXod1piAVuQ==",
- "license": "Apache-2.0",
- "engines": {
- "node": ">=18.0.0"
- },
- "peerDependencies": {
- "@ai-sdk/provider": ">=1.0.0",
- "@anthropic-ai/sdk": ">=0.30.0",
- "ai": ">=6.0.0",
- "openai": ">=4.0.0"
- },
- "peerDependenciesMeta": {
- "@ai-sdk/provider": {
- "optional": true
- },
- "@anthropic-ai/sdk": {
- "optional": true
- },
- "ai": {
- "optional": true
- },
- "openai": {
- "optional": true
- }
- }
- },
- "node_modules/json-schema": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
- "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
- "license": "(AFL-2.1 OR BSD-3-Clause)"
- },
- "node_modules/resolve-pkg-maps": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
- "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
- }
- },
- "node_modules/tsx": {
- "version": "4.21.0",
- "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz",
- "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "esbuild": "~0.27.0",
- "get-tsconfig": "^4.7.5"
- },
- "bin": {
- "tsx": "dist/cli.mjs"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.3"
- }
- },
- "node_modules/typescript": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz",
- "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==",
- "dev": true,
- "license": "Apache-2.0",
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=14.17"
- }
- },
- "node_modules/zod": {
- "version": "4.3.6",
- "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
- "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/colinhacks"
- }
- }
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/CHANGELOG.md b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/CHANGELOG.md
deleted file mode 100644
index 7c0bda09b..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/CHANGELOG.md
+++ /dev/null
@@ -1,2560 +0,0 @@
-# @ai-sdk/anthropic
-
-## 3.0.64
-
-### Patch Changes
-
-- 05b8ca2: feat (provider/anthropic): support passing metadata.user_id
-
-## 3.0.63
-
-### Patch Changes
-
-- 055cd68: fix: publish v6 to latest npm dist tag
-- Updated dependencies [055cd68]
- - @ai-sdk/provider-utils@4.0.21
-
-## 3.0.62
-
-### Patch Changes
-
-- 41c6a56: fix(anthropic): skip passing beta header for tool search tools
-
-## 3.0.61
-
-### Patch Changes
-
-- 2381567: fix(vertex): throw warning when strict: true for vertexAnthropic
-
-## 3.0.60
-
-### Patch Changes
-
-- ffe0f90: fix(anthropic): preserve the error code returned by model
-
-## 3.0.59
-
-### Patch Changes
-
-- Updated dependencies [64ac0fd]
- - @ai-sdk/provider-utils@4.0.20
-
-## 3.0.58
-
-### Patch Changes
-
-- 3fb4e70: feat(anthropic): support eagerInputStreaming option for fine-grained tool streaming
-- Updated dependencies [ad4cfc2]
- - @ai-sdk/provider-utils@4.0.19
-
-## 3.0.57
-
-### Patch Changes
-
-- Updated dependencies [824b295]
- - @ai-sdk/provider-utils@4.0.18
-
-## 3.0.56
-
-### Patch Changes
-
-- e49c34d: feat(anthropic): expose anthropic.anthropicBeta to downstream providers
-- e49c34d: feat(anthropic): expose anthropic.anthropicBeta to downstream provider
-
-## 3.0.55
-
-### Patch Changes
-
-- 7531e72: fix(provider/anthropic): handle encrypted_code_execution_result for multi-turn with web_fetch/web_search 20260209
-
-## 3.0.54
-
-### Patch Changes
-
-- 56c67d5: feat(provider/anthropic): add support for Anthropic web tools `web_fetch_20260209` and `web_search_20260209`
-
-## 3.0.53
-
-### Patch Changes
-
-- 89caf28: fix(openai-compat): decode base64 string data
-
-## 3.0.52
-
-### Patch Changes
-
-- Updated dependencies [08336f1]
- - @ai-sdk/provider-utils@4.0.17
-
-## 3.0.51
-
-### Patch Changes
-
-- 64a8fae: chore: remove obsolete model IDs for Anthropic, Google, OpenAI, xAI
-
-## 3.0.50
-
-### Patch Changes
-
-- Updated dependencies [58bc42d]
- - @ai-sdk/provider-utils@4.0.16
-
-## 3.0.49
-
-### Patch Changes
-
-- d98d9ba: Migrated deprecated `output_format` parameter to `output_config.format` for structured outputs + Enabled native structured output support for Bedrock Anthropic models via `output_config.format`.
-
-## 3.0.48
-
-### Patch Changes
-
-- 2164cdf: feat(anthropic): add the new code_execution tool
-
-## 3.0.47
-
-### Patch Changes
-
-- 17978c6: Pass `cacheControl` provider option as top-level `cache_control` in Anthropic API request body to support automatic caching.
-
-## 3.0.46
-
-### Patch Changes
-
-- b094c07: fix compaction_delta streaming schema to allow null content
-
-## 3.0.45
-
-### Patch Changes
-
-- 2a1c664: feat(provider/anthropic): add support for new Claude Sonnet 4.6 model
-
-## 3.0.44
-
-### Patch Changes
-
-- 23ac4a3: fix(provider/anthropic): minor follow up to support no-op speed standard
-
-## 3.0.43
-
-### Patch Changes
-
-- Updated dependencies [4024a3a]
- - @ai-sdk/provider-utils@4.0.15
-
-## 3.0.42
-
-### Patch Changes
-
-- 99fbed8: feat: normalize provider specific model options type names and ensure they are exported
-
-## 3.0.41
-
-### Patch Changes
-
-- c60b393: feat(anthropic): add the new compaction feature
-
-## 3.0.40
-
-### Patch Changes
-
-- 8c2b1e1: fix(provider/anthropic): include actual raw usage data for `response.usage.raw` when streaming
-
-## 3.0.39
-
-### Patch Changes
-
-- 0a0d29c: feat(anthropic): add support for Opus 4.6 fast mode
-
-## 3.0.38
-
-### Patch Changes
-
-- Updated dependencies [7168375]
- - @ai-sdk/provider@3.0.8
- - @ai-sdk/provider-utils@4.0.14
-
-## 3.0.37
-
-### Patch Changes
-
-- e288302: feat(anthropic): add support for Opus 4.6
-
-## 3.0.36
-
-### Patch Changes
-
-- 1652320: feat(anthropic): support custom tool-reference content for deferred tool loading
-
-## 3.0.35
-
-### Patch Changes
-
-- Updated dependencies [53f6731]
- - @ai-sdk/provider@3.0.7
- - @ai-sdk/provider-utils@4.0.13
-
-## 3.0.34
-
-### Patch Changes
-
-- Updated dependencies [96936e5]
- - @ai-sdk/provider-utils@4.0.12
-
-## 3.0.33
-
-### Patch Changes
-
-- 445cbe3: fix streaming context_management field location - was incorrectly expected inside delta object but API returns it at message_delta root level
-
-## 3.0.32
-
-### Patch Changes
-
-- c33343b: fix(anthropic): add missing param in tool schema
-
-## 3.0.31
-
-### Patch Changes
-
-- Updated dependencies [2810850]
- - @ai-sdk/provider-utils@4.0.11
- - @ai-sdk/provider@3.0.6
-
-## 3.0.30
-
-### Patch Changes
-
-- 1524271: chore: add skill information to README files
-
-## 3.0.29
-
-### Patch Changes
-
-- b9d105f: Fix cache usage reporting for anthropic stream
-
-## 3.0.28
-
-### Patch Changes
-
-- 2445da4: fix(provider/anthropic): populate outputTokens.text field in usage
-
-## 3.0.27
-
-### Patch Changes
-
-- 572ea12: feat(anthropic): allow custom/dynamic key for providerOptions
-
-## 3.0.26
-
-### Patch Changes
-
-- 2c70b90: chore: update provider docs
-
-## 3.0.25
-
-### Patch Changes
-
-- 0bb9bcd: feat(provider/anthropic): add computer_20251124 tool for claude opus 4.5
-
-## 3.0.24
-
-### Patch Changes
-
-- Updated dependencies [462ad00]
- - @ai-sdk/provider-utils@4.0.10
-
-## 3.0.23
-
-### Patch Changes
-
-- 4de5a1d: chore: excluded tests from src folder in npm package
-- Updated dependencies [4de5a1d]
- - @ai-sdk/provider@3.0.5
- - @ai-sdk/provider-utils@4.0.9
-
-## 3.0.22
-
-### Patch Changes
-
-- 8ccf04b: Add `authToken` option to support `Authorization: Bearer` authentication as an alternative to `x-api-key` header authentication.
-
-## 3.0.21
-
-### Patch Changes
-
-- 662d359: feat(anthropic): deferred results for tool search tool
-
-## 3.0.20
-
-### Patch Changes
-
-- 2b8369d: chore: add docs to package dist
-
-## 3.0.19
-
-### Patch Changes
-
-- 8dc54db: chore: add src folders to package bundle
-
-## 3.0.18
-
-### Patch Changes
-
-- c10bd49: fix(anthropic): handle web_search_result_location citations and add webFetch documents to citationDocuments
-
-## 3.0.17
-
-### Patch Changes
-
-- 4729bed: Fix JSON parsing crash when handling Anthropic web_fetch tool error results
-
-## 3.0.16
-
-### Patch Changes
-
-- d36fa72: Not sending structured output beta header for json response tool
-
-## 3.0.15
-
-### Patch Changes
-
-- Updated dependencies [5c090e7]
- - @ai-sdk/provider@3.0.4
- - @ai-sdk/provider-utils@4.0.8
-
-## 3.0.14
-
-### Patch Changes
-
-- Updated dependencies [46f46e4]
- - @ai-sdk/provider-utils@4.0.7
-
-## 3.0.13
-
-### Patch Changes
-
-- Updated dependencies [1b11dcb]
- - @ai-sdk/provider-utils@4.0.6
- - @ai-sdk/provider@3.0.3
-
-## 3.0.12
-
-### Patch Changes
-
-- Updated dependencies [34d1c8a]
- - @ai-sdk/provider-utils@4.0.5
-
-## 3.0.11
-
-### Patch Changes
-
-- 8c1c6e3: fix(anthropic): add application/json type regex matching
-
-## 3.0.10
-
-### Patch Changes
-
-- 02d9b68: fix `input_tokens` compatibility
-
-## 3.0.9
-
-### Patch Changes
-
-- de2399b: fix(anthropic): assign type urls in file parts correctly
-
-## 3.0.8
-
-### Patch Changes
-
-- bee4f82: fix(anthropic): enable structured output support for claude-haiku-4-5
-
- This fixes an issue where the `strict: true` property was not included in the request body when using tools with Claude Haiku 4.5, because `supportsStructuredOutput` was incorrectly set to `false` for this model.
-
- Claude Haiku 4.5 supports structured outputs, so the `strict` property should be forwarded to the Anthropic API when specified on tools.
-
-## 3.0.7
-
-### Patch Changes
-
-- Updated dependencies [d937c8f]
- - @ai-sdk/provider@3.0.2
- - @ai-sdk/provider-utils@4.0.4
-
-## 3.0.6
-
-### Patch Changes
-
-- 2231e84: fix(anthropic): implement temperature/topP mutual exclusivity
-
- Resolves the Anthropic API breaking change where sampling parameters must use only `temperature` OR `top_p`, not both. When both parameters are provided:
-
- - Temperature takes priority and topP is ignored
- - A warning is added to inform users: "topP is not supported when temperature is set. topP is ignored."
- - The validation only runs when thinking mode is not enabled (thinking mode has its own parameter validation)
-
- See Anthropic migration guide: https://platform.claude.com/docs/en/about-claude/models/migrating-to-claude-4
-
-## 3.0.5
-
-### Patch Changes
-
-- Updated dependencies [0b429d4]
- - @ai-sdk/provider-utils@4.0.3
-
-## 3.0.4
-
-### Patch Changes
-
-- bf39dac: Fix: Use provider tool name in Tool Search Tool results
-
-## 3.0.3
-
-### Patch Changes
-
-- 77b760d: fix(anthropic): support deferred results for web search/fetch tool
-
-## 3.0.2
-
-### Patch Changes
-
-- 863d34f: fix: trigger release to update `@latest`
-- Updated dependencies [863d34f]
- - @ai-sdk/provider@3.0.1
- - @ai-sdk/provider-utils@4.0.2
-
-## 3.0.1
-
-### Patch Changes
-
-- Updated dependencies [29264a3]
- - @ai-sdk/provider-utils@4.0.1
-
-## 3.0.0
-
-### Major Changes
-
-- dee8b05: ai SDK 6 beta
-
-### Minor Changes
-
-- 78928cb: release: start 5.1 beta
-
-### Patch Changes
-
-- 0c3b58b: fix(provider): add specificationVersion to ProviderV3
-- 0adc679: feat(provider): shared spec v3
-- 50b70d6: feat(anthropic): add programmatic tool calling
-- b8ea36e: feat(provider/anthropic): Anthropic-native structured outputs
-- ed537e1: Add support for pdf file in tool result in anthropic
-- 2109385: 'fix(anthropic): Opus 4.5 `maxOutputTokens` bump `32000` -> `64000`'
-- 7c4328e: Adds url-based pdf and image support for anthropic tool results
-- 8d9e8ad: chore(provider): remove generics from EmbeddingModelV3
-
- Before
-
- ```ts
- model.textEmbeddingModel("my-model-id");
- ```
-
- After
-
- ```ts
- model.embeddingModel("my-model-id");
- ```
-
-- f33a018: chore: add model ID for Haiku 4.5
-- b2dbfbf: add context_management for anthropic
-- dce03c4: feat: tool input examples
-- 2625a04: feat(openai); update spec for mcp approval
-- 11e4abe: feat(provider/anthropic): web search tool updates
-- f13958c: chore(antropic): allow custom names for provider-defined tools
-- afb00e3: feat(provider/anthropic): add text_editor_20250728 tool support
-
- Add text_editor_20250728 tool for Claude 4 models (Sonnet 4, Opus 4, Opus 4.1) with optional max_characters parameter and no undo_edit command support.
-
-- 95f65c2: chore: use import \* from zod/v4
-- 954c356: feat(openai): allow custom names for provider-defined tools
-- 9e35785: fix(anthropic): send {} as tool input when streaming tool calls without arguments
-- 544d4e8: chore(specification): rename v3 provider defined tool to provider tool
-- a5f77a6: fix(anthropic): remove outdated tool name docs
-- ca07285: feat(anthropic): add prompt caching validation
-- a5a8db4: chore: add model ID for Sonnet 4.5
-- 1742445: Support for custom provider name in google and anthropic providers
-- e8109d3: feat: tool execution approval
-- 87db851: fix(vertex/anthropic): passing beta header only for structured outputs
-- f6603b7: fix(provider/anthropic): correct raw usage information
-- ed329cb: feat: `Provider-V3`
-- 3bd2689: feat: extended token usage
-- 1cad0ab: feat: add provider version to user-agent header
-- 2049c5b: Fix handling of error in web fetch tool in anthropic
-- 4c5a6be: feat(provider/anthropic): default and limit maxTokens based on model
-- 9e1e758: fix(anthropic): use default thinking budget when unspecified
-- 589a4ee: fix(anthropic): simplify pulling first chunk
-- 8dac895: feat: `LanguageModelV3`
-- 6f845b4: Add support for 2025-08-25 code execution tool
-- 9354297: feat(provider/anthropic): add support for Agent Skills
-- 03849b0: throw 500 error when the first stream chunk is an error
-- 0ae783e: feat(anthropic): add the new tool search tools
-- 457318b: chore(provider,ai): switch to SharedV3Warning and unified warnings
-- eb56fc6: fix(anthropic): pull first chunk without async IIFE
-- fa35e95: feat(provider/anthropic): add web fetch tool
-- 80894b3: add return `file_id` property for anthropic code-execution-20250825 to download output files.
-- 366f50b: chore(provider): add deprecated textEmbeddingModel and textEmbedding aliases
-- 81d4308: feat(provider/anthropic): mcp connector support
-- 6fc35cb: Retain user-supplied betas.
-- f4db7b5: feat(provider/anthropic): expose container from response in provider metadata
-- 6c38080: fix(anthropic): support pdf responses in web_fetch_tool_result schema validation
-- 4616b86: chore: update zod peer depenedency version
-- dedf206: feat(provider/anthropic): expose stop_sequence in provider metadata
-- 983e394: chore(provider/anthropic): add missing provider options jsdoc
-- 0e38a79: support ANTHROPIC_BASE_URL
-- cf4e2a9: Add support for tool calling with structured output
-- f4e4a95: feat(provider/anthropic): enable fine grained tool streaming by default
-- 21f378c: fix(provider/anthropic): do not limit maxTokens when model id is unknown
-- c5440c5: chore(provider/anthropic): update anthropic model ids
-- 1d15673: fix(provider/anthropic): clamp temperature to valid 0-1 range with warnings
-- 9cff587: chore(provider/anthropic): lazy schema loading
-- d129d89: chore(anthropic): remove unnecessary doc
-- 3794514: feat: flexible tool output content support
-- e1e2821: fix(provider/anthropic): support null title in web fetch tool
-- cbf52cd: feat: expose raw finish reason
-- 10c1322: fix: moved dependency `@ai-sdk/test-server` to devDependencies
-- d08308b: feat(provider/anthropic): memory tool
-- 05d5b9a: fix(anthropic): make title field nullable in web_fetch and web_search tool output schemas
-- 1bd7d32: feat: tool-specific strict mode
-- 83aaad8: Opus 4.5 and `effort` provider option
-- Updated dependencies
- - @ai-sdk/provider@3.0.0
- - @ai-sdk/provider-utils@4.0.0
-
-## 3.0.0-beta.98
-
-### Patch Changes
-
-- 2049c5b: Fix handling of error in web fetch tool in anthropic
-
-## 3.0.0-beta.97
-
-### Patch Changes
-
-- Updated dependencies [475189e]
- - @ai-sdk/provider@3.0.0-beta.32
- - @ai-sdk/provider-utils@4.0.0-beta.59
-
-## 3.0.0-beta.96
-
-### Patch Changes
-
-- 2625a04: feat(openai); update spec for mcp approval
-- Updated dependencies [2625a04]
- - @ai-sdk/provider@3.0.0-beta.31
- - @ai-sdk/provider-utils@4.0.0-beta.58
-
-## 3.0.0-beta.95
-
-### Patch Changes
-
-- cbf52cd: feat: expose raw finish reason
-- Updated dependencies [cbf52cd]
- - @ai-sdk/provider@3.0.0-beta.30
- - @ai-sdk/provider-utils@4.0.0-beta.57
-
-## 3.0.0-beta.94
-
-### Patch Changes
-
-- Updated dependencies [9549c9e]
- - @ai-sdk/provider@3.0.0-beta.29
- - @ai-sdk/provider-utils@4.0.0-beta.56
-
-## 3.0.0-beta.93
-
-### Patch Changes
-
-- 50b70d6: feat(anthropic): add programmatic tool calling
-- Updated dependencies [50b70d6]
- - @ai-sdk/provider-utils@4.0.0-beta.55
-
-## 3.0.0-beta.92
-
-### Patch Changes
-
-- Updated dependencies [9061dc0]
- - @ai-sdk/provider-utils@4.0.0-beta.54
- - @ai-sdk/provider@3.0.0-beta.28
-
-## 3.0.0-beta.91
-
-### Patch Changes
-
-- d129d89: chore(anthropic): remove unnecessary doc
-
-## 3.0.0-beta.90
-
-### Patch Changes
-
-- 366f50b: chore(provider): add deprecated textEmbeddingModel and textEmbedding aliases
-- Updated dependencies [366f50b]
- - @ai-sdk/provider@3.0.0-beta.27
- - @ai-sdk/provider-utils@4.0.0-beta.53
-
-## 3.0.0-beta.89
-
-### Patch Changes
-
-- Updated dependencies [763d04a]
- - @ai-sdk/provider-utils@4.0.0-beta.52
-
-## 3.0.0-beta.88
-
-### Patch Changes
-
-- 87db851: fix(vertex/anthropic): passing beta header only for structured outputs
-
-## 3.0.0-beta.87
-
-### Patch Changes
-
-- Updated dependencies [c1efac4]
- - @ai-sdk/provider-utils@4.0.0-beta.51
-
-## 3.0.0-beta.86
-
-### Patch Changes
-
-- Updated dependencies [32223c8]
- - @ai-sdk/provider-utils@4.0.0-beta.50
-
-## 3.0.0-beta.85
-
-### Patch Changes
-
-- Updated dependencies [83e5744]
- - @ai-sdk/provider-utils@4.0.0-beta.49
-
-## 3.0.0-beta.84
-
-### Patch Changes
-
-- Updated dependencies [960ec8f]
- - @ai-sdk/provider-utils@4.0.0-beta.48
-
-## 3.0.0-beta.83
-
-### Patch Changes
-
-- 6c38080: fix(anthropic): support pdf responses in web_fetch_tool_result schema validation
-
-## 3.0.0-beta.82
-
-### Patch Changes
-
-- Updated dependencies [e9e157f]
- - @ai-sdk/provider-utils@4.0.0-beta.47
-
-## 3.0.0-beta.81
-
-### Patch Changes
-
-- Updated dependencies [81e29ab]
- - @ai-sdk/provider-utils@4.0.0-beta.46
-
-## 3.0.0-beta.80
-
-### Patch Changes
-
-- 05d5b9a: fix(anthropic): make title field nullable in web_fetch and web_search tool output schemas
-
-## 3.0.0-beta.79
-
-### Patch Changes
-
-- 3bd2689: feat: extended token usage
-- Updated dependencies [3bd2689]
- - @ai-sdk/provider@3.0.0-beta.26
- - @ai-sdk/provider-utils@4.0.0-beta.45
-
-## 3.0.0-beta.78
-
-### Patch Changes
-
-- 9e1e758: fix(anthropic): use default thinking budget when unspecified
-
-## 3.0.0-beta.77
-
-### Patch Changes
-
-- b2dbfbf: add context_management for anthropic
-
-## 3.0.0-beta.76
-
-### Patch Changes
-
-- Updated dependencies [53f3368]
- - @ai-sdk/provider@3.0.0-beta.25
- - @ai-sdk/provider-utils@4.0.0-beta.44
-
-## 3.0.0-beta.75
-
-### Patch Changes
-
-- 0ae783e: feat(anthropic): add the new tool search tools
-
-## 3.0.0-beta.74
-
-### Patch Changes
-
-- dce03c4: feat: tool input examples
-- Updated dependencies [dce03c4]
- - @ai-sdk/provider-utils@4.0.0-beta.43
- - @ai-sdk/provider@3.0.0-beta.24
-
-## 3.0.0-beta.73
-
-### Patch Changes
-
-- Updated dependencies [3ed5519]
- - @ai-sdk/provider-utils@4.0.0-beta.42
-
-## 3.0.0-beta.72
-
-### Patch Changes
-
-- a5f77a6: fix(anthropic): remove outdated tool name docs
-
-## 3.0.0-beta.71
-
-### Patch Changes
-
-- 1bd7d32: feat: tool-specific strict mode
-- Updated dependencies [1bd7d32]
- - @ai-sdk/provider-utils@4.0.0-beta.41
- - @ai-sdk/provider@3.0.0-beta.23
-
-## 3.0.0-beta.70
-
-### Patch Changes
-
-- f13958c: chore(antropic): allow custom names for provider-defined tools
-
-## 3.0.0-beta.69
-
-### Patch Changes
-
-- 589a4ee: fix(anthropic): simplify pulling first chunk
-
-## 3.0.0-beta.68
-
-### Patch Changes
-
-- 9e35785: fix(anthropic): send {} as tool input when streaming tool calls without arguments
-
-## 3.0.0-beta.67
-
-### Patch Changes
-
-- eb56fc6: fix(anthropic): pull first chunk without async IIFE
-
-## 3.0.0-beta.66
-
-### Patch Changes
-
-- 544d4e8: chore(specification): rename v3 provider defined tool to provider tool
-- Updated dependencies [544d4e8]
- - @ai-sdk/provider-utils@4.0.0-beta.40
- - @ai-sdk/provider@3.0.0-beta.22
-
-## 3.0.0-beta.65
-
-### Patch Changes
-
-- 954c356: feat(openai): allow custom names for provider-defined tools
-- Updated dependencies [954c356]
- - @ai-sdk/provider-utils@4.0.0-beta.39
- - @ai-sdk/provider@3.0.0-beta.21
-
-## 3.0.0-beta.64
-
-### Patch Changes
-
-- 03849b0: throw 500 error when the first stream chunk is an error
-- Updated dependencies [03849b0]
- - @ai-sdk/provider-utils@4.0.0-beta.38
-
-## 3.0.0-beta.63
-
-### Patch Changes
-
-- 457318b: chore(provider,ai): switch to SharedV3Warning and unified warnings
-- Updated dependencies [457318b]
- - @ai-sdk/provider@3.0.0-beta.20
- - @ai-sdk/provider-utils@4.0.0-beta.37
-
-## 3.0.0-beta.62
-
-### Patch Changes
-
-- 8d9e8ad: chore(provider): remove generics from EmbeddingModelV3
-
- Before
-
- ```ts
- model.textEmbeddingModel("my-model-id");
- ```
-
- After
-
- ```ts
- model.embeddingModel("my-model-id");
- ```
-
-- Updated dependencies [8d9e8ad]
- - @ai-sdk/provider@3.0.0-beta.19
- - @ai-sdk/provider-utils@4.0.0-beta.36
-
-## 3.0.0-beta.61
-
-### Patch Changes
-
-- Updated dependencies [10d819b]
- - @ai-sdk/provider@3.0.0-beta.18
- - @ai-sdk/provider-utils@4.0.0-beta.35
-
-## 3.0.0-beta.60
-
-### Patch Changes
-
-- 6fc35cb: Retain user-supplied betas.
-
-## 3.0.0-beta.59
-
-### Patch Changes
-
-- 2109385: 'fix(anthropic): Opus 4.5 `maxOutputTokens` bump `32000` -> `64000`'
-
-## 3.0.0-beta.58
-
-### Patch Changes
-
-- 83aaad8: Opus 4.5 and `effort` provider option
-
-## 3.0.0-beta.57
-
-### Patch Changes
-
-- b8ea36e: feat(provider/anthropic): Anthropic-native structured outputs
-
-## 3.0.0-beta.56
-
-### Patch Changes
-
-- 983e394: chore(provider/anthropic): add missing provider options jsdoc
-
-## 3.0.0-beta.55
-
-### Patch Changes
-
-- Updated dependencies [db913bd]
- - @ai-sdk/provider@3.0.0-beta.17
- - @ai-sdk/provider-utils@4.0.0-beta.34
-
-## 3.0.0-beta.54
-
-### Patch Changes
-
-- 1d15673: fix(provider/anthropic): clamp temperature to valid 0-1 range with warnings
-
-## 3.0.0-beta.53
-
-### Patch Changes
-
-- Updated dependencies [b681d7d]
- - @ai-sdk/provider@3.0.0-beta.16
- - @ai-sdk/provider-utils@4.0.0-beta.33
-
-## 3.0.0-beta.52
-
-### Patch Changes
-
-- Updated dependencies [32d8dbb]
- - @ai-sdk/provider-utils@4.0.0-beta.32
-
-## 3.0.0-beta.51
-
-### Patch Changes
-
-- 1742445: Support for custom provider name in google and anthropic providers
-
-## 3.0.0-beta.50
-
-### Patch Changes
-
-- Updated dependencies [bb36798]
- - @ai-sdk/provider@3.0.0-beta.15
- - @ai-sdk/provider-utils@4.0.0-beta.31
-
-## 3.0.0-beta.49
-
-### Patch Changes
-
-- Updated dependencies [4f16c37]
- - @ai-sdk/provider-utils@4.0.0-beta.30
-
-## 3.0.0-beta.48
-
-### Patch Changes
-
-- Updated dependencies [af3780b]
- - @ai-sdk/provider@3.0.0-beta.14
- - @ai-sdk/provider-utils@4.0.0-beta.29
-
-## 3.0.0-beta.47
-
-### Patch Changes
-
-- Updated dependencies [016b111]
- - @ai-sdk/provider-utils@4.0.0-beta.28
-
-## 3.0.0-beta.46
-
-### Patch Changes
-
-- Updated dependencies [37c58a0]
- - @ai-sdk/provider@3.0.0-beta.13
- - @ai-sdk/provider-utils@4.0.0-beta.27
-
-## 3.0.0-beta.45
-
-### Patch Changes
-
-- f4e4a95: feat(provider/anthropic): enable fine grained tool streaming by default
-
-## 3.0.0-beta.44
-
-### Patch Changes
-
-- cf4e2a9: Add support for tool calling with structured output
-
-## 3.0.0-beta.43
-
-### Patch Changes
-
-- Updated dependencies [d1bdadb]
- - @ai-sdk/provider@3.0.0-beta.12
- - @ai-sdk/provider-utils@4.0.0-beta.26
-
-## 3.0.0-beta.42
-
-### Patch Changes
-
-- Updated dependencies [4c44a5b]
- - @ai-sdk/provider@3.0.0-beta.11
- - @ai-sdk/provider-utils@4.0.0-beta.25
-
-## 3.0.0-beta.41
-
-### Patch Changes
-
-- 0c3b58b: fix(provider): add specificationVersion to ProviderV3
-- Updated dependencies [0c3b58b]
- - @ai-sdk/provider@3.0.0-beta.10
- - @ai-sdk/provider-utils@4.0.0-beta.24
-
-## 3.0.0-beta.40
-
-### Patch Changes
-
-- Updated dependencies [a755db5]
- - @ai-sdk/provider@3.0.0-beta.9
- - @ai-sdk/provider-utils@4.0.0-beta.23
-
-## 3.0.0-beta.39
-
-### Patch Changes
-
-- Updated dependencies [58920e0]
- - @ai-sdk/provider-utils@4.0.0-beta.22
-
-## 3.0.0-beta.38
-
-### Patch Changes
-
-- Updated dependencies [293a6b7]
- - @ai-sdk/provider-utils@4.0.0-beta.21
-
-## 3.0.0-beta.37
-
-### Patch Changes
-
-- 7c4328e: Adds url-based pdf and image support for anthropic tool results
-
-## 3.0.0-beta.36
-
-### Patch Changes
-
-- 21f378c: fix(provider/anthropic): do not limit maxTokens when model id is unknown
-
-## 3.0.0-beta.35
-
-### Patch Changes
-
-- 80894b3: add return `file_id` property for anthropic code-execution-20250825 to download output files.
-
-## 3.0.0-beta.34
-
-### Patch Changes
-
-- Updated dependencies [fca786b]
- - @ai-sdk/provider-utils@4.0.0-beta.20
-
-## 3.0.0-beta.33
-
-### Patch Changes
-
-- 0e38a79: support ANTHROPIC_BASE_URL
-
-## 3.0.0-beta.32
-
-### Patch Changes
-
-- f4db7b5: feat(provider/anthropic): expose container from response in provider metadata
-
-## 3.0.0-beta.31
-
-### Patch Changes
-
-- ca07285: feat(anthropic): add prompt caching validation
-
-## 3.0.0-beta.30
-
-### Patch Changes
-
-- 9354297: feat(provider/anthropic): add support for Agent Skills
-
-## 3.0.0-beta.29
-
-### Patch Changes
-
-- 3794514: feat: flexible tool output content support
-- Updated dependencies [3794514]
- - @ai-sdk/provider-utils@4.0.0-beta.19
- - @ai-sdk/provider@3.0.0-beta.8
-
-## 3.0.0-beta.28
-
-### Patch Changes
-
-- 81d4308: feat(provider/anthropic): mcp connector support
-- Updated dependencies [81d4308]
- - @ai-sdk/provider@3.0.0-beta.7
- - @ai-sdk/provider-utils@4.0.0-beta.18
-
-## 3.0.0-beta.27
-
-### Patch Changes
-
-- 4c5a6be: feat(provider/anthropic): default and limit maxTokens based on model
-
-## 3.0.0-beta.26
-
-### Patch Changes
-
-- f33a018: chore: add model ID for Haiku 4.5
-
-## 3.0.0-beta.25
-
-### Patch Changes
-
-- Updated dependencies [703459a]
- - @ai-sdk/provider-utils@4.0.0-beta.17
-
-## 3.0.0-beta.24
-
-### Patch Changes
-
-- d08308b: feat(provider/anthropic): memory tool
-
-## 3.0.0-beta.23
-
-### Patch Changes
-
-- 6f845b4: Add support for 2025-08-25 code execution tool
-
-## 3.0.0-beta.22
-
-### Patch Changes
-
-- ed537e1: Add support for pdf file in tool result in anthropic
-
-## 3.0.0-beta.21
-
-### Patch Changes
-
-- Updated dependencies [6306603]
- - @ai-sdk/provider-utils@4.0.0-beta.16
-
-## 3.0.0-beta.20
-
-### Patch Changes
-
-- Updated dependencies [f0b2157]
- - @ai-sdk/provider-utils@4.0.0-beta.15
-
-## 3.0.0-beta.19
-
-### Patch Changes
-
-- Updated dependencies [3b1d015]
- - @ai-sdk/provider-utils@4.0.0-beta.14
-
-## 3.0.0-beta.18
-
-### Patch Changes
-
-- Updated dependencies [d116b4b]
- - @ai-sdk/provider-utils@4.0.0-beta.13
-
-## 3.0.0-beta.17
-
-### Patch Changes
-
-- Updated dependencies [7e32fea]
- - @ai-sdk/provider-utils@4.0.0-beta.12
-
-## 3.0.0-beta.16
-
-### Patch Changes
-
-- 9cff587: chore(provider/anthropic): lazy schema loading
-
-## 3.0.0-beta.15
-
-### Patch Changes
-
-- 95f65c2: chore: use import \* from zod/v4
-- Updated dependencies
- - @ai-sdk/provider-utils@4.0.0-beta.11
-
-## 3.0.0-beta.14
-
-### Major Changes
-
-- dee8b05: ai SDK 6 beta
-
-### Patch Changes
-
-- Updated dependencies [dee8b05]
- - @ai-sdk/provider@3.0.0-beta.6
- - @ai-sdk/provider-utils@4.0.0-beta.10
-
-## 2.1.0-beta.13
-
-### Patch Changes
-
-- Updated dependencies [521c537]
- - @ai-sdk/provider-utils@3.1.0-beta.9
-
-## 2.1.0-beta.12
-
-### Patch Changes
-
-- Updated dependencies [e06565c]
- - @ai-sdk/provider-utils@3.1.0-beta.8
-
-## 2.1.0-beta.11
-
-### Patch Changes
-
-- e8109d3: feat: tool execution approval
-- Updated dependencies
- - @ai-sdk/provider@2.1.0-beta.5
- - @ai-sdk/provider-utils@3.1.0-beta.7
-
-## 2.1.0-beta.10
-
-### Patch Changes
-
-- dedf206: feat(provider/anthropic): expose stop_sequence in provider metadata
-
-## 2.1.0-beta.9
-
-### Patch Changes
-
-- 0adc679: feat(provider): shared spec v3
-- Updated dependencies
- - @ai-sdk/provider-utils@3.1.0-beta.6
- - @ai-sdk/provider@2.1.0-beta.4
-
-## 2.1.0-beta.8
-
-### Patch Changes
-
-- a5a8db4: chore: add model ID for Sonnet 4.5
-
-## 2.1.0-beta.7
-
-### Patch Changes
-
-- e1e2821: fix(provider/anthropic): support null title in web fetch tool
-
-## 2.1.0-beta.6
-
-### Patch Changes
-
-- 8dac895: feat: `LanguageModelV3`
-- 10c1322: fix: moved dependency `@ai-sdk/test-server` to devDependencies
-- Updated dependencies [8dac895]
- - @ai-sdk/provider-utils@3.1.0-beta.5
- - @ai-sdk/provider@2.1.0-beta.3
-
-## 2.1.0-beta.5
-
-### Patch Changes
-
-- 11e4abe: feat(provider/anthropic): web search tool updates
-- afb00e3: feat(provider/anthropic): add text_editor_20250728 tool support
-
- Add text_editor_20250728 tool for Claude 4 models (Sonnet 4, Opus 4, Opus 4.1) with optional max_characters parameter and no undo_edit command support.
-
-- f6603b7: fix(provider/anthropic): correct raw usage information
-- fa35e95: feat(provider/anthropic): add web fetch tool
-- c5440c5: chore(provider/anthropic): update anthropic model ids
-
-## 2.1.0-beta.4
-
-### Patch Changes
-
-- 4616b86: chore: update zod peer depenedency version
-- Updated dependencies [4616b86]
- - @ai-sdk/provider-utils@3.1.0-beta.4
-
-## 2.1.0-beta.3
-
-### Patch Changes
-
-- ed329cb: feat: `Provider-V3`
-- Updated dependencies
- - @ai-sdk/provider@2.1.0-beta.2
- - @ai-sdk/provider-utils@3.1.0-beta.3
-
-## 2.1.0-beta.2
-
-### Patch Changes
-
-- 1cad0ab: feat: add provider version to user-agent header
-- Updated dependencies [0c4822d]
- - @ai-sdk/provider@2.1.0-beta.1
- - @ai-sdk/provider-utils@3.1.0-beta.2
-
-## 2.1.0-beta.1
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/test-server@1.0.0-beta.0
- - @ai-sdk/provider-utils@3.1.0-beta.1
-
-## 2.1.0-beta.0
-
-### Minor Changes
-
-- 78928cb: release: start 5.1 beta
-
-### Patch Changes
-
-- Updated dependencies [78928cb]
- - @ai-sdk/provider@2.1.0-beta.0
- - @ai-sdk/provider-utils@3.1.0-beta.0
-
-## 2.0.17
-
-### Patch Changes
-
-- da92132: fix(provider/anthorpic): add cacheControl to AnthropicProviderOptions
-
-## 2.0.16
-
-### Patch Changes
-
-- Updated dependencies [0294b58]
- - @ai-sdk/provider-utils@3.0.9
-
-## 2.0.15
-
-### Patch Changes
-
-- c8aab0a: fix (provider/anthropic): revert cd458a8c1667df86e6987a1f2e06159823453864
-
-## 2.0.14
-
-### Patch Changes
-
-- 2338c79: feat (provider/anthropic): update jsdoc of anthropic tools
-
-## 2.0.13
-
-### Patch Changes
-
-- cd458a8: fix(anthropic): reorder tool_result parts to front of combined user messages
-
- Reorders tool_result content to appear before user text within combined user messages, ensuring Claude API validation requirements are met while preserving the intentional message combining behavior that prevents role alternation errors. Fixes #8318.
-
-## 2.0.12
-
-### Patch Changes
-
-- Updated dependencies [99964ed]
- - @ai-sdk/provider-utils@3.0.8
-
-## 2.0.11
-
-### Patch Changes
-
-- c7fee29: feat(anthropic): handle `pause_turn` as value for `stop_reason`
-
-## 2.0.10
-
-### Patch Changes
-
-- c152ef7: feat(providers/anthropic): map 'refusal' stop reason to 'content-filter' finishReason
-
-## 2.0.9
-
-### Patch Changes
-
-- cdc6b7a: fix(provider/anthropic): disable parallel tool use when using json output tool for structured responses
-
-## 2.0.8
-
-### Patch Changes
-
-- Updated dependencies [886e7cd]
- - @ai-sdk/provider-utils@3.0.7
-
-## 2.0.7
-
-### Patch Changes
-
-- Updated dependencies [1b5a3d3]
- - @ai-sdk/provider-utils@3.0.6
-
-## 2.0.6
-
-### Patch Changes
-
-- Updated dependencies [0857788]
- - @ai-sdk/provider-utils@3.0.5
-
-## 2.0.5
-
-### Patch Changes
-
-- Updated dependencies [68751f9]
- - @ai-sdk/provider-utils@3.0.4
-
-## 2.0.4
-
-### Patch Changes
-
-- ae859ce: Added support for Anthropic provider's server-side code execution tool
-
-## 2.0.3
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.3
-
-## 2.0.2
-
-### Patch Changes
-
-- Updated dependencies [38ac190]
- - @ai-sdk/provider-utils@3.0.2
-
-## 2.0.1
-
-### Patch Changes
-
-- Updated dependencies [90d212f]
- - @ai-sdk/provider-utils@3.0.1
-
-## 2.0.0
-
-### Major Changes
-
-- d5f588f: AI SDK 5
-
-### Patch Changes
-
-- ad66c0e: feat (provider/anthropic): json response schema support via tool calls
-- 8f2854f: feat (provider/anthropic): send web search tool calls
-- 5d959e7: refactor: updated openai + anthropic tool use server side
-- 8dfcb11: feat(anthropic/citation): text support for citations
-- 9f73965: feat (provider/anthropic): parse websearch tool args
-- e2aceaf: feat: add raw chunk support
-- fdff8a4: fix(provider/anthropic): correct Claude 4 model ID format
-- eb173f1: chore (providers): remove model shorthand deprecation warnings
-- 4f26d59: feat(provider/anthropic): add disable parallel tool use option
-- 25f3454: feat(provider/anthropic): add PDF citation support with document sources for streamText
-- a85c85f: fix (provider/anthropic): streaming json output
-- 5c9eec4: chore(providers/anthropic): switch to providerOptions
-- 2e13791: feat(anthropic): add server-side web search support
-- 66962ed: fix(packages): export node10 compatible types
-- 075711d: fix (provider/anthropic): return stop finish reason for json output with tool
-- 269683f: Add raw Anthropic usage information to provider metadata
-- d601ed9: fix (provider/anthropic): send tool call id in tool-input-start chunk
-- b9ddcdd: feat(anthropic): add text_editor_20250429 tool for Claude 4 models
-- 91715e5: fix (provider/google-vertex): fix anthropic support for image urls in messages
-- ca8aac6: feat (providers/anthropic): add claude v4 models
-- 61ab528: Add support for URL-based PDF documents in the Anthropic provider
-- 84577c8: fix (providers/anthropic): remove fine grained tool streaming beta
-- d1a034f: feature: using Zod 4 for internal stuff
-- 6392f60: fix(anthropic): resolve web search API validation errors with partial location + provider output
-- 205077b: fix: improve Zod compatibility
-- ee5a9c0: feat: streamText onChunk raw chunk support
-- f418dd7: Added anthropic provider defined tool support to amazon bedrock
-- 362b048: add web search tool support
-- 399e056: fix: anthropic computer tool
-- 0b678b2: feat (provider/anthropic): enable streaming tool calls
-- f10304b: feat(tool-calling): don't require the user to have to pass parameters
-- a753b3a: feat (provider/anthropic): cache control for tools
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0
- - @ai-sdk/provider@2.0.0
-
-## 2.0.0-beta.13
-
-### Patch Changes
-
-- Updated dependencies [88a8ee5]
- - @ai-sdk/provider-utils@3.0.0-beta.10
-
-## 2.0.0-beta.12
-
-### Patch Changes
-
-- f418dd7: Added anthropic provider defined tool support to amazon bedrock
-- Updated dependencies [27deb4d]
- - @ai-sdk/provider@2.0.0-beta.2
- - @ai-sdk/provider-utils@3.0.0-beta.9
-
-## 2.0.0-beta.11
-
-### Patch Changes
-
-- eb173f1: chore (providers): remove model shorthand deprecation warnings
-- Updated dependencies [dd5fd43]
- - @ai-sdk/provider-utils@3.0.0-beta.8
-
-## 2.0.0-beta.10
-
-### Patch Changes
-
-- 269683f: Add raw Anthropic usage information to provider metadata
-- Updated dependencies [e7fcc86]
- - @ai-sdk/provider-utils@3.0.0-beta.7
-
-## 2.0.0-beta.9
-
-### Patch Changes
-
-- 4f26d59: feat(provider/anthropic): add disable parallel tool use option
-- a753b3a: feat (provider/anthropic): cache control for tools
-- Updated dependencies [ac34802]
- - @ai-sdk/provider-utils@3.0.0-beta.6
-
-## 2.0.0-beta.8
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-beta.5
-
-## 2.0.0-beta.7
-
-### Patch Changes
-
-- 205077b: fix: improve Zod compatibility
-- Updated dependencies [205077b]
- - @ai-sdk/provider-utils@3.0.0-beta.4
-
-## 2.0.0-beta.6
-
-### Patch Changes
-
-- Updated dependencies [05d2819]
- - @ai-sdk/provider-utils@3.0.0-beta.3
-
-## 2.0.0-beta.5
-
-### Patch Changes
-
-- b9ddcdd: feat(anthropic): add text_editor_20250429 tool for Claude 4 models
-
-## 2.0.0-beta.4
-
-### Patch Changes
-
-- fdff8a4: fix(provider/anthropic): correct Claude 4 model ID format
-- 84577c8: fix (providers/anthropic): remove fine grained tool streaming beta
-
-## 2.0.0-beta.3
-
-### Patch Changes
-
-- a85c85f: fix (provider/anthropic): streaming json output
-- d1a034f: feature: using Zod 4 for internal stuff
-- 0b678b2: feat (provider/anthropic): enable streaming tool calls
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-beta.2
-
-## 2.0.0-beta.2
-
-### Patch Changes
-
-- d601ed9: fix (provider/anthropic): send tool call id in tool-input-start chunk
-
-## 2.0.0-beta.1
-
-### Patch Changes
-
-- 8f2854f: feat (provider/anthropic): send web search tool calls
-- 5d959e7: refactor: updated openai + anthropic tool use server side
-- 9f73965: feat (provider/anthropic): parse websearch tool args
-- 399e056: fix: anthropic computer tool
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-beta.1
- - @ai-sdk/provider-utils@3.0.0-beta.1
-
-## 2.0.0-alpha.15
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-alpha.15
- - @ai-sdk/provider-utils@3.0.0-alpha.15
-
-## 2.0.0-alpha.14
-
-### Patch Changes
-
-- 2e13791: feat(anthropic): add server-side web search support
-- 6392f60: fix(anthropic): resolve web search API validation errors with partial location + provider output
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-alpha.14
- - @ai-sdk/provider-utils@3.0.0-alpha.14
-
-## 2.0.0-alpha.13
-
-### Patch Changes
-
-- 8dfcb11: feat(anthropic/citation): text support for citations
-- ee5a9c0: feat: streamText onChunk raw chunk support
-- Updated dependencies [68ecf2f]
- - @ai-sdk/provider@2.0.0-alpha.13
- - @ai-sdk/provider-utils@3.0.0-alpha.13
-
-## 2.0.0-alpha.12
-
-### Patch Changes
-
-- e2aceaf: feat: add raw chunk support
-- Updated dependencies [e2aceaf]
- - @ai-sdk/provider@2.0.0-alpha.12
- - @ai-sdk/provider-utils@3.0.0-alpha.12
-
-## 2.0.0-alpha.11
-
-### Patch Changes
-
-- 25f3454: feat(provider/anthropic): add PDF citation support with document sources for streamText
-- Updated dependencies [c1e6647]
- - @ai-sdk/provider@2.0.0-alpha.11
- - @ai-sdk/provider-utils@3.0.0-alpha.11
-
-## 2.0.0-alpha.10
-
-### Patch Changes
-
-- Updated dependencies [c4df419]
- - @ai-sdk/provider@2.0.0-alpha.10
- - @ai-sdk/provider-utils@3.0.0-alpha.10
-
-## 2.0.0-alpha.9
-
-### Patch Changes
-
-- 362b048: add web search tool support
-- Updated dependencies [811dff3]
- - @ai-sdk/provider@2.0.0-alpha.9
- - @ai-sdk/provider-utils@3.0.0-alpha.9
-
-## 2.0.0-alpha.8
-
-### Patch Changes
-
-- ad66c0e: feat (provider/anthropic): json response schema support via tool calls
-- 075711d: fix (provider/anthropic): return stop finish reason for json output with tool
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-alpha.8
- - @ai-sdk/provider@2.0.0-alpha.8
-
-## 2.0.0-alpha.7
-
-### Patch Changes
-
-- Updated dependencies [5c56081]
- - @ai-sdk/provider@2.0.0-alpha.7
- - @ai-sdk/provider-utils@3.0.0-alpha.7
-
-## 2.0.0-alpha.6
-
-### Patch Changes
-
-- Updated dependencies [0d2c085]
- - @ai-sdk/provider@2.0.0-alpha.6
- - @ai-sdk/provider-utils@3.0.0-alpha.6
-
-## 2.0.0-alpha.4
-
-### Patch Changes
-
-- ca8aac6: feat (providers/anthropic): add claude v4 models
-- Updated dependencies [dc714f3]
- - @ai-sdk/provider@2.0.0-alpha.4
- - @ai-sdk/provider-utils@3.0.0-alpha.4
-
-## 2.0.0-alpha.3
-
-### Patch Changes
-
-- Updated dependencies [6b98118]
- - @ai-sdk/provider@2.0.0-alpha.3
- - @ai-sdk/provider-utils@3.0.0-alpha.3
-
-## 2.0.0-alpha.2
-
-### Patch Changes
-
-- Updated dependencies [26535e0]
- - @ai-sdk/provider@2.0.0-alpha.2
- - @ai-sdk/provider-utils@3.0.0-alpha.2
-
-## 2.0.0-alpha.1
-
-### Patch Changes
-
-- Updated dependencies [3f2f00c]
- - @ai-sdk/provider@2.0.0-alpha.1
- - @ai-sdk/provider-utils@3.0.0-alpha.1
-
-## 2.0.0-canary.19
-
-### Patch Changes
-
-- Updated dependencies [faf8446]
- - @ai-sdk/provider-utils@3.0.0-canary.19
-
-## 2.0.0-canary.18
-
-### Patch Changes
-
-- Updated dependencies [40acf9b]
- - @ai-sdk/provider-utils@3.0.0-canary.18
-
-## 2.0.0-canary.17
-
-### Patch Changes
-
-- Updated dependencies [ea7a7c9]
- - @ai-sdk/provider-utils@3.0.0-canary.17
-
-## 2.0.0-canary.16
-
-### Patch Changes
-
-- Updated dependencies [87b828f]
- - @ai-sdk/provider-utils@3.0.0-canary.16
-
-## 2.0.0-canary.15
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-canary.15
- - @ai-sdk/provider@2.0.0-canary.14
-
-## 2.0.0-canary.14
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-canary.14
- - @ai-sdk/provider@2.0.0-canary.13
-
-## 2.0.0-canary.13
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.12
- - @ai-sdk/provider-utils@3.0.0-canary.13
-
-## 2.0.0-canary.12
-
-### Patch Changes
-
-- 5c9eec4: chore(providers/anthropic): switch to providerOptions
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.11
- - @ai-sdk/provider-utils@3.0.0-canary.12
-
-## 2.0.0-canary.11
-
-### Patch Changes
-
-- 66962ed: fix(packages): export node10 compatible types
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-canary.11
- - @ai-sdk/provider@2.0.0-canary.10
-
-## 2.0.0-canary.10
-
-### Patch Changes
-
-- Updated dependencies [e86be6f]
- - @ai-sdk/provider@2.0.0-canary.9
- - @ai-sdk/provider-utils@3.0.0-canary.10
-
-## 2.0.0-canary.9
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.8
- - @ai-sdk/provider-utils@3.0.0-canary.9
-
-## 2.0.0-canary.8
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-canary.8
- - @ai-sdk/provider@2.0.0-canary.7
-
-## 2.0.0-canary.7
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.6
- - @ai-sdk/provider-utils@3.0.0-canary.7
-
-## 2.0.0-canary.6
-
-### Patch Changes
-
-- f10304b: feat(tool-calling): don't require the user to have to pass parameters
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.5
- - @ai-sdk/provider-utils@3.0.0-canary.6
-
-## 2.0.0-canary.5
-
-### Patch Changes
-
-- Updated dependencies [6f6bb89]
- - @ai-sdk/provider@2.0.0-canary.4
- - @ai-sdk/provider-utils@3.0.0-canary.5
-
-## 2.0.0-canary.4
-
-### Patch Changes
-
-- Updated dependencies [d1a1aa1]
- - @ai-sdk/provider@2.0.0-canary.3
- - @ai-sdk/provider-utils@3.0.0-canary.4
-
-## 2.0.0-canary.3
-
-### Patch Changes
-
-- 61ab528: Add support for URL-based PDF documents in the Anthropic provider
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-canary.3
- - @ai-sdk/provider@2.0.0-canary.2
-
-## 2.0.0-canary.2
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.1
- - @ai-sdk/provider-utils@3.0.0-canary.2
-
-## 2.0.0-canary.1
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-canary.1
-
-## 2.0.0-canary.0
-
-### Major Changes
-
-- d5f588f: AI SDK 5
-
-### Patch Changes
-
-- 91715e5: fix (provider/google-vertex): fix anthropic support for image urls in messages
-- Updated dependencies [d5f588f]
- - @ai-sdk/provider-utils@3.0.0-canary.0
- - @ai-sdk/provider@2.0.0-canary.0
-
-## 1.2.4
-
-### Patch Changes
-
-- Updated dependencies [28be004]
- - @ai-sdk/provider-utils@2.2.3
-
-## 1.2.3
-
-### Patch Changes
-
-- Updated dependencies [b01120e]
- - @ai-sdk/provider-utils@2.2.2
-
-## 1.2.2
-
-### Patch Changes
-
-- aeaa92b: feat (provider/anthropic): expose type for validating Anthropic responses provider options
-
-## 1.2.1
-
-### Patch Changes
-
-- Updated dependencies [f10f0fa]
- - @ai-sdk/provider-utils@2.2.1
-
-## 1.2.0
-
-### Minor Changes
-
-- 5bc638d: AI SDK 4.2
-
-### Patch Changes
-
-- Updated dependencies [5bc638d]
- - @ai-sdk/provider@1.1.0
- - @ai-sdk/provider-utils@2.2.0
-
-## 1.1.19
-
-### Patch Changes
-
-- Updated dependencies [d0c4659]
- - @ai-sdk/provider-utils@2.1.15
-
-## 1.1.18
-
-### Patch Changes
-
-- Updated dependencies [0bd5bc6]
- - @ai-sdk/provider@1.0.12
- - @ai-sdk/provider-utils@2.1.14
-
-## 1.1.17
-
-### Patch Changes
-
-- Updated dependencies [2e1101a]
- - @ai-sdk/provider@1.0.11
- - @ai-sdk/provider-utils@2.1.13
-
-## 1.1.16
-
-### Patch Changes
-
-- Updated dependencies [1531959]
- - @ai-sdk/provider-utils@2.1.12
-
-## 1.1.15
-
-### Patch Changes
-
-- e1d3d42: feat (ai): expose raw response body in generateText and generateObject
-- Updated dependencies [e1d3d42]
- - @ai-sdk/provider@1.0.10
- - @ai-sdk/provider-utils@2.1.11
-
-## 1.1.14
-
-### Patch Changes
-
-- 0e8b66c: feat (provider/anthropic): support image urls
-
-## 1.1.13
-
-### Patch Changes
-
-- 3004b14: feat(provider/anthropic): add bash_20250124 and text_editor_20250124 tools
-
-## 1.1.12
-
-### Patch Changes
-
-- b3e5a15: fix (provider/anthropic): add model setting to allow omitting reasoning content from model requests
-
-## 1.1.11
-
-### Patch Changes
-
-- 00276ae: feat (provider/anthropic): update types for Anthropic computer_20250124 tool
-- a4f8714: feat (provider/anthropic): update beta flag for sonnet-3-7 when using new computer-use tool
-
-## 1.1.10
-
-### Patch Changes
-
-- ddf9740: feat (ai): add anthropic reasoning
-- Updated dependencies [ddf9740]
- - @ai-sdk/provider@1.0.9
- - @ai-sdk/provider-utils@2.1.10
-
-## 1.1.9
-
-### Patch Changes
-
-- Updated dependencies [2761f06]
- - @ai-sdk/provider@1.0.8
- - @ai-sdk/provider-utils@2.1.9
-
-## 1.1.8
-
-### Patch Changes
-
-- Updated dependencies [2e898b4]
- - @ai-sdk/provider-utils@2.1.8
-
-## 1.1.7
-
-### Patch Changes
-
-- Updated dependencies [3ff4ef8]
- - @ai-sdk/provider-utils@2.1.7
-
-## 1.1.6
-
-### Patch Changes
-
-- Updated dependencies [d89c3b9]
- - @ai-sdk/provider@1.0.7
- - @ai-sdk/provider-utils@2.1.6
-
-## 1.1.5
-
-### Patch Changes
-
-- Updated dependencies [3a602ca]
- - @ai-sdk/provider-utils@2.1.5
-
-## 1.1.4
-
-### Patch Changes
-
-- Updated dependencies [066206e]
- - @ai-sdk/provider-utils@2.1.4
-
-## 1.1.3
-
-### Patch Changes
-
-- Updated dependencies [39e5c1f]
- - @ai-sdk/provider-utils@2.1.3
-
-## 1.1.2
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@2.1.2
- - @ai-sdk/provider@1.0.6
-
-## 1.1.1
-
-### Patch Changes
-
-- 858f934: feat (provider/anthropic): default cache-control on and mark model setting deprecated
-- b284e2c: feat (provider/google-vertex): support prompt caching for Anthropic Claude models
-- Updated dependencies
- - @ai-sdk/provider-utils@2.1.1
- - @ai-sdk/provider@1.0.5
-
-## 1.1.0
-
-### Minor Changes
-
-- 62ba5ad: release: AI SDK 4.1
-
-### Patch Changes
-
-- Updated dependencies [62ba5ad]
- - @ai-sdk/provider-utils@2.1.0
-
-## 1.0.9
-
-### Patch Changes
-
-- Updated dependencies [00114c5]
- - @ai-sdk/provider-utils@2.0.8
-
-## 1.0.8
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@2.0.7
-
-## 1.0.7
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@1.0.4
- - @ai-sdk/provider-utils@2.0.6
-
-## 1.0.6
-
-### Patch Changes
-
-- 5ed5e45: chore (config): Use ts-library.json tsconfig for no-UI libs.
-- Updated dependencies [5ed5e45]
- - @ai-sdk/provider-utils@2.0.5
- - @ai-sdk/provider@1.0.3
-
-## 1.0.5
-
-### Patch Changes
-
-- Updated dependencies [09a9cab]
- - @ai-sdk/provider@1.0.2
- - @ai-sdk/provider-utils@2.0.4
-
-## 1.0.4
-
-### Patch Changes
-
-- bcd892e: feat (provider/google-vertex): Add support for Anthropic models.
-
-## 1.0.3
-
-### Patch Changes
-
-- Updated dependencies [0984f0b]
- - @ai-sdk/provider-utils@2.0.3
-
-## 1.0.2
-
-### Patch Changes
-
-- Updated dependencies [b446ae5]
- - @ai-sdk/provider@1.0.1
- - @ai-sdk/provider-utils@2.0.2
-
-## 1.0.1
-
-### Patch Changes
-
-- Updated dependencies [c3ab5de]
- - @ai-sdk/provider-utils@2.0.1
-
-## 1.0.0
-
-### Major Changes
-
-- 66060f7: chore (release): bump major version to 4.0
-- 0d3d3f5: chore (providers): remove baseUrl option
-- 8ad0504: chore (provider/anthropic): remove Anthropic facade
-- 2f6e8c0: chore (provider/anthropic): remove topK model setting
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@2.0.0
- - @ai-sdk/provider@1.0.0
-
-## 1.0.0-canary.4
-
-### Major Changes
-
-- 2f6e8c0: chore (provider/anthropic): remove topK model setting
-
-## 1.0.0-canary.3
-
-### Patch Changes
-
-- Updated dependencies [8426f55]
- - @ai-sdk/provider-utils@2.0.0-canary.3
-
-## 1.0.0-canary.2
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@2.0.0-canary.2
-
-## 1.0.0-canary.1
-
-### Major Changes
-
-- 0d3d3f5: chore (providers): remove baseUrl option
-- 8ad0504: chore (provider/anthropic): remove Anthropic facade
-
-### Patch Changes
-
-- Updated dependencies [b1da952]
- - @ai-sdk/provider-utils@2.0.0-canary.1
-
-## 1.0.0-canary.0
-
-### Major Changes
-
-- 66060f7: chore (release): bump major version to 4.0
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@2.0.0-canary.0
- - @ai-sdk/provider@1.0.0-canary.0
-
-## 0.0.56
-
-### Patch Changes
-
-- e6042b1: feat (provider/anthropic): add haiku 3.5 model ids
-
-## 0.0.55
-
-### Patch Changes
-
-- ac380e3: fix (provider/anthropic): continuation mode with 3+ steps
-
-## 0.0.54
-
-### Patch Changes
-
-- 4d2e53b: feat (provider/anthropic): pdf support
-- c8afcb5: feat (provider/anthropic): allow using computer use and cache control at the same time
-
-## 0.0.53
-
-### Patch Changes
-
-- 3b1b69a: feat (provider/anthropic): add computer use tools
-- 3b1b69a: feat: provider-defined tools
-- 8c222cd: feat (provider/anthropic): update model ids
-- 811a317: feat (ai/core): multi-part tool results (incl. images)
-- Updated dependencies
- - @ai-sdk/provider-utils@1.0.22
- - @ai-sdk/provider@0.0.26
-
-## 0.0.52
-
-### Patch Changes
-
-- b9b0d7b: feat (ai): access raw request body
-- Updated dependencies [b9b0d7b]
- - @ai-sdk/provider@0.0.25
- - @ai-sdk/provider-utils@1.0.21
-
-## 0.0.51
-
-### Patch Changes
-
-- Updated dependencies [d595d0d]
- - @ai-sdk/provider@0.0.24
- - @ai-sdk/provider-utils@1.0.20
-
-## 0.0.50
-
-### Patch Changes
-
-- Updated dependencies [273f696]
- - @ai-sdk/provider-utils@1.0.19
-
-## 0.0.49
-
-### Patch Changes
-
-- 03313cd: feat (ai): expose response id, response model, response timestamp in telemetry and api
-- 3be7c1c: fix (provider/anthropic): support prompt caching on assistant messages
-- Updated dependencies
- - @ai-sdk/provider-utils@1.0.18
- - @ai-sdk/provider@0.0.23
-
-## 0.0.48
-
-### Patch Changes
-
-- 26515cb: feat (ai/provider): introduce ProviderV1 specification
-- Updated dependencies [26515cb]
- - @ai-sdk/provider@0.0.22
- - @ai-sdk/provider-utils@1.0.17
-
-## 0.0.47
-
-### Patch Changes
-
-- Updated dependencies [09f895f]
- - @ai-sdk/provider-utils@1.0.16
-
-## 0.0.46
-
-### Patch Changes
-
-- Updated dependencies [d67fa9c]
- - @ai-sdk/provider-utils@1.0.15
-
-## 0.0.45
-
-### Patch Changes
-
-- 95a53a3: chore (provider/anthropic): remove tool calls beta header
-
-## 0.0.44
-
-### Patch Changes
-
-- Updated dependencies [f2c025e]
- - @ai-sdk/provider@0.0.21
- - @ai-sdk/provider-utils@1.0.14
-
-## 0.0.43
-
-### Patch Changes
-
-- 6ac355e: feat (provider/anthropic): add cache control support
-- Updated dependencies [6ac355e]
- - @ai-sdk/provider@0.0.20
- - @ai-sdk/provider-utils@1.0.13
-
-## 0.0.42
-
-### Patch Changes
-
-- dd712ac: fix: use FetchFunction type to prevent self-reference
-- Updated dependencies [dd712ac]
- - @ai-sdk/provider-utils@1.0.12
-
-## 0.0.41
-
-### Patch Changes
-
-- 89b18ca: fix (ai/provider): send finish reason 'unknown' by default
-- Updated dependencies [dd4a0f5]
- - @ai-sdk/provider@0.0.19
- - @ai-sdk/provider-utils@1.0.11
-
-## 0.0.40
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@1.0.10
- - @ai-sdk/provider@0.0.18
-
-## 0.0.39
-
-### Patch Changes
-
-- Updated dependencies [029af4c]
- - @ai-sdk/provider@0.0.17
- - @ai-sdk/provider-utils@1.0.9
-
-## 0.0.38
-
-### Patch Changes
-
-- Updated dependencies [d58517b]
- - @ai-sdk/provider@0.0.16
- - @ai-sdk/provider-utils@1.0.8
-
-## 0.0.37
-
-### Patch Changes
-
-- Updated dependencies [96aed25]
- - @ai-sdk/provider@0.0.15
- - @ai-sdk/provider-utils@1.0.7
-
-## 0.0.36
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@1.0.6
-
-## 0.0.35
-
-### Patch Changes
-
-- fe2128f0: feat (provider/anthropic): combine sequential assistant messages into one
-
-## 0.0.34
-
-### Patch Changes
-
-- 7d0fd5a8: fix (provider/anthropic): handle error stream chunks
-
-## 0.0.33
-
-### Patch Changes
-
-- a8d1c9e9: feat (ai/core): parallel image download
-- Updated dependencies [a8d1c9e9]
- - @ai-sdk/provider-utils@1.0.5
- - @ai-sdk/provider@0.0.14
-
-## 0.0.32
-
-### Patch Changes
-
-- Updated dependencies [4f88248f]
- - @ai-sdk/provider-utils@1.0.4
-
-## 0.0.31
-
-### Patch Changes
-
-- 2b9da0f0: feat (core): support stopSequences setting.
-- a5b58845: feat (core): support topK setting
-- 4aa8deb3: feat (provider): support responseFormat setting in provider api
-- 13b27ec6: chore (ai/core): remove grammar mode
-- Updated dependencies
- - @ai-sdk/provider@0.0.13
- - @ai-sdk/provider-utils@1.0.3
-
-## 0.0.30
-
-### Patch Changes
-
-- 4c6b80f7: chore (provider/anthropic): improve object-tool mode
-
-## 0.0.29
-
-### Patch Changes
-
-- Updated dependencies [b7290943]
- - @ai-sdk/provider@0.0.12
- - @ai-sdk/provider-utils@1.0.2
-
-## 0.0.28
-
-### Patch Changes
-
-- Updated dependencies [d481729f]
- - @ai-sdk/provider-utils@1.0.1
-
-## 0.0.27
-
-### Patch Changes
-
-- 7e86b45e: fix (provider/anthropic): automatically trim trailing whitespace on pre-filled assistant responses
-
-## 0.0.26
-
-### Patch Changes
-
-- 5edc6110: feat (ai/core): add custom request header support
-- Updated dependencies
- - @ai-sdk/provider@0.0.11
- - @ai-sdk/provider-utils@1.0.0
-
-## 0.0.25
-
-### Patch Changes
-
-- 91dc4296: chore (@ai-sdk/anthropic): remove anthropic-beta header
-
-## 0.0.24
-
-### Patch Changes
-
-- 04800838: fix (@ai-sdk/anthropic): combine tool and user messages, combine system messages
-
-## 0.0.23
-
-### Patch Changes
-
-- Updated dependencies [02f6a088]
- - @ai-sdk/provider-utils@0.0.16
-
-## 0.0.22
-
-### Patch Changes
-
-- 0a22b05b: feat (@ai-sdk/anthropic): add claude-3.5-sonnet model
-
-## 0.0.21
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@0.0.15
-
-## 0.0.20
-
-### Patch Changes
-
-- 4728c37f: feat (core): add text embedding model support to provider registry
-- 7910ae84: feat (providers): support custom fetch implementations
-- Updated dependencies [7910ae84]
- - @ai-sdk/provider-utils@0.0.14
-
-## 0.0.19
-
-### Patch Changes
-
-- Updated dependencies [102ca22f]
- - @ai-sdk/provider@0.0.10
- - @ai-sdk/provider-utils@0.0.13
-
-## 0.0.18
-
-### Patch Changes
-
-- 09295e2e: feat (@ai-sdk/anthropic): automatically download image URLs
-- Updated dependencies
- - @ai-sdk/provider@0.0.9
- - @ai-sdk/provider-utils@0.0.12
-
-## 0.0.17
-
-### Patch Changes
-
-- f39c0dd2: feat (provider): implement toolChoice support
-- Updated dependencies [f39c0dd2]
- - @ai-sdk/provider@0.0.8
- - @ai-sdk/provider-utils@0.0.11
-
-## 0.0.16
-
-### Patch Changes
-
-- 24683b72: fix (providers): Zod is required dependency
-- Updated dependencies [8e780288]
- - @ai-sdk/provider@0.0.7
- - @ai-sdk/provider-utils@0.0.10
-
-## 0.0.15
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@0.0.6
- - @ai-sdk/provider-utils@0.0.9
-
-## 0.0.14
-
-### Patch Changes
-
-- 06e3934: feat (provider/anthropic): streaming tool calls
-
-## 0.0.13
-
-### Patch Changes
-
-- Updated dependencies [0f6bc4e]
- - @ai-sdk/provider@0.0.5
- - @ai-sdk/provider-utils@0.0.8
-
-## 0.0.12
-
-### Patch Changes
-
-- Updated dependencies [325ca55]
- - @ai-sdk/provider@0.0.4
- - @ai-sdk/provider-utils@0.0.7
-
-## 0.0.11
-
-### Patch Changes
-
-- 5b01c13: feat (ai/core): add system message support in messages list
-
-## 0.0.10
-
-### Patch Changes
-
-- Updated dependencies [276f22b]
- - @ai-sdk/provider-utils@0.0.6
-
-## 0.0.9
-
-### Patch Changes
-
-- Updated dependencies [41d5736]
- - @ai-sdk/provider@0.0.3
- - @ai-sdk/provider-utils@0.0.5
-
-## 0.0.8
-
-### Patch Changes
-
-- Updated dependencies [56ef84a]
- - @ai-sdk/provider-utils@0.0.4
-
-## 0.0.7
-
-### Patch Changes
-
-- 25f3350: ai/core: add support for getting raw response headers.
-- Updated dependencies
- - @ai-sdk/provider@0.0.2
- - @ai-sdk/provider-utils@0.0.3
-
-## 0.0.6
-
-### Patch Changes
-
-- eb150a6: ai/core: remove scaling of setting values (breaking change). If you were using the temperature, frequency penalty, or presence penalty settings, you need to update the providers and adjust the setting values.
-- Updated dependencies [eb150a6]
- - @ai-sdk/provider-utils@0.0.2
- - @ai-sdk/provider@0.0.1
-
-## 0.0.5
-
-### Patch Changes
-
-- c6fc35b: Add custom header support.
-
-## 0.0.4
-
-### Patch Changes
-
-- ab60b18: Simplified model construction by directly calling provider functions. Add create... functions to create provider instances.
-
-## 0.0.3
-
-### Patch Changes
-
-- 587240b: Standardize providers to offer .chat() method
-
-## 0.0.2
-
-### Patch Changes
-
-- 2bff460: Fix build for release.
-
-## 0.0.1
-
-### Patch Changes
-
-- 7b8791d: Rename baseUrl to baseURL. Automatically remove trailing slashes.
-- Updated dependencies [7b8791d]
- - @ai-sdk/provider-utils@0.0.1
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/LICENSE b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/LICENSE
deleted file mode 100644
index 6c16c29f4..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/LICENSE
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright 2023 Vercel, Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
\ No newline at end of file
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/README.md b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/README.md
deleted file mode 100644
index 3d25ab811..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/README.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# AI SDK - Anthropic Provider
-
-The **[Anthropic provider](https://ai-sdk.dev/providers/ai-sdk-providers/anthropic)** for the [AI SDK](https://ai-sdk.dev/docs) contains language model support for the [Anthropic Messages API](https://docs.anthropic.com/claude/reference/messages_post).
-
-## Setup
-
-The Anthropic provider is available in the `@ai-sdk/anthropic` module. You can install it with
-
-```bash
-npm i @ai-sdk/anthropic
-```
-
-## Skill for Coding Agents
-
-If you use coding agents such as Claude Code or Cursor, we highly recommend adding the AI SDK skill to your repository:
-
-```shell
-npx skills add vercel/ai
-```
-
-## Provider Instance
-
-You can import the default provider instance `anthropic` from `@ai-sdk/anthropic`:
-
-```ts
-import { anthropic } from '@ai-sdk/anthropic';
-```
-
-## Example
-
-```ts
-import { anthropic } from '@ai-sdk/anthropic';
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: anthropic('claude-3-haiku-20240307'),
- prompt: 'Write a vegetarian lasagna recipe for 4 people.',
-});
-```
-
-## Documentation
-
-Please check out the **[Anthropic provider documentation](https://ai-sdk.dev/providers/ai-sdk-providers/anthropic)** for more information.
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/docs/05-anthropic.mdx b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/docs/05-anthropic.mdx
deleted file mode 100644
index bef2b7a3f..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/docs/05-anthropic.mdx
+++ /dev/null
@@ -1,1368 +0,0 @@
----
-title: Anthropic
-description: Learn how to use the Anthropic provider for the AI SDK.
----
-
-# Anthropic Provider
-
-The [Anthropic](https://www.anthropic.com/) provider contains language model support for the [Anthropic Messages API](https://docs.anthropic.com/claude/reference/messages_post).
-
-## Setup
-
-The Anthropic provider is available in the `@ai-sdk/anthropic` module. You can install it with
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-## Provider Instance
-
-You can import the default provider instance `anthropic` from `@ai-sdk/anthropic`:
-
-```ts
-import { anthropic } from '@ai-sdk/anthropic';
-```
-
-If you need a customized setup, you can import `createAnthropic` from `@ai-sdk/anthropic` and create a provider instance with your settings:
-
-```ts
-import { createAnthropic } from '@ai-sdk/anthropic';
-
-const anthropic = createAnthropic({
- // custom settings
-});
-```
-
-You can use the following optional settings to customize the Anthropic provider instance:
-
-- **baseURL** _string_
-
- Use a different URL prefix for API calls, e.g. to use proxy servers.
- The default prefix is `https://api.anthropic.com/v1`.
-
-- **apiKey** _string_
-
- API key that is being sent using the `x-api-key` header.
- It defaults to the `ANTHROPIC_API_KEY` environment variable.
- Only one of `apiKey` or `authToken` is required.
-
-- **authToken** _string_
-
- Auth token that is being sent using the `Authorization: Bearer` header.
- It defaults to the `ANTHROPIC_AUTH_TOKEN` environment variable.
- Only one of `apiKey` or `authToken` is required.
-
-- **headers** _Record<string,string>_
-
- Custom headers to include in the requests.
-
-- **fetch** _(input: RequestInfo, init?: RequestInit) => Promise<Response>_
-
- Custom [fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch) implementation.
- Defaults to the global `fetch` function.
- You can use it as a middleware to intercept requests,
- or to provide a custom fetch implementation for e.g. testing.
-
-## Language Models
-
-You can create models that call the [Anthropic Messages API](https://docs.anthropic.com/claude/reference/messages_post) using the provider instance.
-The first argument is the model id, e.g. `claude-3-haiku-20240307`.
-Some models have multi-modal capabilities.
-
-```ts
-const model = anthropic('claude-3-haiku-20240307');
-```
-
-You can also use the following aliases for model creation:
-
-- `anthropic.languageModel('claude-3-haiku-20240307')` - Creates a language model
-- `anthropic.chat('claude-3-haiku-20240307')` - Alias for `languageModel`
-- `anthropic.messages('claude-3-haiku-20240307')` - Alias for `languageModel`
-
-You can use Anthropic language models to generate text with the `generateText` function:
-
-```ts
-import { anthropic } from '@ai-sdk/anthropic';
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: anthropic('claude-3-haiku-20240307'),
- prompt: 'Write a vegetarian lasagna recipe for 4 people.',
-});
-```
-
-Anthropic language models can also be used in the `streamText` function
-and support structured data generation with [`Output`](/docs/reference/ai-sdk-core/output)
-(see [AI SDK Core](/docs/ai-sdk-core)).
-
-The following optional provider options are available for Anthropic models:
-
-- `disableParallelToolUse` _boolean_
-
- Optional. Disables the use of parallel tool calls. Defaults to `false`.
-
- When set to `true`, the model will only call one tool at a time instead of potentially calling multiple tools in parallel.
-
-- `sendReasoning` _boolean_
-
- Optional. Include reasoning content in requests sent to the model. Defaults to `true`.
-
- If you are experiencing issues with the model handling requests involving
- reasoning content, you can set this to `false` to omit them from the request.
-
-- `effort` _"high" | "medium" | "low"_
-
- Optional. See [Effort section](#effort) for more details.
-
-- `speed` _"fast" | "standard"_
-
- Optional. See [Fast Mode section](#fast-mode) for more details.
-
-- `thinking` _object_
-
- Optional. See [Reasoning section](#reasoning) for more details.
-
-- `toolStreaming` _boolean_
-
- Whether to enable tool streaming (and structured output streaming). Default to `true`.
-
-- `structuredOutputMode` _"outputFormat" | "jsonTool" | "auto"_
-
- Determines how structured outputs are generated. Optional.
-
- - `"outputFormat"`: Use the `output_format` parameter to specify the structured output format.
- - `"jsonTool"`: Use a special `"json"` tool to specify the structured output format.
- - `"auto"`: Use `"outputFormat"` when supported, otherwise fall back to `"jsonTool"` (default).
-
-- `metadata` _object_
-
- Optional. Metadata to include with the request. See the [Anthropic API documentation](https://platform.claude.com/docs/en/api/messages/create) for details.
-
- - `userId` _string_ - An external identifier for the end-user. Should be a UUID, hash, or other opaque identifier. Must not contain PII.
-
-### Structured Outputs and Tool Input Streaming
-
-Tool call streaming is enabled by default. You can opt out by setting the
-`toolStreaming` provider option to `false`.
-
-```ts
-import { anthropic } from '@ai-sdk/anthropic';
-import { streamText, tool } from 'ai';
-import { z } from 'zod';
-
-const result = streamText({
- model: anthropic('claude-sonnet-4-20250514'),
- tools: {
- writeFile: tool({
- description: 'Write content to a file',
- inputSchema: z.object({
- path: z.string(),
- content: z.string(),
- }),
- execute: async ({ path, content }) => {
- // Implementation
- return { success: true };
- },
- }),
- },
- prompt: 'Write a short story to story.txt',
-});
-```
-
-### Effort
-
-Anthropic introduced an `effort` option with `claude-opus-4-5` that affects thinking, text responses, and function calls. Effort defaults to `high` and you can set it to `medium` or `low` to save tokens and to lower time-to-last-token latency (TTLT).
-
-```ts highlight="8-10"
-import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
-import { generateText } from 'ai';
-
-const { text, usage } = await generateText({
- model: anthropic('claude-opus-4-20250514'),
- prompt: 'How many people will live in the world in 2040?',
- providerOptions: {
- anthropic: {
- effort: 'low',
- } satisfies AnthropicLanguageModelOptions,
- },
-});
-
-console.log(text); // resulting text
-console.log(usage); // token usage
-```
-
-### Fast Mode
-
-Anthropic supports a [`speed` option](https://code.claude.com/docs/en/fast-mode) for `claude-opus-4-6` that enables faster inference with approximately 2.5x faster output token speeds.
-
-```ts highlight="8-10"
-import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: anthropic('claude-opus-4-6'),
- prompt: 'Write a short poem about the sea.',
- providerOptions: {
- anthropic: {
- speed: 'fast',
- } satisfies AnthropicLanguageModelOptions,
- },
-});
-```
-
-The `speed` option accepts `'fast'` or `'standard'` (default behavior).
-
-### Reasoning
-
-Anthropic models support extended thinking, where Claude shows its reasoning process before providing a final answer.
-
-#### Adaptive Thinking
-
-For newer models (`claude-sonnet-4-6`, `claude-opus-4-6`, and later), use adaptive thinking.
-Claude automatically determines how much reasoning to use based on the complexity of the prompt.
-
-```ts highlight="4,8-10"
-import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
-import { generateText } from 'ai';
-
-const { text, reasoningText, reasoning } = await generateText({
- model: anthropic('claude-opus-4-6'),
- prompt: 'How many people will live in the world in 2040?',
- providerOptions: {
- anthropic: {
- thinking: { type: 'adaptive' },
- } satisfies AnthropicLanguageModelOptions,
- },
-});
-
-console.log(reasoningText); // reasoning text
-console.log(reasoning); // reasoning details including redacted reasoning
-console.log(text); // text response
-```
-
-You can combine adaptive thinking with the `effort` option to control how much reasoning Claude uses:
-
-```ts highlight="6-8"
-const { text } = await generateText({
- model: anthropic('claude-opus-4-6'),
- prompt: 'Invent a new holiday and describe its traditions.',
- providerOptions: {
- anthropic: {
- thinking: { type: 'adaptive' },
- effort: 'max', // 'low' | 'medium' | 'high' | 'max'
- } satisfies AnthropicLanguageModelOptions,
- },
-});
-```
-
-#### Budget-Based Thinking
-
-For earlier models (`claude-opus-4-20250514`, `claude-sonnet-4-20250514`, `claude-sonnet-4-5-20250929`),
-use `type: 'enabled'` with an explicit token budget:
-
-```ts highlight="4,8-10"
-import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
-import { generateText } from 'ai';
-
-const { text, reasoningText, reasoning } = await generateText({
- model: anthropic('claude-sonnet-4-5-20250929'),
- prompt: 'How many people will live in the world in 2040?',
- providerOptions: {
- anthropic: {
- thinking: { type: 'enabled', budgetTokens: 12000 },
- } satisfies AnthropicLanguageModelOptions,
- },
-});
-
-console.log(reasoningText); // reasoning text
-console.log(reasoning); // reasoning details including redacted reasoning
-console.log(text); // text response
-```
-
-See [AI SDK UI: Chatbot](/docs/ai-sdk-ui/chatbot#reasoning) for more details
-on how to integrate reasoning into your chatbot.
-
-### Context Management
-
-Anthropic's Context Management feature allows you to automatically manage conversation context by clearing tool uses or thinking content when certain conditions are met. This helps optimize token usage and manage long conversations more efficiently.
-
-You can configure context management using the `contextManagement` provider option:
-
-```ts highlight="7-20"
-import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: anthropic('claude-sonnet-4-5-20250929'),
- prompt: 'Continue our conversation...',
- providerOptions: {
- anthropic: {
- contextManagement: {
- edits: [
- {
- type: 'clear_tool_uses_20250919',
- trigger: { type: 'input_tokens', value: 10000 },
- keep: { type: 'tool_uses', value: 5 },
- clearAtLeast: { type: 'input_tokens', value: 1000 },
- clearToolInputs: true,
- excludeTools: ['important_tool'],
- },
- ],
- },
- } satisfies AnthropicLanguageModelOptions,
- },
-});
-
-// Check what was cleared
-console.log(result.providerMetadata?.anthropic?.contextManagement);
-```
-
-#### Context Editing
-
-Context editing strategies selectively remove specific content types from earlier in the conversation to reduce token usage without losing the overall conversation flow.
-
-##### Clear Tool Uses
-
-The `clear_tool_uses_20250919` edit type removes old tool call/result pairs from the conversation history:
-
-- **trigger** - Condition that triggers the clearing (e.g., `{ type: 'input_tokens', value: 10000 }` or `{ type: 'tool_uses', value: 10 }`)
-- **keep** - How many recent tool uses to preserve (e.g., `{ type: 'tool_uses', value: 5 }`)
-- **clearAtLeast** - Minimum amount to clear (e.g., `{ type: 'input_tokens', value: 1000 }`)
-- **clearToolInputs** - Whether to clear tool input parameters (boolean)
-- **excludeTools** - Array of tool names to never clear
-
-##### Clear Thinking
-
-The `clear_thinking_20251015` edit type removes thinking/reasoning blocks from earlier turns, keeping only the most recent ones:
-
-- **keep** - How many recent thinking turns to preserve (e.g., `{ type: 'thinking_turns', value: 2 }`) or `'all'` to keep everything
-
-```ts
-const result = await generateText({
- model: anthropic('claude-opus-4-20250514'),
- prompt: 'Continue reasoning...',
- providerOptions: {
- anthropic: {
- thinking: { type: 'enabled', budgetTokens: 12000 },
- contextManagement: {
- edits: [
- {
- type: 'clear_thinking_20251015',
- keep: { type: 'thinking_turns', value: 2 },
- },
- ],
- },
- } satisfies AnthropicLanguageModelOptions,
- },
-});
-```
-
-#### Compaction
-
-The `compact_20260112` edit type automatically summarizes earlier conversation context when token limits are reached. This is useful for long-running conversations where you want to preserve the essence of earlier exchanges while staying within token limits.
-
-```ts highlight="7-19"
-import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
-import { streamText } from 'ai';
-
-const result = streamText({
- model: anthropic('claude-opus-4-6'),
- messages: conversationHistory,
- providerOptions: {
- anthropic: {
- contextManagement: {
- edits: [
- {
- type: 'compact_20260112',
- trigger: {
- type: 'input_tokens',
- value: 50000, // trigger compaction when input exceeds 50k tokens
- },
- instructions:
- 'Summarize the conversation concisely, preserving key decisions and context.',
- pauseAfterCompaction: false,
- },
- ],
- },
- } satisfies AnthropicLanguageModelOptions,
- },
-});
-```
-
-**Configuration:**
-
-- **trigger** - Condition that triggers compaction (e.g., `{ type: 'input_tokens', value: 50000 }`)
-- **instructions** - Custom instructions for how the model should summarize the conversation. Use this to guide the compaction summary towards specific aspects of the conversation you want to preserve.
-- **pauseAfterCompaction** - When `true`, the model will pause after generating the compaction summary, allowing you to inspect or process it before continuing. Defaults to `false`.
-
-When compaction occurs, the model generates a summary of the earlier context. This summary appears as a text block with special provider metadata.
-
-##### Detecting Compaction in Streams
-
-When using `streamText`, you can detect compaction summaries by checking the `providerMetadata` on `text-start` events:
-
-```ts
-for await (const part of result.fullStream) {
- switch (part.type) {
- case 'text-start': {
- const isCompaction =
- part.providerMetadata?.anthropic?.type === 'compaction';
- if (isCompaction) {
- console.log('[COMPACTION SUMMARY START]');
- }
- break;
- }
- case 'text-delta': {
- process.stdout.write(part.text);
- break;
- }
- }
-}
-```
-
-##### Compaction in UI Applications
-
-When using `useChat` or other UI hooks, compaction summaries appear as regular text parts with `providerMetadata`. You can style them differently in your UI:
-
-```tsx
-{
- message.parts.map((part, index) => {
- if (part.type === 'text') {
- const isCompaction =
- (part.providerMetadata?.anthropic as { type?: string } | undefined)
- ?.type === 'compaction';
-
- if (isCompaction) {
- return (
-
-
[Compaction Summary]
-
{part.text}
-
- );
- }
- return {part.text}
;
- }
- });
-}
-```
-
-#### Applied Edits Metadata
-
-After generation, you can check which edits were applied in the provider metadata:
-
-```ts
-const metadata = result.providerMetadata?.anthropic?.contextManagement;
-
-if (metadata?.appliedEdits) {
- metadata.appliedEdits.forEach(edit => {
- if (edit.type === 'clear_tool_uses_20250919') {
- console.log(`Cleared ${edit.clearedToolUses} tool uses`);
- console.log(`Freed ${edit.clearedInputTokens} tokens`);
- } else if (edit.type === 'clear_thinking_20251015') {
- console.log(`Cleared ${edit.clearedThinkingTurns} thinking turns`);
- console.log(`Freed ${edit.clearedInputTokens} tokens`);
- } else if (edit.type === 'compact_20260112') {
- console.log('Compaction was applied');
- }
- });
-}
-```
-
-For more details, see [Anthropic's Context Management documentation](https://docs.anthropic.com/en/docs/build-with-claude/context-management).
-
-### Cache Control
-
-In the messages and message parts, you can use the `providerOptions` property to set cache control breakpoints.
-You need to set the `anthropic` property in the `providerOptions` object to `{ cacheControl: { type: 'ephemeral' } }` to set a cache control breakpoint.
-
-The cache creation input tokens are then returned in the `providerMetadata` object
-for `generateText`, again under the `anthropic` property.
-When you use `streamText`, the response contains a promise
-that resolves to the metadata. Alternatively you can receive it in the
-`onFinish` callback.
-
-```ts highlight="8,18-20,29-30"
-import { anthropic } from '@ai-sdk/anthropic';
-import { generateText } from 'ai';
-
-const errorMessage = '... long error message ...';
-
-const result = await generateText({
- model: anthropic('claude-sonnet-4-5'),
- messages: [
- {
- role: 'user',
- content: [
- { type: 'text', text: 'You are a JavaScript expert.' },
- {
- type: 'text',
- text: `Error message: ${errorMessage}`,
- providerOptions: {
- anthropic: { cacheControl: { type: 'ephemeral' } },
- },
- },
- { type: 'text', text: 'Explain the error message.' },
- ],
- },
- ],
-});
-
-console.log(result.text);
-console.log(result.providerMetadata?.anthropic);
-// e.g. { cacheCreationInputTokens: 2118 }
-```
-
-You can also use cache control on system messages by providing multiple system messages at the head of your messages array:
-
-```ts highlight="3,7-9"
-const result = await generateText({
- model: anthropic('claude-sonnet-4-5'),
- messages: [
- {
- role: 'system',
- content: 'Cached system message part',
- providerOptions: {
- anthropic: { cacheControl: { type: 'ephemeral' } },
- },
- },
- {
- role: 'system',
- content: 'Uncached system message part',
- },
- {
- role: 'user',
- content: 'User prompt',
- },
- ],
-});
-```
-
-Cache control for tools:
-
-```ts
-const result = await generateText({
- model: anthropic('claude-haiku-4-5'),
- tools: {
- cityAttractions: tool({
- inputSchema: z.object({ city: z.string() }),
- providerOptions: {
- anthropic: {
- cacheControl: { type: 'ephemeral' },
- },
- },
- }),
- },
- messages: [
- {
- role: 'user',
- content: 'User prompt',
- },
- ],
-});
-```
-
-#### Longer cache TTL
-
-Anthropic also supports a longer 1-hour cache duration.
-
-Here's an example:
-
-```ts
-const result = await generateText({
- model: anthropic('claude-haiku-4-5'),
- messages: [
- {
- role: 'user',
- content: [
- {
- type: 'text',
- text: 'Long cached message',
- providerOptions: {
- anthropic: {
- cacheControl: { type: 'ephemeral', ttl: '1h' },
- },
- },
- },
- ],
- },
- ],
-});
-```
-
-#### Limitations
-
-The minimum cacheable prompt length is:
-
-- 4096 tokens for Claude Opus 4.5
-- 1024 tokens for Claude Opus 4.1, Claude Opus 4, Claude Sonnet 4.5, Claude Sonnet 4, Claude Sonnet 3.7, and Claude Opus 3
-- 4096 tokens for Claude Haiku 4.5
-- 2048 tokens for Claude Haiku 3.5 and Claude Haiku 3
-
-Shorter prompts cannot be cached, even if marked with `cacheControl`. Any requests to cache fewer than this number of tokens will be processed without caching.
-
-For more on prompt caching with Anthropic, see [Anthropic's Cache Control documentation](https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching).
-
-
- Because the `UIMessage` type (used by AI SDK UI hooks like `useChat`) does not
- support the `providerOptions` property, you can use `convertToModelMessages`
- first before passing the messages to functions like `generateText` or
- `streamText`. For more details on `providerOptions` usage, see
- [here](/docs/foundations/prompts#provider-options).
-
-
-### Bash Tool
-
-The Bash Tool allows running bash commands. Here's how to create and use it:
-
-```ts
-const bashTool = anthropic.tools.bash_20250124({
- execute: async ({ command, restart }) => {
- // Implement your bash command execution logic here
- // Return the result of the command execution
- },
-});
-```
-
-Parameters:
-
-- `command` (string): The bash command to run. Required unless the tool is being restarted.
-- `restart` (boolean, optional): Specifying true will restart this tool.
-
-
- Two versions are available: `bash_20250124` (recommended) and `bash_20241022`.
- Only certain Claude versions are supported.
-
-
-### Memory Tool
-
-The [Memory Tool](https://docs.claude.com/en/docs/agents-and-tools/tool-use/memory-tool) allows Claude to use a local memory, e.g. in the filesystem.
-Here's how to create it:
-
-```ts
-const memory = anthropic.tools.memory_20250818({
- execute: async action => {
- // Implement your memory command execution logic here
- // Return the result of the command execution
- },
-});
-```
-
-Only certain Claude versions are supported.
-
-### Text Editor Tool
-
-The Text Editor Tool provides functionality for viewing and editing text files.
-
-```ts
-const tools = {
- str_replace_based_edit_tool: anthropic.tools.textEditor_20250728({
- maxCharacters: 10000, // optional
- async execute({ command, path, old_str, new_str, insert_text }) {
- // ...
- },
- }),
-} satisfies ToolSet;
-```
-
-
- Different models support different versions of the tool:
-
-- `textEditor_20250728` - For Claude Sonnet 4, Opus 4, and Opus 4.1 (recommended)
-- `textEditor_20250124` - For Claude Sonnet 3.7
-- `textEditor_20241022` - For Claude Sonnet 3.5
-
-Note: `textEditor_20250429` is deprecated. Use `textEditor_20250728` instead.
-
-
-
-Parameters:
-
-- `command` ('view' | 'create' | 'str_replace' | 'insert' | 'undo_edit'): The command to run. Note: `undo_edit` is only available in Claude 3.5 Sonnet and earlier models.
-- `path` (string): Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`.
-- `file_text` (string, optional): Required for `create` command, with the content of the file to be created.
-- `insert_line` (number, optional): Required for `insert` command. The line number after which to insert the new string.
-- `new_str` (string, optional): New string for `str_replace` command.
-- `insert_text` (string, optional): Required for `insert` command, containing the text to insert.
-- `old_str` (string, optional): Required for `str_replace` command, containing the string to replace.
-- `view_range` (number[], optional): Optional for `view` command to specify line range to show.
-
-### Computer Tool
-
-The Computer Tool enables control of keyboard and mouse actions on a computer:
-
-```ts
-const computerTool = anthropic.tools.computer_20251124({
- displayWidthPx: 1920,
- displayHeightPx: 1080,
- displayNumber: 0, // Optional, for X11 environments
- enableZoom: true, // Optional, enables the zoom action
-
- execute: async ({ action, coordinate, text, region }) => {
- // Implement your computer control logic here
- // Return the result of the action
-
- // Example code:
- switch (action) {
- case 'screenshot': {
- // multipart result:
- return {
- type: 'image',
- data: fs
- .readFileSync('./data/screenshot-editor.png')
- .toString('base64'),
- };
- }
- case 'zoom': {
- // region is [x1, y1, x2, y2] defining the area to zoom into
- return {
- type: 'image',
- data: fs.readFileSync('./data/zoomed-region.png').toString('base64'),
- };
- }
- default: {
- console.log('Action:', action);
- console.log('Coordinate:', coordinate);
- console.log('Text:', text);
- return `executed ${action}`;
- }
- }
- },
-
- // map to tool result content for LLM consumption:
- toModelOutput({ output }) {
- return typeof output === 'string'
- ? [{ type: 'text', text: output }]
- : [{ type: 'image', data: output.data, mediaType: 'image/png' }];
- },
-});
-```
-
-
- Use `computer_20251124` for Claude Opus 4.5 which supports the zoom action.
- Use `computer_20250124` for Claude Sonnet 4.5, Haiku 4.5, Opus 4.1, Sonnet 4,
- Opus 4, and Sonnet 3.7.
-
-
-Parameters:
-
-- `action` ('key' | 'type' | 'mouse_move' | 'left_click' | 'left_click_drag' | 'right_click' | 'middle_click' | 'double_click' | 'screenshot' | 'cursor_position' | 'zoom'): The action to perform. The `zoom` action is only available with `computer_20251124`.
-- `coordinate` (number[], optional): Required for `mouse_move` and `left_click_drag` actions. Specifies the (x, y) coordinates.
-- `text` (string, optional): Required for `type` and `key` actions.
-- `region` (number[], optional): Required for `zoom` action. Specifies `[x1, y1, x2, y2]` coordinates for the area to inspect.
-- `displayWidthPx` (number): The width of the display in pixels.
-- `displayHeightPx` (number): The height of the display in pixels.
-- `displayNumber` (number, optional): The display number for X11 environments.
-- `enableZoom` (boolean, optional): Enable the zoom action. Only available with `computer_20251124`. Default: `false`.
-
-### Web Search Tool
-
-Anthropic provides a provider-defined web search tool that gives Claude direct access to real-time web content, allowing it to answer questions with up-to-date information beyond its knowledge cutoff.
-
-You can enable web search using the provider-defined web search tool:
-
-```ts
-import { anthropic } from '@ai-sdk/anthropic';
-import { generateText } from 'ai';
-
-const webSearchTool = anthropic.tools.webSearch_20250305({
- maxUses: 5,
-});
-
-const result = await generateText({
- model: anthropic('claude-opus-4-20250514'),
- prompt: 'What are the latest developments in AI?',
- tools: {
- web_search: webSearchTool,
- },
-});
-```
-
-
- Web search must be enabled in your organization's [Console
- settings](https://console.anthropic.com/settings/privacy).
-
-
-#### Configuration Options
-
-The web search tool supports several configuration options:
-
-- **maxUses** _number_
-
- Maximum number of web searches Claude can perform during the conversation.
-
-- **allowedDomains** _string[]_
-
- Optional list of domains that Claude is allowed to search. If provided, searches will be restricted to these domains.
-
-- **blockedDomains** _string[]_
-
- Optional list of domains that Claude should avoid when searching.
-
-- **userLocation** _object_
-
- Optional user location information to provide geographically relevant search results.
-
-```ts
-const webSearchTool = anthropic.tools.webSearch_20250305({
- maxUses: 3,
- allowedDomains: ['techcrunch.com', 'wired.com'],
- blockedDomains: ['example-spam-site.com'],
- userLocation: {
- type: 'approximate',
- country: 'US',
- region: 'California',
- city: 'San Francisco',
- timezone: 'America/Los_Angeles',
- },
-});
-
-const result = await generateText({
- model: anthropic('claude-opus-4-20250514'),
- prompt: 'Find local news about technology',
- tools: {
- web_search: webSearchTool,
- },
-});
-```
-
-### Web Fetch Tool
-
-Anthropic provides a provider-defined web fetch tool that allows Claude to retrieve content from specific URLs. This is useful when you want Claude to analyze or reference content from a particular webpage or document.
-
-You can enable web fetch using the provider-defined web fetch tool:
-
-```ts
-import { anthropic } from '@ai-sdk/anthropic';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: anthropic('claude-sonnet-4-0'),
- prompt:
- 'What is this page about? https://en.wikipedia.org/wiki/Maglemosian_culture',
- tools: {
- web_fetch: anthropic.tools.webFetch_20250910({ maxUses: 1 }),
- },
-});
-```
-
-### Tool Search
-
-Anthropic provides provider-defined tool search tools that enable Claude to work with hundreds or thousands of tools by dynamically discovering and loading them on-demand. Instead of loading all tool definitions into the context window upfront, Claude searches your tool catalog and loads only the tools it needs.
-
-There are two variants:
-
-- **BM25 Search** - Uses natural language queries to find tools
-- **Regex Search** - Uses regex patterns (Python `re.search()` syntax) to find tools
-
-#### Basic Usage
-
-```ts
-import { anthropic } from '@ai-sdk/anthropic';
-import { generateText, tool } from 'ai';
-import { z } from 'zod';
-
-const result = await generateText({
- model: anthropic('claude-sonnet-4-5'),
- prompt: 'What is the weather in San Francisco?',
- tools: {
- toolSearch: anthropic.tools.toolSearchBm25_20251119(),
-
- get_weather: tool({
- description: 'Get the current weather at a specific location',
- inputSchema: z.object({
- location: z.string().describe('The city and state'),
- }),
- execute: async ({ location }) => ({
- location,
- temperature: 72,
- condition: 'Sunny',
- }),
- // Defer tool here - Claude discovers these via the tool search tool
- providerOptions: {
- anthropic: { deferLoading: true },
- },
- }),
- },
-});
-```
-
-#### Using Regex Search
-
-For more precise tool matching, you can use the regex variant:
-
-```ts
-const result = await generateText({
- model: anthropic('claude-sonnet-4-5'),
- prompt: 'Get the weather data',
- tools: {
- toolSearch: anthropic.tools.toolSearchRegex_20251119(),
- // ... deferred tools
- },
-});
-```
-
-Claude will construct regex patterns like `weather|temperature|forecast` to find matching tools.
-
-#### Custom Tool Search
-
-You can implement your own tool search logic (e.g., using embeddings or semantic search) by returning `tool-reference` content blocks via `toModelOutput`:
-
-```ts
-import { anthropic } from '@ai-sdk/anthropic';
-import { generateText, tool } from 'ai';
-import { z } from 'zod';
-
-const result = await generateText({
- model: anthropic('claude-sonnet-4-5'),
- prompt: 'What is the weather in San Francisco?',
- tools: {
- // Custom search tool
- searchTools: tool({
- description: 'Search for tools by keyword',
- inputSchema: z.object({ query: z.string() }),
- execute: async ({ query }) => {
- // Your custom search logic (embeddings, fuzzy match, etc.)
- const allTools = ['get_weather', 'get_forecast', 'get_temperature'];
- return allTools.filter(name => name.includes(query.toLowerCase()));
- },
- toModelOutput: ({ output }) => ({
- type: 'content',
- value: (output as string[]).map(toolName => ({
- type: 'custom' as const,
- providerOptions: {
- anthropic: {
- type: 'tool-reference',
- toolName,
- },
- },
- })),
- }),
- }),
-
- // Deferred tools
- get_weather: tool({
- description: 'Get the current weather',
- inputSchema: z.object({ location: z.string() }),
- execute: async ({ location }) => ({ location, temperature: 72 }),
- providerOptions: {
- anthropic: { deferLoading: true },
- },
- }),
- },
-});
-```
-
-This sends `tool_reference` blocks to Anthropic, which loads the corresponding deferred tool schemas into Claude's context.
-
-### MCP Connectors
-
-Anthropic supports connecting to [MCP servers](https://docs.claude.com/en/docs/agents-and-tools/mcp-connector) as part of their execution.
-
-You can enable this feature with the `mcpServers` provider option:
-
-```ts
-import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: anthropic('claude-sonnet-4-5'),
- prompt: `Call the echo tool with "hello world". what does it respond with back?`,
- providerOptions: {
- anthropic: {
- mcpServers: [
- {
- type: 'url',
- name: 'echo',
- url: 'https://echo.mcp.inevitable.fyi/mcp',
- // optional: authorization token
- authorizationToken: mcpAuthToken,
- // optional: tool configuration
- toolConfiguration: {
- enabled: true,
- allowedTools: ['echo'],
- },
- },
- ],
- } satisfies AnthropicLanguageModelOptions,
- },
-});
-```
-
-The tool calls and results are dynamic, i.e. the input and output schemas are not known.
-
-#### Configuration Options
-
-The web fetch tool supports several configuration options:
-
-- **maxUses** _number_
-
- The maxUses parameter limits the number of web fetches performed.
-
-- **allowedDomains** _string[]_
-
- Only fetch from these domains.
-
-- **blockedDomains** _string[]_
-
- Never fetch from these domains.
-
-- **citations** _object_
-
- Unlike web search where citations are always enabled, citations are optional for web fetch. Set `"citations": {"enabled": true}` to enable Claude to cite specific passages from fetched documents.
-
-- **maxContentTokens** _number_
-
- The maxContentTokens parameter limits the amount of content that will be included in the context.
-
-#### Error Handling
-
-Web search errors are handled differently depending on whether you're using streaming or non-streaming:
-
-**Non-streaming (`generateText`):**
-Web search errors throw exceptions that you can catch:
-
-```ts
-try {
- const result = await generateText({
- model: anthropic('claude-opus-4-20250514'),
- prompt: 'Search for something',
- tools: {
- web_search: webSearchTool,
- },
- });
-} catch (error) {
- if (error.message.includes('Web search failed')) {
- console.log('Search error:', error.message);
- // Handle search error appropriately
- }
-}
-```
-
-**Streaming (`streamText`):**
-Web search errors are delivered as error parts in the stream:
-
-```ts
-const result = await streamText({
- model: anthropic('claude-opus-4-20250514'),
- prompt: 'Search for something',
- tools: {
- web_search: webSearchTool,
- },
-});
-
-for await (const part of result.textStream) {
- if (part.type === 'error') {
- console.log('Search error:', part.error);
- // Handle search error appropriately
- }
-}
-```
-
-## Code Execution
-
-Anthropic provides a provider-defined code execution tool that gives Claude direct access to a real Python environment allowing it to execute code to inform its responses.
-
-You can enable code execution using the provider-defined code execution tool:
-
-```ts
-import { anthropic } from '@ai-sdk/anthropic';
-import { generateText } from 'ai';
-
-const codeExecutionTool = anthropic.tools.codeExecution_20260120();
-
-const result = await generateText({
- model: anthropic('claude-opus-4-20250514'),
- prompt:
- 'Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]',
- tools: {
- code_execution: codeExecutionTool,
- },
-});
-```
-
-
- Three versions are available: `codeExecution_20260120` (recommended, does not
- require a beta header, supports Claude Opus 4.6, Sonnet 4.6, Sonnet 4.5, and
- Opus 4.5), `codeExecution_20250825` (supports Python and Bash with enhanced
- file operations), and `codeExecution_20250522` (supports Bash only).
-
-
-#### Error Handling
-
-Code execution errors are handled differently depending on whether you're using streaming or non-streaming:
-
-**Non-streaming (`generateText`):**
-Code execution errors are delivered as tool result parts in the response:
-
-```ts
-const result = await generateText({
- model: anthropic('claude-opus-4-20250514'),
- prompt: 'Execute some Python script',
- tools: {
- code_execution: codeExecutionTool,
- },
-});
-
-const toolErrors = result.content?.filter(
- content => content.type === 'tool-error',
-);
-
-toolErrors?.forEach(error => {
- console.error('Tool execution error:', {
- toolName: error.toolName,
- toolCallId: error.toolCallId,
- error: error.error,
- });
-});
-```
-
-**Streaming (`streamText`):**
-Code execution errors are delivered as error parts in the stream:
-
-```ts
-const result = await streamText({
- model: anthropic('claude-opus-4-20250514'),
- prompt: 'Execute some Python script',
- tools: {
- code_execution: codeExecutionTool,
- },
-});
-for await (const part of result.textStream) {
- if (part.type === 'error') {
- console.log('Code execution error:', part.error);
- // Handle code execution error appropriately
- }
-}
-```
-
-### Programmatic Tool Calling
-
-[Programmatic Tool Calling](https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/programmatic-tool-calling) allows Claude to write code that calls your tools programmatically within a code execution container, rather than requiring round trips through the model for each tool invocation. This reduces latency for multi-tool workflows and decreases token consumption.
-
-To enable programmatic tool calling, use the `allowedCallers` provider option on tools that you want to be callable from within code execution:
-
-```ts highlight="13-17"
-import {
- anthropic,
- forwardAnthropicContainerIdFromLastStep,
-} from '@ai-sdk/anthropic';
-import { generateText, tool, stepCountIs } from 'ai';
-import { z } from 'zod';
-
-const result = await generateText({
- model: anthropic('claude-sonnet-4-5'),
- stopWhen: stepCountIs(10),
- prompt:
- 'Get the weather for Tokyo, Sydney, and London, then calculate the average temperature.',
- tools: {
- code_execution: anthropic.tools.codeExecution_20260120(),
-
- getWeather: tool({
- description: 'Get current weather data for a city.',
- inputSchema: z.object({
- city: z.string().describe('Name of the city'),
- }),
- execute: async ({ city }) => {
- // Your weather API implementation
- return { temp: 22, condition: 'Sunny' };
- },
- // Enable this tool to be called from within code execution
- providerOptions: {
- anthropic: {
- allowedCallers: ['code_execution_20260120'],
- },
- },
- }),
- },
-
- // Propagate container ID between steps for code execution continuity
- prepareStep: forwardAnthropicContainerIdFromLastStep,
-});
-```
-
-In this flow:
-
-1. Claude writes Python code that calls your `getWeather` tool multiple times in parallel
-2. The SDK automatically executes your tool and returns results to the code execution container
-3. Claude processes the results in code and generates the final response
-
-
- Programmatic tool calling requires `claude-sonnet-4-6`, `claude-sonnet-4-5`,
- `claude-opus-4-6`, or `claude-opus-4-5` models and uses the
- `code_execution_20260120` or `code_execution_20250825` tool.
-
-
-#### Container Persistence
-
-When using programmatic tool calling across multiple steps, you need to preserve the container ID between steps using `prepareStep`. You can use the `forwardAnthropicContainerIdFromLastStep` helper function to do this automatically. The container ID is available in `providerMetadata.anthropic.container.id` after each step completes.
-
-## Agent Skills
-
-[Anthropic Agent Skills](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/overview) enable Claude to perform specialized tasks like document processing (PPTX, DOCX, PDF, XLSX) and data analysis. Skills run in a sandboxed container and require the code execution tool to be enabled.
-
-### Using Built-in Skills
-
-Anthropic provides several built-in skills:
-
-- **pptx** - Create and edit PowerPoint presentations
-- **docx** - Create and edit Word documents
-- **pdf** - Process and analyze PDF files
-- **xlsx** - Work with Excel spreadsheets
-
-To use skills, you need to:
-
-1. Enable the code execution tool
-2. Specify the container with skills in `providerOptions`
-
-```ts highlight="4,9-17,19-23"
-import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: anthropic('claude-sonnet-4-5'),
- tools: {
- code_execution: anthropic.tools.codeExecution_20260120(),
- },
- prompt: 'Create a presentation about renewable energy with 5 slides',
- providerOptions: {
- anthropic: {
- container: {
- skills: [
- {
- type: 'anthropic',
- skillId: 'pptx',
- version: 'latest', // optional
- },
- ],
- },
- } satisfies AnthropicLanguageModelOptions,
- },
-});
-```
-
-### Custom Skills
-
-You can also use custom skills by specifying `type: 'custom'`:
-
-```ts highlight="9-11"
-const result = await generateText({
- model: anthropic('claude-sonnet-4-5'),
- tools: {
- code_execution: anthropic.tools.codeExecution_20260120(),
- },
- prompt: 'Use my custom skill to process this data',
- providerOptions: {
- anthropic: {
- container: {
- skills: [
- {
- type: 'custom',
- skillId: 'my-custom-skill-id',
- version: '1.0', // optional
- },
- ],
- },
- } satisfies AnthropicLanguageModelOptions,
- },
-});
-```
-
-
- Skills use progressive context loading and execute within a sandboxed
- container with code execution capabilities.
-
-
-### PDF support
-
-Anthropic Claude models support reading PDF files.
-You can pass PDF files as part of the message content using the `file` type:
-
-Option 1: URL-based PDF document
-
-```ts
-const result = await generateText({
- model: anthropic('claude-sonnet-4-5'),
- messages: [
- {
- role: 'user',
- content: [
- {
- type: 'text',
- text: 'What is an embedding model according to this document?',
- },
- {
- type: 'file',
- data: new URL(
- 'https://github.com/vercel/ai/blob/main/examples/ai-functions/data/ai.pdf?raw=true',
- ),
- mimeType: 'application/pdf',
- },
- ],
- },
- ],
-});
-```
-
-Option 2: Base64-encoded PDF document
-
-```ts
-const result = await generateText({
- model: anthropic('claude-sonnet-4-5'),
- messages: [
- {
- role: 'user',
- content: [
- {
- type: 'text',
- text: 'What is an embedding model according to this document?',
- },
- {
- type: 'file',
- data: fs.readFileSync('./data/ai.pdf'),
- mediaType: 'application/pdf',
- },
- ],
- },
- ],
-});
-```
-
-The model will have access to the contents of the PDF file and
-respond to questions about it.
-The PDF file should be passed using the `data` field,
-and the `mediaType` should be set to `'application/pdf'`.
-
-### Model Capabilities
-
-| Model | Image Input | Object Generation | Tool Usage | Computer Use | Web Search | Tool Search | Compaction |
-| ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- |
-| `claude-opus-4-6` | | | | | | | |
-| `claude-sonnet-4-6` | | | | | | | |
-| `claude-opus-4-5` | | | | | | | |
-| `claude-haiku-4-5` | | | | | | | |
-| `claude-sonnet-4-5` | | | | | | | |
-| `claude-opus-4-1` | | | | | | | |
-| `claude-opus-4-0` | | | | | | | |
-| `claude-sonnet-4-0` | | | | | | | |
-
-
- The table above lists popular models. Please see the [Anthropic
- docs](https://docs.anthropic.com/en/docs/about-claude/models) for a full list
- of available models. The table above lists popular models. You can also pass
- any available provider model ID as a string if needed.
-
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/internal.d.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/internal.d.ts
deleted file mode 100644
index be034cd88..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/internal.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './dist/internal';
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/package.json b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/package.json
deleted file mode 100644
index 19c717b55..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/package.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "name": "@ai-sdk/anthropic",
- "version": "3.0.64",
- "license": "Apache-2.0",
- "sideEffects": false,
- "main": "./dist/index.js",
- "module": "./dist/index.mjs",
- "types": "./dist/index.d.ts",
- "files": [
- "dist/**/*",
- "docs/**/*",
- "src",
- "!src/**/*.test.ts",
- "!src/**/*.test-d.ts",
- "!src/**/__snapshots__",
- "!src/**/__fixtures__",
- "CHANGELOG.md",
- "README.md",
- "internal.d.ts"
- ],
- "directories": {
- "doc": "./docs"
- },
- "exports": {
- "./package.json": "./package.json",
- ".": {
- "types": "./dist/index.d.ts",
- "import": "./dist/index.mjs",
- "require": "./dist/index.js"
- },
- "./internal": {
- "types": "./dist/internal/index.d.ts",
- "import": "./dist/internal/index.mjs",
- "module": "./dist/internal/index.mjs",
- "require": "./dist/internal/index.js"
- }
- },
- "dependencies": {
- "@ai-sdk/provider": "3.0.8",
- "@ai-sdk/provider-utils": "4.0.21"
- },
- "devDependencies": {
- "@types/node": "20.17.24",
- "tsup": "^8",
- "typescript": "5.8.3",
- "zod": "3.25.76",
- "@ai-sdk/test-server": "1.0.3",
- "@vercel/ai-tsconfig": "0.0.0"
- },
- "peerDependencies": {
- "zod": "^3.25.76 || ^4.1.8"
- },
- "engines": {
- "node": ">=18"
- },
- "publishConfig": {
- "access": "public"
- },
- "homepage": "https://ai-sdk.dev/docs",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/vercel/ai.git"
- },
- "bugs": {
- "url": "https://github.com/vercel/ai/issues"
- },
- "keywords": [
- "ai"
- ],
- "scripts": {
- "build": "pnpm clean && tsup --tsconfig tsconfig.build.json",
- "build:watch": "pnpm clean && tsup --watch --tsconfig tsconfig.build.json",
- "clean": "del-cli dist docs *.tsbuildinfo",
- "type-check": "tsc --build",
- "test": "pnpm test:node && pnpm test:edge",
- "test:update": "pnpm test:node -u",
- "test:watch": "vitest --config vitest.node.config.js",
- "test:edge": "vitest --config vitest.edge.config.js --run",
- "test:node": "vitest --config vitest.node.config.js --run"
- }
-}
\ No newline at end of file
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-error.ts
deleted file mode 100644
index e44740c2a..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-error.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import {
- createJsonErrorResponseHandler,
- InferSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const anthropicErrorDataSchema = lazySchema(() =>
- zodSchema(
- z.object({
- type: z.literal('error'),
- error: z.object({
- type: z.string(),
- message: z.string(),
- }),
- }),
- ),
-);
-
-export type AnthropicErrorData = InferSchema;
-
-export const anthropicFailedResponseHandler = createJsonErrorResponseHandler({
- errorSchema: anthropicErrorDataSchema,
- errorToMessage: data => data.error.message,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-message-metadata.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-message-metadata.ts
deleted file mode 100644
index d58b08c5c..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-message-metadata.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-import { JSONObject } from '@ai-sdk/provider';
-
-/**
- * Represents a single iteration in the usage breakdown.
- * When compaction occurs, the API returns an iterations array showing
- * usage for each sampling iteration (compaction + message).
- */
-export interface AnthropicUsageIteration {
- type: 'compaction' | 'message';
-
- /**
- * Number of input tokens consumed in this iteration.
- */
- inputTokens: number;
-
- /**
- * Number of output tokens generated in this iteration.
- */
- outputTokens: number;
-}
-
-export interface AnthropicMessageMetadata {
- usage: JSONObject;
- // TODO remove cacheCreationInputTokens in AI SDK 6
- // (use value in usage object instead)
- cacheCreationInputTokens: number | null;
- stopSequence: string | null;
-
- /**
- * Usage breakdown by iteration when compaction is triggered.
- *
- * When compaction occurs, this array contains usage for each sampling iteration.
- * The first iteration is typically the compaction step, followed by the main
- * message iteration.
- */
- iterations: AnthropicUsageIteration[] | null;
-
- /**
- * Information about the container used in this request.
- *
- * This will be non-null if a container tool (e.g., code execution) was used.
- * Information about the container used in the request (for the code execution tool).
- */
- container: {
- /**
- * The time at which the container will expire (RFC3339 timestamp).
- */
- expiresAt: string;
-
- /**
- * Identifier for the container used in this request.
- */
- id: string;
-
- /**
- * Skills loaded in the container.
- */
- skills: Array<{
- /**
- * Type of skill: either 'anthropic' (built-in) or 'custom' (user-defined).
- */
- type: 'anthropic' | 'custom';
-
- /**
- * Skill ID (1-64 characters).
- */
- skillId: string;
-
- /**
- * Skill version or 'latest' for most recent version (1-64 characters).
- */
- version: string;
- }> | null;
- } | null;
-
- /**
- * Context management response.
- *
- * Information about context management strategies applied during the request.
- */
- contextManagement: {
- /**
- * List of context management edits that were applied.
- * Each item in the array is a specific type of context management edit.
- */
- appliedEdits: Array<
- /**
- * Represents an edit where a certain number of tool uses and input tokens were cleared.
- */
- | {
- /**
- * The type of context management edit applied.
- * Possible value: 'clear_tool_uses_20250919'
- */
- type: 'clear_tool_uses_20250919';
-
- /**
- * Number of tool uses that were cleared by this edit.
- * Minimum: 0
- */
- clearedToolUses: number;
-
- /**
- * Number of input tokens cleared by this edit.
- * Minimum: 0
- */
- clearedInputTokens: number;
- }
- /**
- * Represents an edit where a certain number of thinking turns and input tokens were cleared.
- */
- | {
- /**
- * The type of context management edit applied.
- * Possible value: 'clear_thinking_20251015'
- */
- type: 'clear_thinking_20251015';
-
- /**
- * Number of thinking turns that were cleared by this edit.
- * Minimum: 0
- */
- clearedThinkingTurns: number;
-
- /**
- * Number of input tokens cleared by this edit.
- * Minimum: 0
- */
- clearedInputTokens: number;
- }
- /**
- * Represents a compaction edit where the conversation context was summarized.
- */
- | {
- /**
- * The type of context management edit applied.
- * Possible value: 'compact_20260112'
- */
- type: 'compact_20260112';
- }
- >;
- } | null;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-messages-api.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-messages-api.ts
deleted file mode 100644
index e0e3058f7..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-messages-api.ts
+++ /dev/null
@@ -1,1344 +0,0 @@
-import { JSONSchema7 } from '@ai-sdk/provider';
-import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export type AnthropicMessagesPrompt = {
- system: Array | undefined;
- messages: AnthropicMessage[];
-};
-
-export type AnthropicMessage = AnthropicUserMessage | AnthropicAssistantMessage;
-
-export type AnthropicCacheControl = {
- type: 'ephemeral';
- ttl?: '5m' | '1h';
-};
-
-export interface AnthropicUserMessage {
- role: 'user';
- content: Array<
- | AnthropicTextContent
- | AnthropicImageContent
- | AnthropicDocumentContent
- | AnthropicToolResultContent
- >;
-}
-
-export interface AnthropicAssistantMessage {
- role: 'assistant';
- content: Array<
- | AnthropicTextContent
- | AnthropicThinkingContent
- | AnthropicRedactedThinkingContent
- | AnthropicToolCallContent
- | AnthropicServerToolUseContent
- | AnthropicCodeExecutionToolResultContent
- | AnthropicWebFetchToolResultContent
- | AnthropicWebSearchToolResultContent
- | AnthropicToolSearchToolResultContent
- | AnthropicBashCodeExecutionToolResultContent
- | AnthropicTextEditorCodeExecutionToolResultContent
- | AnthropicMcpToolUseContent
- | AnthropicMcpToolResultContent
- | AnthropicCompactionContent
- >;
-}
-
-export interface AnthropicCompactionContent {
- type: 'compaction';
- content: string;
- cache_control?: AnthropicCacheControl;
-}
-
-export interface AnthropicTextContent {
- type: 'text';
- text: string;
- cache_control: AnthropicCacheControl | undefined;
-}
-
-export interface AnthropicThinkingContent {
- type: 'thinking';
- thinking: string;
- signature: string;
- // Note: thinking blocks cannot be directly cached with cache_control.
- // They are cached implicitly when appearing in previous assistant turns.
- cache_control?: never;
-}
-
-export interface AnthropicRedactedThinkingContent {
- type: 'redacted_thinking';
- data: string;
- // Note: redacted thinking blocks cannot be directly cached with cache_control.
- // They are cached implicitly when appearing in previous assistant turns.
- cache_control?: never;
-}
-
-type AnthropicContentSource =
- | {
- type: 'base64';
- media_type: string;
- data: string;
- }
- | {
- type: 'url';
- url: string;
- }
- | {
- type: 'text';
- media_type: 'text/plain';
- data: string;
- };
-
-export interface AnthropicImageContent {
- type: 'image';
- source: AnthropicContentSource;
- cache_control: AnthropicCacheControl | undefined;
-}
-
-export interface AnthropicDocumentContent {
- type: 'document';
- source: AnthropicContentSource;
- title?: string;
- context?: string;
- citations?: { enabled: boolean };
- cache_control: AnthropicCacheControl | undefined;
-}
-
-/**
- * The caller information for programmatic tool calling.
- * Present when a tool is called from within code execution.
- */
-export type AnthropicToolCallCaller =
- | {
- type: 'code_execution_20250825';
- tool_id: string;
- }
- | {
- type: 'code_execution_20260120';
- tool_id: string;
- }
- | {
- type: 'direct';
- };
-
-export interface AnthropicToolCallContent {
- type: 'tool_use';
- id: string;
- name: string;
- input: unknown;
- /**
- * Present when this tool call was triggered by a server-executed tool
- * (e.g., code execution calling a user-defined tool programmatically).
- */
- caller?: AnthropicToolCallCaller;
- cache_control: AnthropicCacheControl | undefined;
-}
-
-export interface AnthropicServerToolUseContent {
- type: 'server_tool_use';
- id: string;
- name:
- | 'web_fetch'
- | 'web_search'
- // code execution 20250522:
- | 'code_execution'
- // code execution 20250825:
- | 'bash_code_execution'
- | 'text_editor_code_execution'
- // tool search:
- | 'tool_search_tool_regex'
- | 'tool_search_tool_bm25';
- input: unknown;
- cache_control: AnthropicCacheControl | undefined;
-}
-
-// Nested content types for tool results (without cache_control)
-// Sub-content blocks cannot be cached directly according to Anthropic docs
-type AnthropicNestedTextContent = Omit<
- AnthropicTextContent,
- 'cache_control'
-> & {
- cache_control?: never;
-};
-
-type AnthropicNestedImageContent = Omit<
- AnthropicImageContent,
- 'cache_control'
-> & {
- cache_control?: never;
-};
-
-type AnthropicNestedDocumentContent = Omit<
- AnthropicDocumentContent,
- 'cache_control'
-> & {
- cache_control?: never;
-};
-
-export interface AnthropicToolReferenceContent {
- type: 'tool_reference';
- tool_name: string;
-}
-
-export interface AnthropicToolResultContent {
- type: 'tool_result';
- tool_use_id: string;
- content:
- | string
- | Array<
- | AnthropicNestedTextContent
- | AnthropicNestedImageContent
- | AnthropicNestedDocumentContent
- | AnthropicToolReferenceContent
- >;
- is_error: boolean | undefined;
- cache_control: AnthropicCacheControl | undefined;
-}
-
-export interface AnthropicWebSearchToolResultContent {
- type: 'web_search_tool_result';
- tool_use_id: string;
- content: Array<{
- url: string;
- title: string | null;
- page_age: string | null;
- encrypted_content: string;
- type: string;
- }>;
- cache_control: AnthropicCacheControl | undefined;
-}
-
-export interface AnthropicToolSearchToolResultContent {
- type: 'tool_search_tool_result';
- tool_use_id: string;
- content:
- | {
- type: 'tool_search_tool_search_result';
- tool_references: Array<{
- type: 'tool_reference';
- tool_name: string;
- }>;
- }
- | {
- type: 'tool_search_tool_result_error';
- error_code: string;
- };
- cache_control: AnthropicCacheControl | undefined;
-}
-
-// code execution results for code_execution_20250522 tool:
-export interface AnthropicCodeExecutionToolResultContent {
- type: 'code_execution_tool_result';
- tool_use_id: string;
- content:
- | {
- type: 'code_execution_result';
- stdout: string;
- stderr: string;
- return_code: number;
- content: Array<{ type: 'code_execution_output'; file_id: string }>;
- }
- | {
- type: 'encrypted_code_execution_result';
- encrypted_stdout: string;
- stderr: string;
- return_code: number;
- content: Array<{ type: 'code_execution_output'; file_id: string }>;
- }
- | {
- type: 'code_execution_tool_result_error';
- error_code: string;
- };
- cache_control: AnthropicCacheControl | undefined;
-}
-
-// text editor code execution results for code_execution_20250825 tool:
-export interface AnthropicTextEditorCodeExecutionToolResultContent {
- type: 'text_editor_code_execution_tool_result';
- tool_use_id: string;
- content:
- | {
- type: 'text_editor_code_execution_tool_result_error';
- error_code: string;
- }
- | {
- type: 'text_editor_code_execution_create_result';
- is_file_update: boolean;
- }
- | {
- type: 'text_editor_code_execution_view_result';
- content: string;
- file_type: string;
- num_lines: number | null;
- start_line: number | null;
- total_lines: number | null;
- }
- | {
- type: 'text_editor_code_execution_str_replace_result';
- lines: string[] | null;
- new_lines: number | null;
- new_start: number | null;
- old_lines: number | null;
- old_start: number | null;
- };
- cache_control: AnthropicCacheControl | undefined;
-}
-
-// bash code execution results for code_execution_20250825 tool:
-export interface AnthropicBashCodeExecutionToolResultContent {
- type: 'bash_code_execution_tool_result';
- tool_use_id: string;
- content:
- | {
- type: 'bash_code_execution_result';
- stdout: string;
- stderr: string;
- return_code: number;
- content: {
- type: 'bash_code_execution_output';
- file_id: string;
- }[];
- }
- | {
- type: 'bash_code_execution_tool_result_error';
- error_code: string;
- };
- cache_control: AnthropicCacheControl | undefined;
-}
-
-export interface AnthropicWebFetchToolResultContent {
- type: 'web_fetch_tool_result';
- tool_use_id: string;
- content:
- | {
- type: 'web_fetch_result';
- url: string;
- retrieved_at: string | null;
- content: {
- type: 'document';
- title: string | null;
- citations?: { enabled: boolean };
- source:
- | { type: 'base64'; media_type: 'application/pdf'; data: string }
- | { type: 'text'; media_type: 'text/plain'; data: string };
- };
- }
- | {
- type: 'web_fetch_tool_result_error';
- error_code: string;
- };
- cache_control: AnthropicCacheControl | undefined;
-}
-export interface AnthropicMcpToolUseContent {
- type: 'mcp_tool_use';
- id: string;
- name: string;
- server_name: string;
- input: unknown;
- cache_control: AnthropicCacheControl | undefined;
-}
-
-export interface AnthropicMcpToolResultContent {
- type: 'mcp_tool_result';
- tool_use_id: string;
- is_error: boolean;
- content: string | Array<{ type: 'text'; text: string }>;
- cache_control: AnthropicCacheControl | undefined;
-}
-
-export type AnthropicTool =
- | {
- name: string;
- description: string | undefined;
- input_schema: JSONSchema7;
- cache_control: AnthropicCacheControl | undefined;
- eager_input_streaming?: boolean;
- strict?: boolean;
- /**
- * When true, this tool is deferred and will only be loaded when
- * discovered via the tool search tool.
- */
- defer_loading?: boolean;
- /**
- * Programmatic tool calling: specifies which server-executed tools
- * are allowed to call this tool. When set, only the specified callers
- * can invoke this tool programmatically.
- *
- * @example ['code_execution_20250825']
- */
- allowed_callers?: Array<
- 'direct' | 'code_execution_20250825' | 'code_execution_20260120'
- >;
- }
- | {
- type: 'code_execution_20250522';
- name: string;
- cache_control: AnthropicCacheControl | undefined;
- }
- | {
- type: 'code_execution_20250825';
- name: string;
- }
- | {
- type: 'code_execution_20260120';
- name: string;
- }
- | {
- name: string;
- type: 'computer_20250124' | 'computer_20241022';
- display_width_px: number;
- display_height_px: number;
- display_number: number;
- cache_control: AnthropicCacheControl | undefined;
- }
- | {
- name: string;
- type: 'computer_20251124';
- display_width_px: number;
- display_height_px: number;
- display_number: number;
- enable_zoom?: boolean;
- cache_control: AnthropicCacheControl | undefined;
- }
- | {
- name: string;
- type:
- | 'text_editor_20250124'
- | 'text_editor_20241022'
- | 'text_editor_20250429';
- cache_control: AnthropicCacheControl | undefined;
- }
- | {
- name: string;
- type: 'text_editor_20250728';
- max_characters?: number;
- cache_control: AnthropicCacheControl | undefined;
- }
- | {
- name: string;
- type: 'bash_20250124' | 'bash_20241022';
- cache_control: AnthropicCacheControl | undefined;
- }
- | {
- name: string;
- type: 'memory_20250818';
- }
- | {
- type: 'web_fetch_20250910' | 'web_fetch_20260209';
- name: string;
- max_uses?: number;
- allowed_domains?: string[];
- blocked_domains?: string[];
- citations?: { enabled: boolean };
- max_content_tokens?: number;
- cache_control: AnthropicCacheControl | undefined;
- }
- | {
- type: 'web_search_20250305' | 'web_search_20260209';
- name: string;
- max_uses?: number;
- allowed_domains?: string[];
- blocked_domains?: string[];
- user_location?: {
- type: 'approximate';
- city?: string;
- region?: string;
- country?: string;
- timezone?: string;
- };
- cache_control: AnthropicCacheControl | undefined;
- }
- | {
- type: 'tool_search_tool_regex_20251119';
- name: string;
- }
- | {
- type: 'tool_search_tool_bm25_20251119';
- name: string;
- };
-
-export type AnthropicSpeed = 'fast' | 'standard';
-
-export type AnthropicToolChoice =
- | { type: 'auto' | 'any'; disable_parallel_tool_use?: boolean }
- | { type: 'tool'; name: string; disable_parallel_tool_use?: boolean };
-
-export type AnthropicContainer = {
- id?: string | null;
- skills?: Array<{
- type: 'anthropic' | 'custom';
- skill_id: string;
- version?: string;
- }> | null;
-};
-
-export type AnthropicInputTokensTrigger = {
- type: 'input_tokens';
- value: number;
-};
-
-export type AnthropicToolUsesTrigger = {
- type: 'tool_uses';
- value: number;
-};
-
-export type AnthropicContextManagementTrigger =
- | AnthropicInputTokensTrigger
- | AnthropicToolUsesTrigger;
-
-export type AnthropicClearToolUsesEdit = {
- type: 'clear_tool_uses_20250919';
- trigger?: AnthropicContextManagementTrigger;
- keep?: {
- type: 'tool_uses';
- value: number;
- };
- clear_at_least?: {
- type: 'input_tokens';
- value: number;
- };
- clear_tool_inputs?: boolean;
- exclude_tools?: string[];
-};
-
-export type AnthropicClearThinkingBlockEdit = {
- type: 'clear_thinking_20251015';
- keep?: 'all' | { type: 'thinking_turns'; value: number };
-};
-
-export type AnthropicCompactEdit = {
- type: 'compact_20260112';
- trigger?: AnthropicInputTokensTrigger;
- pause_after_compaction?: boolean;
- instructions?: string;
-};
-
-export type AnthropicContextManagementEdit =
- | AnthropicClearToolUsesEdit
- | AnthropicClearThinkingBlockEdit
- | AnthropicCompactEdit;
-
-export type AnthropicContextManagementConfig = {
- edits: AnthropicContextManagementEdit[];
-};
-
-export type AnthropicResponseClearToolUsesEdit = {
- type: 'clear_tool_uses_20250919';
- cleared_tool_uses: number;
- cleared_input_tokens: number;
-};
-
-export type AnthropicResponseClearThinkingBlockEdit = {
- type: 'clear_thinking_20251015';
- cleared_thinking_turns: number;
- cleared_input_tokens: number;
-};
-
-export type AnthropicResponseCompactEdit = {
- type: 'compact_20260112';
-};
-
-export type AnthropicResponseContextManagementEdit =
- | AnthropicResponseClearToolUsesEdit
- | AnthropicResponseClearThinkingBlockEdit
- | AnthropicResponseCompactEdit;
-
-export type AnthropicResponseContextManagement = {
- applied_edits: AnthropicResponseContextManagementEdit[];
-};
-
-// limited version of the schema, focussed on what is needed for the implementation
-// this approach limits breakages when the API changes and increases efficiency
-export const anthropicMessagesResponseSchema = lazySchema(() =>
- zodSchema(
- z.object({
- type: z.literal('message'),
- id: z.string().nullish(),
- model: z.string().nullish(),
- content: z.array(
- z.discriminatedUnion('type', [
- z.object({
- type: z.literal('text'),
- text: z.string(),
- citations: z
- .array(
- z.discriminatedUnion('type', [
- z.object({
- type: z.literal('web_search_result_location'),
- cited_text: z.string(),
- url: z.string(),
- title: z.string(),
- encrypted_index: z.string(),
- }),
- z.object({
- type: z.literal('page_location'),
- cited_text: z.string(),
- document_index: z.number(),
- document_title: z.string().nullable(),
- start_page_number: z.number(),
- end_page_number: z.number(),
- }),
- z.object({
- type: z.literal('char_location'),
- cited_text: z.string(),
- document_index: z.number(),
- document_title: z.string().nullable(),
- start_char_index: z.number(),
- end_char_index: z.number(),
- }),
- ]),
- )
- .optional(),
- }),
- z.object({
- type: z.literal('thinking'),
- thinking: z.string(),
- signature: z.string(),
- }),
- z.object({
- type: z.literal('redacted_thinking'),
- data: z.string(),
- }),
- z.object({
- type: z.literal('compaction'),
- content: z.string(),
- }),
- z.object({
- type: z.literal('tool_use'),
- id: z.string(),
- name: z.string(),
- input: z.unknown(),
- // Programmatic tool calling: caller info when triggered from code execution
- caller: z
- .union([
- z.object({
- type: z.literal('code_execution_20250825'),
- tool_id: z.string(),
- }),
- z.object({
- type: z.literal('code_execution_20260120'),
- tool_id: z.string(),
- }),
- z.object({
- type: z.literal('direct'),
- }),
- ])
- .optional(),
- }),
- z.object({
- type: z.literal('server_tool_use'),
- id: z.string(),
- name: z.string(),
- input: z.record(z.string(), z.unknown()).nullish(),
- caller: z
- .union([
- z.object({
- type: z.literal('code_execution_20260120'),
- tool_id: z.string(),
- }),
- z.object({
- type: z.literal('direct'),
- }),
- ])
- .optional(),
- }),
- z.object({
- type: z.literal('mcp_tool_use'),
- id: z.string(),
- name: z.string(),
- input: z.unknown(),
- server_name: z.string(),
- }),
- z.object({
- type: z.literal('mcp_tool_result'),
- tool_use_id: z.string(),
- is_error: z.boolean(),
- content: z.array(
- z.union([
- z.string(),
- z.object({ type: z.literal('text'), text: z.string() }),
- ]),
- ),
- }),
- z.object({
- type: z.literal('web_fetch_tool_result'),
- tool_use_id: z.string(),
- content: z.union([
- z.object({
- type: z.literal('web_fetch_result'),
- url: z.string(),
- retrieved_at: z.string(),
- content: z.object({
- type: z.literal('document'),
- title: z.string().nullable(),
- citations: z.object({ enabled: z.boolean() }).optional(),
- source: z.union([
- z.object({
- type: z.literal('base64'),
- media_type: z.literal('application/pdf'),
- data: z.string(),
- }),
- z.object({
- type: z.literal('text'),
- media_type: z.literal('text/plain'),
- data: z.string(),
- }),
- ]),
- }),
- }),
- z.object({
- type: z.literal('web_fetch_tool_result_error'),
- error_code: z.string(),
- }),
- ]),
- }),
- z.object({
- type: z.literal('web_search_tool_result'),
- tool_use_id: z.string(),
- content: z.union([
- z.array(
- z.object({
- type: z.literal('web_search_result'),
- url: z.string(),
- title: z.string(),
- encrypted_content: z.string(),
- page_age: z.string().nullish(),
- }),
- ),
- z.object({
- type: z.literal('web_search_tool_result_error'),
- error_code: z.string(),
- }),
- ]),
- }),
- // code execution results for code_execution_20250522 tool:
- z.object({
- type: z.literal('code_execution_tool_result'),
- tool_use_id: z.string(),
- content: z.union([
- z.object({
- type: z.literal('code_execution_result'),
- stdout: z.string(),
- stderr: z.string(),
- return_code: z.number(),
- content: z
- .array(
- z.object({
- type: z.literal('code_execution_output'),
- file_id: z.string(),
- }),
- )
- .optional()
- .default([]),
- }),
- z.object({
- type: z.literal('encrypted_code_execution_result'),
- encrypted_stdout: z.string(),
- stderr: z.string(),
- return_code: z.number(),
- content: z
- .array(
- z.object({
- type: z.literal('code_execution_output'),
- file_id: z.string(),
- }),
- )
- .optional()
- .default([]),
- }),
- z.object({
- type: z.literal('code_execution_tool_result_error'),
- error_code: z.string(),
- }),
- ]),
- }),
- // bash code execution results for code_execution_20250825 tool:
- z.object({
- type: z.literal('bash_code_execution_tool_result'),
- tool_use_id: z.string(),
- content: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('bash_code_execution_result'),
- content: z.array(
- z.object({
- type: z.literal('bash_code_execution_output'),
- file_id: z.string(),
- }),
- ),
- stdout: z.string(),
- stderr: z.string(),
- return_code: z.number(),
- }),
- z.object({
- type: z.literal('bash_code_execution_tool_result_error'),
- error_code: z.string(),
- }),
- ]),
- }),
- // text editor code execution results for code_execution_20250825 tool:
- z.object({
- type: z.literal('text_editor_code_execution_tool_result'),
- tool_use_id: z.string(),
- content: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('text_editor_code_execution_tool_result_error'),
- error_code: z.string(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution_view_result'),
- content: z.string(),
- file_type: z.string(),
- num_lines: z.number().nullable(),
- start_line: z.number().nullable(),
- total_lines: z.number().nullable(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution_create_result'),
- is_file_update: z.boolean(),
- }),
- z.object({
- type: z.literal(
- 'text_editor_code_execution_str_replace_result',
- ),
- lines: z.array(z.string()).nullable(),
- new_lines: z.number().nullable(),
- new_start: z.number().nullable(),
- old_lines: z.number().nullable(),
- old_start: z.number().nullable(),
- }),
- ]),
- }),
- // tool search tool results for tool_search_tool_regex_20251119 and tool_search_tool_bm25_20251119:
- z.object({
- type: z.literal('tool_search_tool_result'),
- tool_use_id: z.string(),
- content: z.union([
- z.object({
- type: z.literal('tool_search_tool_search_result'),
- tool_references: z.array(
- z.object({
- type: z.literal('tool_reference'),
- tool_name: z.string(),
- }),
- ),
- }),
- z.object({
- type: z.literal('tool_search_tool_result_error'),
- error_code: z.string(),
- }),
- ]),
- }),
- ]),
- ),
- stop_reason: z.string().nullish(),
- stop_sequence: z.string().nullish(),
- usage: z.looseObject({
- input_tokens: z.number(),
- output_tokens: z.number(),
- cache_creation_input_tokens: z.number().nullish(),
- cache_read_input_tokens: z.number().nullish(),
- iterations: z
- .array(
- z.object({
- type: z.union([z.literal('compaction'), z.literal('message')]),
- input_tokens: z.number(),
- output_tokens: z.number(),
- }),
- )
- .nullish(),
- }),
- container: z
- .object({
- expires_at: z.string(),
- id: z.string(),
- skills: z
- .array(
- z.object({
- type: z.union([z.literal('anthropic'), z.literal('custom')]),
- skill_id: z.string(),
- version: z.string(),
- }),
- )
- .nullish(),
- })
- .nullish(),
- context_management: z
- .object({
- applied_edits: z.array(
- z.union([
- z.object({
- type: z.literal('clear_tool_uses_20250919'),
- cleared_tool_uses: z.number(),
- cleared_input_tokens: z.number(),
- }),
- z.object({
- type: z.literal('clear_thinking_20251015'),
- cleared_thinking_turns: z.number(),
- cleared_input_tokens: z.number(),
- }),
- z.object({
- type: z.literal('compact_20260112'),
- }),
- ]),
- ),
- })
- .nullish(),
- }),
- ),
-);
-
-// limited version of the schema, focused on what is needed for the implementation
-// this approach limits breakages when the API changes and increases efficiency
-export const anthropicMessagesChunkSchema = lazySchema(() =>
- zodSchema(
- z.discriminatedUnion('type', [
- z.object({
- type: z.literal('message_start'),
- message: z.object({
- id: z.string().nullish(),
- model: z.string().nullish(),
- role: z.string().nullish(),
- usage: z.looseObject({
- input_tokens: z.number(),
- cache_creation_input_tokens: z.number().nullish(),
- cache_read_input_tokens: z.number().nullish(),
- }),
- // Programmatic tool calling: content may be pre-populated for deferred tool calls
- content: z
- .array(
- z.discriminatedUnion('type', [
- z.object({
- type: z.literal('tool_use'),
- id: z.string(),
- name: z.string(),
- input: z.unknown(),
- caller: z
- .union([
- z.object({
- type: z.literal('code_execution_20250825'),
- tool_id: z.string(),
- }),
- z.object({
- type: z.literal('code_execution_20260120'),
- tool_id: z.string(),
- }),
- z.object({
- type: z.literal('direct'),
- }),
- ])
- .optional(),
- }),
- ]),
- )
- .nullish(),
- stop_reason: z.string().nullish(),
- container: z
- .object({
- expires_at: z.string(),
- id: z.string(),
- })
- .nullish(),
- }),
- }),
- z.object({
- type: z.literal('content_block_start'),
- index: z.number(),
- content_block: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('text'),
- text: z.string(),
- }),
- z.object({
- type: z.literal('thinking'),
- thinking: z.string(),
- }),
- z.object({
- type: z.literal('tool_use'),
- id: z.string(),
- name: z.string(),
- // Programmatic tool calling: input may be present directly for deferred tool calls
- input: z.record(z.string(), z.unknown()).optional(),
- // Programmatic tool calling: caller info when triggered from code execution
- caller: z
- .union([
- z.object({
- type: z.literal('code_execution_20250825'),
- tool_id: z.string(),
- }),
- z.object({
- type: z.literal('code_execution_20260120'),
- tool_id: z.string(),
- }),
- z.object({
- type: z.literal('direct'),
- }),
- ])
- .optional(),
- }),
- z.object({
- type: z.literal('redacted_thinking'),
- data: z.string(),
- }),
- z.object({
- type: z.literal('compaction'),
- content: z.string().nullish(),
- }),
- z.object({
- type: z.literal('server_tool_use'),
- id: z.string(),
- name: z.string(),
- input: z.record(z.string(), z.unknown()).nullish(),
- caller: z
- .union([
- z.object({
- type: z.literal('code_execution_20260120'),
- tool_id: z.string(),
- }),
- z.object({
- type: z.literal('direct'),
- }),
- ])
- .optional(),
- }),
- z.object({
- type: z.literal('mcp_tool_use'),
- id: z.string(),
- name: z.string(),
- input: z.unknown(),
- server_name: z.string(),
- }),
- z.object({
- type: z.literal('mcp_tool_result'),
- tool_use_id: z.string(),
- is_error: z.boolean(),
- content: z.array(
- z.union([
- z.string(),
- z.object({ type: z.literal('text'), text: z.string() }),
- ]),
- ),
- }),
- z.object({
- type: z.literal('web_fetch_tool_result'),
- tool_use_id: z.string(),
- content: z.union([
- z.object({
- type: z.literal('web_fetch_result'),
- url: z.string(),
- retrieved_at: z.string(),
- content: z.object({
- type: z.literal('document'),
- title: z.string().nullable(),
- citations: z.object({ enabled: z.boolean() }).optional(),
- source: z.union([
- z.object({
- type: z.literal('base64'),
- media_type: z.literal('application/pdf'),
- data: z.string(),
- }),
- z.object({
- type: z.literal('text'),
- media_type: z.literal('text/plain'),
- data: z.string(),
- }),
- ]),
- }),
- }),
- z.object({
- type: z.literal('web_fetch_tool_result_error'),
- error_code: z.string(),
- }),
- ]),
- }),
- z.object({
- type: z.literal('web_search_tool_result'),
- tool_use_id: z.string(),
- content: z.union([
- z.array(
- z.object({
- type: z.literal('web_search_result'),
- url: z.string(),
- title: z.string(),
- encrypted_content: z.string(),
- page_age: z.string().nullish(),
- }),
- ),
- z.object({
- type: z.literal('web_search_tool_result_error'),
- error_code: z.string(),
- }),
- ]),
- }),
- // code execution results for code_execution_20250522 tool:
- z.object({
- type: z.literal('code_execution_tool_result'),
- tool_use_id: z.string(),
- content: z.union([
- z.object({
- type: z.literal('code_execution_result'),
- stdout: z.string(),
- stderr: z.string(),
- return_code: z.number(),
- content: z
- .array(
- z.object({
- type: z.literal('code_execution_output'),
- file_id: z.string(),
- }),
- )
- .optional()
- .default([]),
- }),
- z.object({
- type: z.literal('encrypted_code_execution_result'),
- encrypted_stdout: z.string(),
- stderr: z.string(),
- return_code: z.number(),
- content: z
- .array(
- z.object({
- type: z.literal('code_execution_output'),
- file_id: z.string(),
- }),
- )
- .optional()
- .default([]),
- }),
- z.object({
- type: z.literal('code_execution_tool_result_error'),
- error_code: z.string(),
- }),
- ]),
- }),
- // bash code execution results for code_execution_20250825 tool:
- z.object({
- type: z.literal('bash_code_execution_tool_result'),
- tool_use_id: z.string(),
- content: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('bash_code_execution_result'),
- content: z.array(
- z.object({
- type: z.literal('bash_code_execution_output'),
- file_id: z.string(),
- }),
- ),
- stdout: z.string(),
- stderr: z.string(),
- return_code: z.number(),
- }),
- z.object({
- type: z.literal('bash_code_execution_tool_result_error'),
- error_code: z.string(),
- }),
- ]),
- }),
- // text editor code execution results for code_execution_20250825 tool:
- z.object({
- type: z.literal('text_editor_code_execution_tool_result'),
- tool_use_id: z.string(),
- content: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('text_editor_code_execution_tool_result_error'),
- error_code: z.string(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution_view_result'),
- content: z.string(),
- file_type: z.string(),
- num_lines: z.number().nullable(),
- start_line: z.number().nullable(),
- total_lines: z.number().nullable(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution_create_result'),
- is_file_update: z.boolean(),
- }),
- z.object({
- type: z.literal(
- 'text_editor_code_execution_str_replace_result',
- ),
- lines: z.array(z.string()).nullable(),
- new_lines: z.number().nullable(),
- new_start: z.number().nullable(),
- old_lines: z.number().nullable(),
- old_start: z.number().nullable(),
- }),
- ]),
- }),
- // tool search tool results for tool_search_tool_regex_20251119 and tool_search_tool_bm25_20251119:
- z.object({
- type: z.literal('tool_search_tool_result'),
- tool_use_id: z.string(),
- content: z.union([
- z.object({
- type: z.literal('tool_search_tool_search_result'),
- tool_references: z.array(
- z.object({
- type: z.literal('tool_reference'),
- tool_name: z.string(),
- }),
- ),
- }),
- z.object({
- type: z.literal('tool_search_tool_result_error'),
- error_code: z.string(),
- }),
- ]),
- }),
- ]),
- }),
- z.object({
- type: z.literal('content_block_delta'),
- index: z.number(),
- delta: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('input_json_delta'),
- partial_json: z.string(),
- }),
- z.object({
- type: z.literal('text_delta'),
- text: z.string(),
- }),
- z.object({
- type: z.literal('thinking_delta'),
- thinking: z.string(),
- }),
- z.object({
- type: z.literal('signature_delta'),
- signature: z.string(),
- }),
- z.object({
- type: z.literal('compaction_delta'),
- content: z.string().nullish(),
- }),
- z.object({
- type: z.literal('citations_delta'),
- citation: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('web_search_result_location'),
- cited_text: z.string(),
- url: z.string(),
- title: z.string(),
- encrypted_index: z.string(),
- }),
- z.object({
- type: z.literal('page_location'),
- cited_text: z.string(),
- document_index: z.number(),
- document_title: z.string().nullable(),
- start_page_number: z.number(),
- end_page_number: z.number(),
- }),
- z.object({
- type: z.literal('char_location'),
- cited_text: z.string(),
- document_index: z.number(),
- document_title: z.string().nullable(),
- start_char_index: z.number(),
- end_char_index: z.number(),
- }),
- ]),
- }),
- ]),
- }),
- z.object({
- type: z.literal('content_block_stop'),
- index: z.number(),
- }),
- z.object({
- type: z.literal('error'),
- error: z.object({
- type: z.string(),
- message: z.string(),
- }),
- }),
- z.object({
- type: z.literal('message_delta'),
- delta: z.object({
- stop_reason: z.string().nullish(),
- stop_sequence: z.string().nullish(),
- container: z
- .object({
- expires_at: z.string(),
- id: z.string(),
- skills: z
- .array(
- z.object({
- type: z.union([
- z.literal('anthropic'),
- z.literal('custom'),
- ]),
- skill_id: z.string(),
- version: z.string(),
- }),
- )
- .nullish(),
- })
- .nullish(),
- }),
- usage: z.looseObject({
- input_tokens: z.number().nullish(),
- output_tokens: z.number(),
- cache_creation_input_tokens: z.number().nullish(),
- cache_read_input_tokens: z.number().nullish(),
- iterations: z
- .array(
- z.object({
- type: z.union([z.literal('compaction'), z.literal('message')]),
- input_tokens: z.number(),
- output_tokens: z.number(),
- }),
- )
- .nullish(),
- }),
- context_management: z
- .object({
- applied_edits: z.array(
- z.union([
- z.object({
- type: z.literal('clear_tool_uses_20250919'),
- cleared_tool_uses: z.number(),
- cleared_input_tokens: z.number(),
- }),
- z.object({
- type: z.literal('clear_thinking_20251015'),
- cleared_thinking_turns: z.number(),
- cleared_input_tokens: z.number(),
- }),
- z.object({
- type: z.literal('compact_20260112'),
- }),
- ]),
- ),
- })
- .nullish(),
- }),
- z.object({
- type: z.literal('message_stop'),
- }),
- z.object({
- type: z.literal('ping'),
- }),
- ]),
- ),
-);
-
-export const anthropicReasoningMetadataSchema = lazySchema(() =>
- zodSchema(
- z.object({
- signature: z.string().optional(),
- redactedData: z.string().optional(),
- }),
- ),
-);
-
-export type AnthropicReasoningMetadata = InferSchema<
- typeof anthropicReasoningMetadataSchema
->;
-
-export type Citation = NonNullable<
- (InferSchema['content'][number] & {
- type: 'text';
- })['citations']
->[number];
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-messages-language-model.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-messages-language-model.ts
deleted file mode 100644
index 5a736b0ac..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-messages-language-model.ts
+++ /dev/null
@@ -1,2392 +0,0 @@
-import {
- APICallError,
- JSONObject,
- LanguageModelV3,
- LanguageModelV3CallOptions,
- LanguageModelV3Content,
- LanguageModelV3FinishReason,
- LanguageModelV3FunctionTool,
- LanguageModelV3GenerateResult,
- LanguageModelV3Prompt,
- LanguageModelV3Source,
- LanguageModelV3StreamPart,
- LanguageModelV3StreamResult,
- LanguageModelV3ToolCall,
- SharedV3ProviderMetadata,
- SharedV3Warning,
-} from '@ai-sdk/provider';
-import {
- combineHeaders,
- createEventSourceResponseHandler,
- createJsonResponseHandler,
- createToolNameMapping,
- FetchFunction,
- generateId,
- InferSchema,
- parseProviderOptions,
- ParseResult,
- postJsonToApi,
- Resolvable,
- resolve,
-} from '@ai-sdk/provider-utils';
-import { anthropicFailedResponseHandler } from './anthropic-error';
-import { AnthropicMessageMetadata } from './anthropic-message-metadata';
-import {
- AnthropicContainer,
- anthropicMessagesChunkSchema,
- anthropicMessagesResponseSchema,
- AnthropicReasoningMetadata,
- AnthropicResponseContextManagement,
- AnthropicTool,
- Citation,
-} from './anthropic-messages-api';
-import {
- AnthropicMessagesModelId,
- anthropicLanguageModelOptions,
-} from './anthropic-messages-options';
-import { prepareTools } from './anthropic-prepare-tools';
-import {
- AnthropicMessagesUsage,
- convertAnthropicMessagesUsage,
-} from './convert-anthropic-messages-usage';
-import { convertToAnthropicMessagesPrompt } from './convert-to-anthropic-messages-prompt';
-import { CacheControlValidator } from './get-cache-control';
-import { mapAnthropicStopReason } from './map-anthropic-stop-reason';
-
-function createCitationSource(
- citation: Citation,
- citationDocuments: Array<{
- title: string;
- filename?: string;
- mediaType: string;
- }>,
- generateId: () => string,
-): LanguageModelV3Source | undefined {
- if (citation.type === 'web_search_result_location') {
- return {
- type: 'source' as const,
- sourceType: 'url' as const,
- id: generateId(),
- url: citation.url,
- title: citation.title,
- providerMetadata: {
- anthropic: {
- citedText: citation.cited_text,
- encryptedIndex: citation.encrypted_index,
- },
- } satisfies SharedV3ProviderMetadata,
- };
- }
-
- if (citation.type !== 'page_location' && citation.type !== 'char_location') {
- return;
- }
-
- const documentInfo = citationDocuments[citation.document_index];
-
- if (!documentInfo) {
- return;
- }
-
- return {
- type: 'source' as const,
- sourceType: 'document' as const,
- id: generateId(),
- mediaType: documentInfo.mediaType,
- title: citation.document_title ?? documentInfo.title,
- filename: documentInfo.filename,
- providerMetadata: {
- anthropic:
- citation.type === 'page_location'
- ? {
- citedText: citation.cited_text,
- startPageNumber: citation.start_page_number,
- endPageNumber: citation.end_page_number,
- }
- : {
- citedText: citation.cited_text,
- startCharIndex: citation.start_char_index,
- endCharIndex: citation.end_char_index,
- },
- } satisfies SharedV3ProviderMetadata,
- };
-}
-
-type AnthropicMessagesConfig = {
- provider: string;
- baseURL: string;
- headers: Resolvable>;
- fetch?: FetchFunction;
- buildRequestUrl?: (baseURL: string, isStreaming: boolean) => string;
- transformRequestBody?: (
- args: Record,
- betas: Set,
- ) => Record;
- supportedUrls?: () => LanguageModelV3['supportedUrls'];
- generateId?: () => string;
-
- /**
- * When false, the model will use JSON tool fallback for structured outputs.
- */
- supportsNativeStructuredOutput?: boolean;
-
- /**
- * When false, `strict` on tool definitions will be ignored and a warning emitted.
- * Defaults to true.
- */
- supportsStrictTools?: boolean;
-};
-
-export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
- readonly specificationVersion = 'v3';
-
- readonly modelId: AnthropicMessagesModelId;
-
- private readonly config: AnthropicMessagesConfig;
- private readonly generateId: () => string;
-
- constructor(
- modelId: AnthropicMessagesModelId,
- config: AnthropicMessagesConfig,
- ) {
- this.modelId = modelId;
- this.config = config;
- this.generateId = config.generateId ?? generateId;
- }
-
- supportsUrl(url: URL): boolean {
- return url.protocol === 'https:';
- }
-
- get provider(): string {
- return this.config.provider;
- }
-
- /**
- * Extracts the dynamic provider name from the config.provider string.
- * e.g., 'my-custom-anthropic.messages' -> 'my-custom-anthropic'
- */
- private get providerOptionsName(): string {
- const provider = this.config.provider;
- const dotIndex = provider.indexOf('.');
- return dotIndex === -1 ? provider : provider.substring(0, dotIndex);
- }
-
- get supportedUrls() {
- return this.config.supportedUrls?.() ?? {};
- }
-
- private async getArgs({
- userSuppliedBetas,
- prompt,
- maxOutputTokens,
- temperature,
- topP,
- topK,
- frequencyPenalty,
- presencePenalty,
- stopSequences,
- responseFormat,
- seed,
- tools,
- toolChoice,
- providerOptions,
- stream,
- }: LanguageModelV3CallOptions & {
- stream: boolean;
- userSuppliedBetas: Set;
- }) {
- const warnings: SharedV3Warning[] = [];
-
- if (frequencyPenalty != null) {
- warnings.push({ type: 'unsupported', feature: 'frequencyPenalty' });
- }
-
- if (presencePenalty != null) {
- warnings.push({ type: 'unsupported', feature: 'presencePenalty' });
- }
-
- if (seed != null) {
- warnings.push({ type: 'unsupported', feature: 'seed' });
- }
-
- if (temperature != null && temperature > 1) {
- warnings.push({
- type: 'unsupported',
- feature: 'temperature',
- details: `${temperature} exceeds anthropic maximum of 1.0. clamped to 1.0`,
- });
- temperature = 1;
- } else if (temperature != null && temperature < 0) {
- warnings.push({
- type: 'unsupported',
- feature: 'temperature',
- details: `${temperature} is below anthropic minimum of 0. clamped to 0`,
- });
- temperature = 0;
- }
-
- if (responseFormat?.type === 'json') {
- if (responseFormat.schema == null) {
- warnings.push({
- type: 'unsupported',
- feature: 'responseFormat',
- details:
- 'JSON response format requires a schema. ' +
- 'The response format is ignored.',
- });
- }
- }
-
- const providerOptionsName = this.providerOptionsName;
-
- // Parse provider options from both canonical 'anthropic' key and custom key
- const canonicalOptions = await parseProviderOptions({
- provider: 'anthropic',
- providerOptions,
- schema: anthropicLanguageModelOptions,
- });
-
- const customProviderOptions =
- providerOptionsName !== 'anthropic'
- ? await parseProviderOptions({
- provider: providerOptionsName,
- providerOptions,
- schema: anthropicLanguageModelOptions,
- })
- : null;
-
- // Track if custom key was explicitly used
- const usedCustomProviderKey = customProviderOptions != null;
-
- // Merge options
- const anthropicOptions = Object.assign(
- {},
- canonicalOptions ?? {},
- customProviderOptions ?? {},
- );
-
- const {
- maxOutputTokens: maxOutputTokensForModel,
- supportsStructuredOutput: modelSupportsStructuredOutput,
- isKnownModel,
- } = getModelCapabilities(this.modelId);
-
- const supportsStructuredOutput =
- (this.config.supportsNativeStructuredOutput ?? true) &&
- modelSupportsStructuredOutput;
-
- const supportsStrictTools =
- (this.config.supportsStrictTools ?? true) &&
- modelSupportsStructuredOutput;
-
- const structureOutputMode =
- anthropicOptions?.structuredOutputMode ?? 'auto';
- const useStructuredOutput =
- structureOutputMode === 'outputFormat' ||
- (structureOutputMode === 'auto' && supportsStructuredOutput);
-
- const jsonResponseTool: LanguageModelV3FunctionTool | undefined =
- responseFormat?.type === 'json' &&
- responseFormat.schema != null &&
- !useStructuredOutput
- ? {
- type: 'function',
- name: 'json',
- description: 'Respond with a JSON object.',
- inputSchema: responseFormat.schema,
- }
- : undefined;
-
- const contextManagement = anthropicOptions?.contextManagement;
-
- // Create a shared cache control validator to track breakpoints across tools and messages
- const cacheControlValidator = new CacheControlValidator();
-
- const toolNameMapping = createToolNameMapping({
- tools,
- providerToolNames: {
- 'anthropic.code_execution_20250522': 'code_execution',
- 'anthropic.code_execution_20250825': 'code_execution',
- 'anthropic.code_execution_20260120': 'code_execution',
- 'anthropic.computer_20241022': 'computer',
- 'anthropic.computer_20250124': 'computer',
- 'anthropic.text_editor_20241022': 'str_replace_editor',
- 'anthropic.text_editor_20250124': 'str_replace_editor',
- 'anthropic.text_editor_20250429': 'str_replace_based_edit_tool',
- 'anthropic.text_editor_20250728': 'str_replace_based_edit_tool',
- 'anthropic.bash_20241022': 'bash',
- 'anthropic.bash_20250124': 'bash',
- 'anthropic.memory_20250818': 'memory',
- 'anthropic.web_search_20250305': 'web_search',
- 'anthropic.web_search_20260209': 'web_search',
- 'anthropic.web_fetch_20250910': 'web_fetch',
- 'anthropic.web_fetch_20260209': 'web_fetch',
- 'anthropic.tool_search_regex_20251119': 'tool_search_tool_regex',
- 'anthropic.tool_search_bm25_20251119': 'tool_search_tool_bm25',
- },
- });
-
- const { prompt: messagesPrompt, betas } =
- await convertToAnthropicMessagesPrompt({
- prompt,
- sendReasoning: anthropicOptions?.sendReasoning ?? true,
- warnings,
- cacheControlValidator,
- toolNameMapping,
- });
-
- const thinkingType = anthropicOptions?.thinking?.type;
- const isThinking =
- thinkingType === 'enabled' || thinkingType === 'adaptive';
- let thinkingBudget =
- thinkingType === 'enabled'
- ? anthropicOptions?.thinking?.budgetTokens
- : undefined;
-
- const maxTokens = maxOutputTokens ?? maxOutputTokensForModel;
-
- const baseArgs = {
- // model id:
- model: this.modelId,
-
- // standardized settings:
- max_tokens: maxTokens,
- temperature,
- top_k: topK,
- top_p: topP,
- stop_sequences: stopSequences,
-
- // provider specific settings:
- ...(isThinking && {
- thinking: {
- type: thinkingType,
- ...(thinkingBudget != null && { budget_tokens: thinkingBudget }),
- },
- }),
- ...((anthropicOptions?.effort ||
- (useStructuredOutput &&
- responseFormat?.type === 'json' &&
- responseFormat.schema != null)) && {
- output_config: {
- ...(anthropicOptions?.effort && {
- effort: anthropicOptions.effort,
- }),
- ...(useStructuredOutput &&
- responseFormat?.type === 'json' &&
- responseFormat.schema != null && {
- format: {
- type: 'json_schema',
- schema: responseFormat.schema,
- },
- }),
- },
- }),
- ...(anthropicOptions?.speed && {
- speed: anthropicOptions.speed,
- }),
- ...(anthropicOptions?.cacheControl && {
- cache_control: anthropicOptions.cacheControl,
- }),
- ...(anthropicOptions?.metadata?.userId != null && {
- metadata: { user_id: anthropicOptions.metadata.userId },
- }),
-
- // mcp servers:
- ...(anthropicOptions?.mcpServers &&
- anthropicOptions.mcpServers.length > 0 && {
- mcp_servers: anthropicOptions.mcpServers.map(server => ({
- type: server.type,
- name: server.name,
- url: server.url,
- authorization_token: server.authorizationToken,
- tool_configuration: server.toolConfiguration
- ? {
- allowed_tools: server.toolConfiguration.allowedTools,
- enabled: server.toolConfiguration.enabled,
- }
- : undefined,
- })),
- }),
-
- // container: For programmatic tool calling (just an ID string) or agent skills (object with id and skills)
- ...(anthropicOptions?.container && {
- container:
- anthropicOptions.container.skills &&
- anthropicOptions.container.skills.length > 0
- ? // Object format when skills are provided (agent skills feature)
- ({
- id: anthropicOptions.container.id,
- skills: anthropicOptions.container.skills.map(skill => ({
- type: skill.type,
- skill_id: skill.skillId,
- version: skill.version,
- })),
- } satisfies AnthropicContainer)
- : // String format for container ID only (programmatic tool calling)
- anthropicOptions.container.id,
- }),
-
- // prompt:
- system: messagesPrompt.system,
- messages: messagesPrompt.messages,
-
- ...(contextManagement && {
- context_management: {
- edits: contextManagement.edits
- .map(edit => {
- const strategy = edit.type;
- switch (strategy) {
- case 'clear_tool_uses_20250919':
- return {
- type: edit.type,
- ...(edit.trigger !== undefined && {
- trigger: edit.trigger,
- }),
- ...(edit.keep !== undefined && { keep: edit.keep }),
- ...(edit.clearAtLeast !== undefined && {
- clear_at_least: edit.clearAtLeast,
- }),
- ...(edit.clearToolInputs !== undefined && {
- clear_tool_inputs: edit.clearToolInputs,
- }),
- ...(edit.excludeTools !== undefined && {
- exclude_tools: edit.excludeTools,
- }),
- };
-
- case 'clear_thinking_20251015':
- return {
- type: edit.type,
- ...(edit.keep !== undefined && { keep: edit.keep }),
- };
-
- case 'compact_20260112':
- return {
- type: edit.type,
- ...(edit.trigger !== undefined && {
- trigger: edit.trigger,
- }),
- ...(edit.pauseAfterCompaction !== undefined && {
- pause_after_compaction: edit.pauseAfterCompaction,
- }),
- ...(edit.instructions !== undefined && {
- instructions: edit.instructions,
- }),
- };
-
- default:
- warnings.push({
- type: 'other',
- message: `Unknown context management strategy: ${strategy}`,
- });
- return undefined;
- }
- })
- .filter(edit => edit !== undefined),
- },
- }),
- };
-
- if (isThinking) {
- if (thinkingType === 'enabled' && thinkingBudget == null) {
- warnings.push({
- type: 'compatibility',
- feature: 'extended thinking',
- details:
- 'thinking budget is required when thinking is enabled. using default budget of 1024 tokens.',
- });
-
- baseArgs.thinking = {
- type: 'enabled',
- budget_tokens: 1024,
- };
-
- thinkingBudget = 1024;
- }
-
- if (baseArgs.temperature != null) {
- baseArgs.temperature = undefined;
- warnings.push({
- type: 'unsupported',
- feature: 'temperature',
- details: 'temperature is not supported when thinking is enabled',
- });
- }
-
- if (topK != null) {
- baseArgs.top_k = undefined;
- warnings.push({
- type: 'unsupported',
- feature: 'topK',
- details: 'topK is not supported when thinking is enabled',
- });
- }
-
- if (topP != null) {
- baseArgs.top_p = undefined;
- warnings.push({
- type: 'unsupported',
- feature: 'topP',
- details: 'topP is not supported when thinking is enabled',
- });
- }
-
- // adjust max tokens to account for thinking:
- baseArgs.max_tokens = maxTokens + (thinkingBudget ?? 0);
- } else {
- // Only check temperature/topP mutual exclusivity when thinking is not enabled
- if (topP != null && temperature != null) {
- warnings.push({
- type: 'unsupported',
- feature: 'topP',
- details: `topP is not supported when temperature is set. topP is ignored.`,
- });
- baseArgs.top_p = undefined;
- }
- }
-
- // limit to max output tokens for known models to enable model switching without breaking it:
- if (isKnownModel && baseArgs.max_tokens > maxOutputTokensForModel) {
- // only warn if max output tokens is provided as input:
- if (maxOutputTokens != null) {
- warnings.push({
- type: 'unsupported',
- feature: 'maxOutputTokens',
- details:
- `${baseArgs.max_tokens} (maxOutputTokens + thinkingBudget) is greater than ${this.modelId} ${maxOutputTokensForModel} max output tokens. ` +
- `The max output tokens have been limited to ${maxOutputTokensForModel}.`,
- });
- }
- baseArgs.max_tokens = maxOutputTokensForModel;
- }
-
- if (
- anthropicOptions?.mcpServers &&
- anthropicOptions.mcpServers.length > 0
- ) {
- betas.add('mcp-client-2025-04-04');
- }
-
- if (contextManagement) {
- betas.add('context-management-2025-06-27');
-
- // Add compaction beta if compact edit is present
- if (contextManagement.edits.some(e => e.type === 'compact_20260112')) {
- betas.add('compact-2026-01-12');
- }
- }
-
- if (
- anthropicOptions?.container &&
- anthropicOptions.container.skills &&
- anthropicOptions.container.skills.length > 0
- ) {
- betas.add('code-execution-2025-08-25');
- betas.add('skills-2025-10-02');
- betas.add('files-api-2025-04-14');
-
- if (
- !tools?.some(
- tool =>
- tool.type === 'provider' &&
- (tool.id === 'anthropic.code_execution_20250825' ||
- tool.id === 'anthropic.code_execution_20260120'),
- )
- ) {
- warnings.push({
- type: 'other',
- message: 'code execution tool is required when using skills',
- });
- }
- }
-
- if (anthropicOptions?.effort) {
- betas.add('effort-2025-11-24');
- }
-
- if (anthropicOptions?.speed === 'fast') {
- betas.add('fast-mode-2026-02-01');
- }
-
- // only when streaming: enable fine-grained tool streaming
- if (stream && (anthropicOptions?.toolStreaming ?? true)) {
- betas.add('fine-grained-tool-streaming-2025-05-14');
- }
-
- const {
- tools: anthropicTools,
- toolChoice: anthropicToolChoice,
- toolWarnings,
- betas: toolsBetas,
- } = await prepareTools(
- jsonResponseTool != null
- ? {
- tools: [...(tools ?? []), jsonResponseTool],
- toolChoice: { type: 'required' },
- disableParallelToolUse: true,
- cacheControlValidator,
- supportsStructuredOutput: false,
- supportsStrictTools,
- }
- : {
- tools: tools ?? [],
- toolChoice,
- disableParallelToolUse: anthropicOptions?.disableParallelToolUse,
- cacheControlValidator,
- supportsStructuredOutput,
- supportsStrictTools,
- },
- );
-
- // Extract cache control warnings once at the end
- const cacheWarnings = cacheControlValidator.getWarnings();
-
- return {
- args: {
- ...baseArgs,
- tools: anthropicTools,
- tool_choice: anthropicToolChoice,
- stream: stream === true ? true : undefined, // do not send when not streaming
- },
- warnings: [...warnings, ...toolWarnings, ...cacheWarnings],
- betas: new Set([
- ...betas,
- ...toolsBetas,
- ...userSuppliedBetas,
- ...(anthropicOptions?.anthropicBeta ?? []),
- ]),
- usesJsonResponseTool: jsonResponseTool != null,
- toolNameMapping,
- providerOptionsName,
- usedCustomProviderKey,
- };
- }
-
- private async getHeaders({
- betas,
- headers,
- }: {
- betas: Set;
- headers: Record | undefined;
- }) {
- return combineHeaders(
- await resolve(this.config.headers),
- headers,
- betas.size > 0 ? { 'anthropic-beta': Array.from(betas).join(',') } : {},
- );
- }
-
- private async getBetasFromHeaders(
- requestHeaders: Record | undefined,
- ) {
- const configHeaders = await resolve(this.config.headers);
-
- const configBetaHeader = configHeaders['anthropic-beta'] ?? '';
- const requestBetaHeader = requestHeaders?.['anthropic-beta'] ?? '';
-
- return new Set(
- [
- ...configBetaHeader.toLowerCase().split(','),
- ...requestBetaHeader.toLowerCase().split(','),
- ]
- .map(beta => beta.trim())
- .filter(beta => beta !== ''),
- );
- }
-
- private buildRequestUrl(isStreaming: boolean): string {
- return (
- this.config.buildRequestUrl?.(this.config.baseURL, isStreaming) ??
- `${this.config.baseURL}/messages`
- );
- }
-
- private transformRequestBody(
- args: Record,
- betas: Set,
- ): Record {
- return this.config.transformRequestBody?.(args, betas) ?? args;
- }
-
- private extractCitationDocuments(prompt: LanguageModelV3Prompt): Array<{
- title: string;
- filename?: string;
- mediaType: string;
- }> {
- const isCitationPart = (part: {
- type: string;
- mediaType?: string;
- providerOptions?: { anthropic?: { citations?: { enabled?: boolean } } };
- }) => {
- if (part.type !== 'file') {
- return false;
- }
-
- if (
- part.mediaType !== 'application/pdf' &&
- part.mediaType !== 'text/plain'
- ) {
- return false;
- }
-
- const anthropic = part.providerOptions?.anthropic;
- const citationsConfig = anthropic?.citations as
- | { enabled?: boolean }
- | undefined;
- return citationsConfig?.enabled ?? false;
- };
-
- return prompt
- .filter(message => message.role === 'user')
- .flatMap(message => message.content)
- .filter(isCitationPart)
- .map(part => {
- // TypeScript knows this is a file part due to our filter
- const filePart = part as Extract;
- return {
- title: filePart.filename ?? 'Untitled Document',
- filename: filePart.filename,
- mediaType: filePart.mediaType,
- };
- });
- }
-
- async doGenerate(
- options: LanguageModelV3CallOptions,
- ): Promise {
- const {
- args,
- warnings,
- betas,
- usesJsonResponseTool,
- toolNameMapping,
- providerOptionsName,
- usedCustomProviderKey,
- } = await this.getArgs({
- ...options,
- stream: false,
- userSuppliedBetas: await this.getBetasFromHeaders(options.headers),
- });
-
- // Extract citation documents for response processing
- const citationDocuments = [
- ...this.extractCitationDocuments(options.prompt),
- ];
-
- const markCodeExecutionDynamic = hasWebTool20260209WithoutCodeExecution(
- args.tools,
- );
-
- const {
- responseHeaders,
- value: response,
- rawValue: rawResponse,
- } = await postJsonToApi({
- url: this.buildRequestUrl(false),
- headers: await this.getHeaders({ betas, headers: options.headers }),
- body: this.transformRequestBody(args, betas),
- failedResponseHandler: anthropicFailedResponseHandler,
- successfulResponseHandler: createJsonResponseHandler(
- anthropicMessagesResponseSchema,
- ),
- abortSignal: options.abortSignal,
- fetch: this.config.fetch,
- });
-
- const content: Array = [];
- const mcpToolCalls: Record = {};
- const serverToolCalls: Record = {}; // tool_use_id -> provider tool name
- let isJsonResponseFromTool = false;
-
- // map response content to content array
- for (const part of response.content) {
- switch (part.type) {
- case 'text': {
- if (!usesJsonResponseTool) {
- content.push({ type: 'text', text: part.text });
-
- // Process citations if present
- if (part.citations) {
- for (const citation of part.citations) {
- const source = createCitationSource(
- citation,
- citationDocuments,
- this.generateId,
- );
-
- if (source) {
- content.push(source);
- }
- }
- }
- }
- break;
- }
- case 'thinking': {
- content.push({
- type: 'reasoning',
- text: part.thinking,
- providerMetadata: {
- anthropic: {
- signature: part.signature,
- } satisfies AnthropicReasoningMetadata,
- },
- });
- break;
- }
- case 'redacted_thinking': {
- content.push({
- type: 'reasoning',
- text: '',
- providerMetadata: {
- anthropic: {
- redactedData: part.data,
- } satisfies AnthropicReasoningMetadata,
- },
- });
- break;
- }
- case 'compaction': {
- content.push({
- type: 'text',
- text: part.content,
- providerMetadata: {
- anthropic: {
- type: 'compaction',
- },
- },
- });
- break;
- }
- case 'tool_use': {
- const isJsonResponseTool =
- usesJsonResponseTool && part.name === 'json';
-
- if (isJsonResponseTool) {
- isJsonResponseFromTool = true;
-
- // when a json response tool is used, the tool call becomes the text:
- content.push({
- type: 'text',
- text: JSON.stringify(part.input),
- });
- } else {
- const caller = part.caller;
- const callerInfo = caller
- ? {
- type: caller.type,
- toolId: 'tool_id' in caller ? caller.tool_id : undefined,
- }
- : undefined;
-
- content.push({
- type: 'tool-call',
- toolCallId: part.id,
- toolName: part.name,
- input: JSON.stringify(part.input),
- ...(callerInfo && {
- providerMetadata: {
- anthropic: {
- caller: callerInfo,
- },
- },
- }),
- });
- }
-
- break;
- }
- case 'server_tool_use': {
- // code execution 20250825 needs mapping:
- if (
- part.name === 'text_editor_code_execution' ||
- part.name === 'bash_code_execution'
- ) {
- content.push({
- type: 'tool-call',
- toolCallId: part.id,
- toolName: toolNameMapping.toCustomToolName('code_execution'),
- input: JSON.stringify({ type: part.name, ...part.input }),
- providerExecuted: true,
- });
- } else if (
- part.name === 'web_search' ||
- part.name === 'code_execution' ||
- part.name === 'web_fetch'
- ) {
- // For code_execution, inject 'programmatic-tool-call' type when input has { code } format
- const inputToSerialize =
- part.name === 'code_execution' &&
- part.input != null &&
- typeof part.input === 'object' &&
- 'code' in part.input &&
- !('type' in part.input)
- ? { type: 'programmatic-tool-call', ...part.input }
- : part.input;
-
- content.push({
- type: 'tool-call',
- toolCallId: part.id,
- toolName: toolNameMapping.toCustomToolName(part.name),
- input: JSON.stringify(inputToSerialize),
- providerExecuted: true,
- // We want this 'code_execution' tool call to be allowed even if the tool is not explicitly provided.
- // Since the validation generally bypasses dynamic tools, we mark this specific tool as dynamic.
- ...(markCodeExecutionDynamic && part.name === 'code_execution'
- ? { dynamic: true }
- : {}),
- });
- } else if (
- part.name === 'tool_search_tool_regex' ||
- part.name === 'tool_search_tool_bm25'
- ) {
- serverToolCalls[part.id] = part.name;
- content.push({
- type: 'tool-call',
- toolCallId: part.id,
- toolName: toolNameMapping.toCustomToolName(part.name),
- input: JSON.stringify(part.input),
- providerExecuted: true,
- });
- }
-
- break;
- }
- case 'mcp_tool_use': {
- mcpToolCalls[part.id] = {
- type: 'tool-call',
- toolCallId: part.id,
- toolName: part.name,
- input: JSON.stringify(part.input),
- providerExecuted: true,
- dynamic: true,
- providerMetadata: {
- anthropic: {
- type: 'mcp-tool-use',
- serverName: part.server_name,
- },
- },
- };
- content.push(mcpToolCalls[part.id]);
- break;
- }
- case 'mcp_tool_result': {
- content.push({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: mcpToolCalls[part.tool_use_id].toolName,
- isError: part.is_error,
- result: part.content,
- dynamic: true,
- providerMetadata: mcpToolCalls[part.tool_use_id].providerMetadata,
- });
- break;
- }
- case 'web_fetch_tool_result': {
- if (part.content.type === 'web_fetch_result') {
- citationDocuments.push({
- title: part.content.content.title ?? part.content.url,
- mediaType: part.content.content.source.media_type,
- });
- content.push({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName('web_fetch'),
- result: {
- type: 'web_fetch_result',
- url: part.content.url,
- retrievedAt: part.content.retrieved_at,
- content: {
- type: part.content.content.type,
- title: part.content.content.title,
- citations: part.content.content.citations,
- source: {
- type: part.content.content.source.type,
- mediaType: part.content.content.source.media_type,
- data: part.content.content.source.data,
- },
- },
- },
- });
- } else if (part.content.type === 'web_fetch_tool_result_error') {
- content.push({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName('web_fetch'),
- isError: true,
- result: {
- type: 'web_fetch_tool_result_error',
- errorCode: part.content.error_code,
- },
- });
- }
- break;
- }
- case 'web_search_tool_result': {
- if (Array.isArray(part.content)) {
- content.push({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName('web_search'),
- result: part.content.map(result => ({
- url: result.url,
- title: result.title,
- pageAge: result.page_age ?? null,
- encryptedContent: result.encrypted_content,
- type: result.type,
- })),
- });
-
- for (const result of part.content) {
- content.push({
- type: 'source',
- sourceType: 'url',
- id: this.generateId(),
- url: result.url,
- title: result.title,
- providerMetadata: {
- anthropic: {
- pageAge: result.page_age ?? null,
- },
- },
- });
- }
- } else {
- content.push({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName('web_search'),
- isError: true,
- result: {
- type: 'web_search_tool_result_error',
- errorCode: part.content.error_code,
- },
- });
- }
- break;
- }
-
- // code execution 20250522:
- case 'code_execution_tool_result': {
- if (part.content.type === 'code_execution_result') {
- content.push({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName('code_execution'),
- result: {
- type: part.content.type,
- stdout: part.content.stdout,
- stderr: part.content.stderr,
- return_code: part.content.return_code,
- content: part.content.content ?? [],
- },
- });
- } else if (part.content.type === 'encrypted_code_execution_result') {
- content.push({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName('code_execution'),
- result: {
- type: part.content.type,
- encrypted_stdout: part.content.encrypted_stdout,
- stderr: part.content.stderr,
- return_code: part.content.return_code,
- content: part.content.content ?? [],
- },
- });
- } else if (part.content.type === 'code_execution_tool_result_error') {
- content.push({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName('code_execution'),
- isError: true,
- result: {
- type: 'code_execution_tool_result_error',
- errorCode: part.content.error_code,
- },
- });
- }
- break;
- }
-
- // code execution 20250825:
- case 'bash_code_execution_tool_result':
- case 'text_editor_code_execution_tool_result': {
- content.push({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName('code_execution'),
- result: part.content,
- });
- break;
- }
-
- // tool search tool results:
- case 'tool_search_tool_result': {
- let providerToolName = serverToolCalls[part.tool_use_id];
-
- if (providerToolName == null) {
- const bm25CustomName = toolNameMapping.toCustomToolName(
- 'tool_search_tool_bm25',
- );
- const regexCustomName = toolNameMapping.toCustomToolName(
- 'tool_search_tool_regex',
- );
-
- if (bm25CustomName !== 'tool_search_tool_bm25') {
- providerToolName = 'tool_search_tool_bm25';
- } else if (regexCustomName !== 'tool_search_tool_regex') {
- providerToolName = 'tool_search_tool_regex';
- } else {
- providerToolName = 'tool_search_tool_regex';
- }
- }
-
- if (part.content.type === 'tool_search_tool_search_result') {
- content.push({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName(providerToolName),
- result: part.content.tool_references.map(ref => ({
- type: ref.type,
- toolName: ref.tool_name,
- })),
- });
- } else {
- content.push({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName(providerToolName),
- isError: true,
- result: {
- type: 'tool_search_tool_result_error',
- errorCode: part.content.error_code,
- },
- });
- }
- break;
- }
- }
- }
-
- return {
- content,
- finishReason: {
- unified: mapAnthropicStopReason({
- finishReason: response.stop_reason,
- isJsonResponseFromTool,
- }),
- raw: response.stop_reason ?? undefined,
- },
- usage: convertAnthropicMessagesUsage({ usage: response.usage }),
- request: { body: args },
- response: {
- id: response.id ?? undefined,
- modelId: response.model ?? undefined,
- headers: responseHeaders,
- body: rawResponse,
- },
- warnings,
- providerMetadata: (() => {
- const anthropicMetadata = {
- usage: response.usage as JSONObject,
- cacheCreationInputTokens:
- response.usage.cache_creation_input_tokens ?? null,
- stopSequence: response.stop_sequence ?? null,
-
- iterations: response.usage.iterations
- ? response.usage.iterations.map(iter => ({
- type: iter.type,
- inputTokens: iter.input_tokens,
- outputTokens: iter.output_tokens,
- }))
- : null,
- container: response.container
- ? {
- expiresAt: response.container.expires_at,
- id: response.container.id,
- skills:
- response.container.skills?.map(skill => ({
- type: skill.type,
- skillId: skill.skill_id,
- version: skill.version,
- })) ?? null,
- }
- : null,
- contextManagement:
- mapAnthropicResponseContextManagement(
- response.context_management,
- ) ?? null,
- } satisfies AnthropicMessageMetadata;
-
- const providerMetadata: SharedV3ProviderMetadata = {
- anthropic: anthropicMetadata,
- };
-
- if (usedCustomProviderKey && providerOptionsName !== 'anthropic') {
- providerMetadata[providerOptionsName] = anthropicMetadata;
- }
-
- return providerMetadata;
- })(),
- };
- }
-
- async doStream(
- options: LanguageModelV3CallOptions,
- ): Promise {
- const {
- args: body,
- warnings,
- betas,
- usesJsonResponseTool,
- toolNameMapping,
- providerOptionsName,
- usedCustomProviderKey,
- } = await this.getArgs({
- ...options,
- stream: true,
- userSuppliedBetas: await this.getBetasFromHeaders(options.headers),
- });
-
- // Extract citation documents for response processing
- const citationDocuments = [
- ...this.extractCitationDocuments(options.prompt),
- ];
-
- const markCodeExecutionDynamic = hasWebTool20260209WithoutCodeExecution(
- body.tools,
- );
-
- const url = this.buildRequestUrl(true);
- const { responseHeaders, value: response } = await postJsonToApi({
- url,
- headers: await this.getHeaders({ betas, headers: options.headers }),
- body: this.transformRequestBody(body, betas),
- failedResponseHandler: anthropicFailedResponseHandler,
- successfulResponseHandler: createEventSourceResponseHandler(
- anthropicMessagesChunkSchema,
- ),
- abortSignal: options.abortSignal,
- fetch: this.config.fetch,
- });
-
- let finishReason: LanguageModelV3FinishReason = {
- unified: 'other',
- raw: undefined,
- };
- const usage: AnthropicMessagesUsage = {
- input_tokens: 0,
- output_tokens: 0,
- cache_creation_input_tokens: 0,
- cache_read_input_tokens: 0,
- iterations: null,
- };
-
- const contentBlocks: Record<
- number,
- | {
- type: 'tool-call';
- toolCallId: string;
- toolName: string;
- input: string;
- providerExecuted?: boolean;
- firstDelta: boolean;
- providerToolName?: string;
- caller?: {
- type:
- | 'code_execution_20250825'
- | 'code_execution_20260120'
- | 'direct';
- toolId?: string;
- };
- }
- | { type: 'text' | 'reasoning' }
- > = {};
- const mcpToolCalls: Record = {};
- const serverToolCalls: Record = {}; // tool_use_id -> provider tool name
-
- let contextManagement:
- | AnthropicMessageMetadata['contextManagement']
- | null = null;
- let rawUsage: JSONObject | undefined = undefined;
- let cacheCreationInputTokens: number | null = null;
- let stopSequence: string | null = null;
- let container: AnthropicMessageMetadata['container'] | null = null;
- let isJsonResponseFromTool = false;
-
- let blockType:
- | 'text'
- | 'thinking'
- | 'tool_use'
- | 'redacted_thinking'
- | 'server_tool_use'
- | 'web_fetch_tool_result'
- | 'web_search_tool_result'
- | 'code_execution_tool_result'
- | 'text_editor_code_execution_tool_result'
- | 'bash_code_execution_tool_result'
- | 'tool_search_tool_result'
- | 'mcp_tool_use'
- | 'mcp_tool_result'
- | 'compaction'
- | undefined = undefined;
-
- const generateId = this.generateId;
-
- const transformedStream = response.pipeThrough(
- new TransformStream<
- ParseResult>,
- LanguageModelV3StreamPart
- >({
- start(controller) {
- controller.enqueue({ type: 'stream-start', warnings });
- },
-
- transform(chunk, controller) {
- if (options.includeRawChunks) {
- controller.enqueue({ type: 'raw', rawValue: chunk.rawValue });
- }
-
- if (!chunk.success) {
- controller.enqueue({ type: 'error', error: chunk.error });
- return;
- }
-
- const value = chunk.value;
-
- switch (value.type) {
- case 'ping': {
- return; // ignored
- }
-
- case 'content_block_start': {
- const part = value.content_block;
- const contentBlockType = part.type;
- blockType = contentBlockType;
-
- switch (contentBlockType) {
- case 'text': {
- // when a json response tool is used, the tool call is returned as text,
- // so we ignore the text content:
- if (usesJsonResponseTool) {
- return;
- }
-
- contentBlocks[value.index] = { type: 'text' };
- controller.enqueue({
- type: 'text-start',
- id: String(value.index),
- });
- return;
- }
-
- case 'thinking': {
- contentBlocks[value.index] = { type: 'reasoning' };
- controller.enqueue({
- type: 'reasoning-start',
- id: String(value.index),
- });
- return;
- }
-
- case 'redacted_thinking': {
- contentBlocks[value.index] = { type: 'reasoning' };
- controller.enqueue({
- type: 'reasoning-start',
- id: String(value.index),
- providerMetadata: {
- anthropic: {
- redactedData: part.data,
- } satisfies AnthropicReasoningMetadata,
- },
- });
- return;
- }
-
- case 'compaction': {
- contentBlocks[value.index] = { type: 'text' };
- controller.enqueue({
- type: 'text-start',
- id: String(value.index),
- providerMetadata: {
- anthropic: {
- type: 'compaction',
- },
- },
- });
- return;
- }
-
- case 'tool_use': {
- const isJsonResponseTool =
- usesJsonResponseTool && part.name === 'json';
-
- if (isJsonResponseTool) {
- isJsonResponseFromTool = true;
-
- contentBlocks[value.index] = { type: 'text' };
-
- controller.enqueue({
- type: 'text-start',
- id: String(value.index),
- });
- } else {
- // Extract caller info for type-safe access
- const caller = part.caller;
- const callerInfo = caller
- ? {
- type: caller.type,
- toolId:
- 'tool_id' in caller ? caller.tool_id : undefined,
- }
- : undefined;
-
- // Programmatic tool calling: for deferred tool calls from code_execution,
- // input may be present directly in content_block_start.
- // Only use if non-empty (empty {} means input comes via deltas)
- const hasNonEmptyInput =
- part.input && Object.keys(part.input).length > 0;
- const initialInput = hasNonEmptyInput
- ? JSON.stringify(part.input)
- : '';
-
- contentBlocks[value.index] = {
- type: 'tool-call',
- toolCallId: part.id,
- toolName: part.name,
- input: initialInput,
- firstDelta: initialInput.length === 0,
- ...(callerInfo && { caller: callerInfo }),
- };
-
- controller.enqueue({
- type: 'tool-input-start',
- id: part.id,
- toolName: part.name,
- });
- }
- return;
- }
-
- case 'server_tool_use': {
- if (
- [
- 'web_fetch',
- 'web_search',
- // code execution 20250825:
- 'code_execution',
- // code execution 20250825 text editor:
- 'text_editor_code_execution',
- // code execution 20250825 bash:
- 'bash_code_execution',
- ].includes(part.name)
- ) {
- // map tool names for the code execution 20250825 tool:
- const providerToolName =
- part.name === 'text_editor_code_execution' ||
- part.name === 'bash_code_execution'
- ? 'code_execution'
- : part.name;
-
- const customToolName =
- toolNameMapping.toCustomToolName(providerToolName);
-
- // Tools like 'web_fetch_20260209' provide input data here.
- // Other tools like 'code_execution_20260120' provide input data via deltas.
- // So we only use this if it's non-empty to avoid conflicts.
- const finalInput =
- part.input != null &&
- typeof part.input === 'object' &&
- Object.keys(part.input).length > 0
- ? JSON.stringify(part.input)
- : '';
-
- contentBlocks[value.index] = {
- type: 'tool-call',
- toolCallId: part.id,
- toolName: customToolName,
- input: finalInput,
- providerExecuted: true,
- ...(markCodeExecutionDynamic &&
- providerToolName === 'code_execution'
- ? { dynamic: true }
- : {}),
- firstDelta: true,
- providerToolName: part.name,
- };
-
- controller.enqueue({
- type: 'tool-input-start',
- id: part.id,
- toolName: customToolName,
- providerExecuted: true,
- ...(markCodeExecutionDynamic &&
- providerToolName === 'code_execution'
- ? { dynamic: true }
- : {}),
- });
- } else if (
- part.name === 'tool_search_tool_regex' ||
- part.name === 'tool_search_tool_bm25'
- ) {
- serverToolCalls[part.id] = part.name;
- const customToolName = toolNameMapping.toCustomToolName(
- part.name,
- );
-
- contentBlocks[value.index] = {
- type: 'tool-call',
- toolCallId: part.id,
- toolName: customToolName,
- input: '',
- providerExecuted: true,
- firstDelta: true,
- providerToolName: part.name,
- };
-
- controller.enqueue({
- type: 'tool-input-start',
- id: part.id,
- toolName: customToolName,
- providerExecuted: true,
- });
- }
-
- return;
- }
-
- case 'web_fetch_tool_result': {
- if (part.content.type === 'web_fetch_result') {
- citationDocuments.push({
- title: part.content.content.title ?? part.content.url,
- mediaType: part.content.content.source.media_type,
- });
- controller.enqueue({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName('web_fetch'),
- result: {
- type: 'web_fetch_result',
- url: part.content.url,
- retrievedAt: part.content.retrieved_at,
- content: {
- type: part.content.content.type,
- title: part.content.content.title,
- citations: part.content.content.citations,
- source: {
- type: part.content.content.source.type,
- mediaType: part.content.content.source.media_type,
- data: part.content.content.source.data,
- },
- },
- },
- });
- } else if (
- part.content.type === 'web_fetch_tool_result_error'
- ) {
- controller.enqueue({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName('web_fetch'),
- isError: true,
- result: {
- type: 'web_fetch_tool_result_error',
- errorCode: part.content.error_code,
- },
- });
- }
-
- return;
- }
-
- case 'web_search_tool_result': {
- if (Array.isArray(part.content)) {
- controller.enqueue({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName('web_search'),
- result: part.content.map(result => ({
- url: result.url,
- title: result.title,
- pageAge: result.page_age ?? null,
- encryptedContent: result.encrypted_content,
- type: result.type,
- })),
- });
-
- for (const result of part.content) {
- controller.enqueue({
- type: 'source',
- sourceType: 'url',
- id: generateId(),
- url: result.url,
- title: result.title,
- providerMetadata: {
- anthropic: {
- pageAge: result.page_age ?? null,
- },
- },
- });
- }
- } else {
- controller.enqueue({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: toolNameMapping.toCustomToolName('web_search'),
- isError: true,
- result: {
- type: 'web_search_tool_result_error',
- errorCode: part.content.error_code,
- },
- });
- }
- return;
- }
-
- // code execution 20250522:
- case 'code_execution_tool_result': {
- if (part.content.type === 'code_execution_result') {
- controller.enqueue({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName:
- toolNameMapping.toCustomToolName('code_execution'),
- result: {
- type: part.content.type,
- stdout: part.content.stdout,
- stderr: part.content.stderr,
- return_code: part.content.return_code,
- content: part.content.content ?? [],
- },
- });
- } else if (
- part.content.type === 'encrypted_code_execution_result'
- ) {
- controller.enqueue({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName:
- toolNameMapping.toCustomToolName('code_execution'),
- result: {
- type: part.content.type,
- encrypted_stdout: part.content.encrypted_stdout,
- stderr: part.content.stderr,
- return_code: part.content.return_code,
- content: part.content.content ?? [],
- },
- });
- } else if (
- part.content.type === 'code_execution_tool_result_error'
- ) {
- controller.enqueue({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName:
- toolNameMapping.toCustomToolName('code_execution'),
- isError: true,
- result: {
- type: 'code_execution_tool_result_error',
- errorCode: part.content.error_code,
- },
- });
- }
-
- return;
- }
-
- // code execution 20250825:
- case 'bash_code_execution_tool_result':
- case 'text_editor_code_execution_tool_result': {
- controller.enqueue({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName:
- toolNameMapping.toCustomToolName('code_execution'),
- result: part.content,
- });
- return;
- }
-
- // tool search tool results:
- case 'tool_search_tool_result': {
- let providerToolName = serverToolCalls[part.tool_use_id];
-
- if (providerToolName == null) {
- const bm25CustomName = toolNameMapping.toCustomToolName(
- 'tool_search_tool_bm25',
- );
- const regexCustomName = toolNameMapping.toCustomToolName(
- 'tool_search_tool_regex',
- );
-
- if (bm25CustomName !== 'tool_search_tool_bm25') {
- providerToolName = 'tool_search_tool_bm25';
- } else if (regexCustomName !== 'tool_search_tool_regex') {
- providerToolName = 'tool_search_tool_regex';
- } else {
- providerToolName = 'tool_search_tool_regex';
- }
- }
-
- if (part.content.type === 'tool_search_tool_search_result') {
- controller.enqueue({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName:
- toolNameMapping.toCustomToolName(providerToolName),
- result: part.content.tool_references.map(ref => ({
- type: ref.type,
- toolName: ref.tool_name,
- })),
- });
- } else {
- controller.enqueue({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName:
- toolNameMapping.toCustomToolName(providerToolName),
- isError: true,
- result: {
- type: 'tool_search_tool_result_error',
- errorCode: part.content.error_code,
- },
- });
- }
- return;
- }
-
- case 'mcp_tool_use': {
- mcpToolCalls[part.id] = {
- type: 'tool-call',
- toolCallId: part.id,
- toolName: part.name,
- input: JSON.stringify(part.input),
- providerExecuted: true,
- dynamic: true,
- providerMetadata: {
- anthropic: {
- type: 'mcp-tool-use',
- serverName: part.server_name,
- },
- },
- };
- controller.enqueue(mcpToolCalls[part.id]);
- return;
- }
-
- case 'mcp_tool_result': {
- controller.enqueue({
- type: 'tool-result',
- toolCallId: part.tool_use_id,
- toolName: mcpToolCalls[part.tool_use_id].toolName,
- isError: part.is_error,
- result: part.content,
- dynamic: true,
- providerMetadata:
- mcpToolCalls[part.tool_use_id].providerMetadata,
- });
- return;
- }
-
- default: {
- const _exhaustiveCheck: never = contentBlockType;
- throw new Error(
- `Unsupported content block type: ${_exhaustiveCheck}`,
- );
- }
- }
- }
-
- case 'content_block_stop': {
- // when finishing a tool call block, send the full tool call:
- if (contentBlocks[value.index] != null) {
- const contentBlock = contentBlocks[value.index];
-
- switch (contentBlock.type) {
- case 'text': {
- controller.enqueue({
- type: 'text-end',
- id: String(value.index),
- });
- break;
- }
-
- case 'reasoning': {
- controller.enqueue({
- type: 'reasoning-end',
- id: String(value.index),
- });
- break;
- }
-
- case 'tool-call':
- // when a json response tool is used, the tool call is returned as text,
- // so we ignore the tool call content:
- const isJsonResponseTool =
- usesJsonResponseTool && contentBlock.toolName === 'json';
-
- if (!isJsonResponseTool) {
- controller.enqueue({
- type: 'tool-input-end',
- id: contentBlock.toolCallId,
- });
-
- // For code_execution, inject 'programmatic-tool-call' type
- // when input has { code } format (programmatic tool calling)
- let finalInput =
- contentBlock.input === '' ? '{}' : contentBlock.input;
- if (contentBlock.providerToolName === 'code_execution') {
- try {
- const parsed = JSON.parse(finalInput);
- if (
- parsed != null &&
- typeof parsed === 'object' &&
- 'code' in parsed &&
- !('type' in parsed)
- ) {
- finalInput = JSON.stringify({
- type: 'programmatic-tool-call',
- ...parsed,
- });
- }
- } catch {
- // ignore parse errors, use original input
- }
- }
-
- controller.enqueue({
- type: 'tool-call',
- toolCallId: contentBlock.toolCallId,
- toolName: contentBlock.toolName,
- input: finalInput,
- providerExecuted: contentBlock.providerExecuted,
- ...(markCodeExecutionDynamic &&
- contentBlock.providerToolName === 'code_execution'
- ? { dynamic: true }
- : {}),
- ...(contentBlock.caller && {
- providerMetadata: {
- anthropic: {
- caller: contentBlock.caller,
- },
- },
- }),
- });
- }
- break;
- }
-
- delete contentBlocks[value.index];
- }
-
- blockType = undefined; // reset block type
-
- return;
- }
-
- case 'content_block_delta': {
- const deltaType = value.delta.type;
-
- switch (deltaType) {
- case 'text_delta': {
- // when a json response tool is used, the tool call is returned as text,
- // so we ignore the text content:
- if (usesJsonResponseTool) {
- return; // excluding the text-start will also exclude the text-end
- }
-
- controller.enqueue({
- type: 'text-delta',
- id: String(value.index),
- delta: value.delta.text,
- });
-
- return;
- }
-
- case 'thinking_delta': {
- controller.enqueue({
- type: 'reasoning-delta',
- id: String(value.index),
- delta: value.delta.thinking,
- });
-
- return;
- }
-
- case 'signature_delta': {
- // signature are only supported on thinking blocks:
- if (blockType === 'thinking') {
- controller.enqueue({
- type: 'reasoning-delta',
- id: String(value.index),
- delta: '',
- providerMetadata: {
- anthropic: {
- signature: value.delta.signature,
- } satisfies AnthropicReasoningMetadata,
- },
- });
- }
-
- return;
- }
-
- case 'compaction_delta': {
- if (value.delta.content != null) {
- controller.enqueue({
- type: 'text-delta',
- id: String(value.index),
- delta: value.delta.content,
- });
- }
-
- return;
- }
-
- case 'input_json_delta': {
- const contentBlock = contentBlocks[value.index];
- let delta = value.delta.partial_json;
-
- // skip empty deltas to enable replacing the first character
- // in the code execution 20250825 tool.
- if (delta.length === 0) {
- return;
- }
-
- if (isJsonResponseFromTool) {
- if (contentBlock?.type !== 'text') {
- return; // exclude reasoning
- }
-
- controller.enqueue({
- type: 'text-delta',
- id: String(value.index),
- delta,
- });
- } else {
- if (contentBlock?.type !== 'tool-call') {
- return;
- }
-
- // for the code execution 20250825, we need to add
- // the type to the delta and change the tool name.
- if (
- contentBlock.firstDelta &&
- (contentBlock.providerToolName ===
- 'bash_code_execution' ||
- contentBlock.providerToolName ===
- 'text_editor_code_execution')
- ) {
- delta = `{"type": "${contentBlock.providerToolName}",${delta.substring(1)}`;
- }
-
- controller.enqueue({
- type: 'tool-input-delta',
- id: contentBlock.toolCallId,
- delta,
- });
-
- contentBlock.input += delta;
- contentBlock.firstDelta = false;
- }
-
- return;
- }
-
- case 'citations_delta': {
- const citation = value.delta.citation;
- const source = createCitationSource(
- citation,
- citationDocuments,
- generateId,
- );
-
- if (source) {
- controller.enqueue(source);
- }
-
- return;
- }
-
- default: {
- const _exhaustiveCheck: never = deltaType;
- throw new Error(
- `Unsupported delta type: ${_exhaustiveCheck}`,
- );
- }
- }
- }
-
- case 'message_start': {
- usage.input_tokens = value.message.usage.input_tokens;
- usage.cache_read_input_tokens =
- value.message.usage.cache_read_input_tokens ?? 0;
- usage.cache_creation_input_tokens =
- value.message.usage.cache_creation_input_tokens ?? 0;
-
- rawUsage = {
- ...(value.message.usage as JSONObject),
- };
-
- cacheCreationInputTokens =
- value.message.usage.cache_creation_input_tokens ?? null;
-
- if (value.message.container != null) {
- container = {
- expiresAt: value.message.container.expires_at,
- id: value.message.container.id,
- skills: null,
- };
- }
-
- if (value.message.stop_reason != null) {
- finishReason = {
- unified: mapAnthropicStopReason({
- finishReason: value.message.stop_reason,
- isJsonResponseFromTool,
- }),
- raw: value.message.stop_reason,
- };
- }
-
- controller.enqueue({
- type: 'response-metadata',
- id: value.message.id ?? undefined,
- modelId: value.message.model ?? undefined,
- });
-
- // Programmatic tool calling: process pre-populated content blocks
- // (for deferred tool calls, content may be in message_start)
- if (value.message.content != null) {
- for (
- let contentIndex = 0;
- contentIndex < value.message.content.length;
- contentIndex++
- ) {
- const part = value.message.content[contentIndex];
- if (part.type === 'tool_use') {
- const caller = part.caller;
- const callerInfo = caller
- ? {
- type: caller.type,
- toolId:
- 'tool_id' in caller ? caller.tool_id : undefined,
- }
- : undefined;
-
- controller.enqueue({
- type: 'tool-input-start',
- id: part.id,
- toolName: part.name,
- });
-
- const inputStr = JSON.stringify(part.input ?? {});
- controller.enqueue({
- type: 'tool-input-delta',
- id: part.id,
- delta: inputStr,
- });
-
- controller.enqueue({
- type: 'tool-input-end',
- id: part.id,
- });
-
- controller.enqueue({
- type: 'tool-call',
- toolCallId: part.id,
- toolName: part.name,
- input: inputStr,
- ...(callerInfo && {
- providerMetadata: {
- anthropic: {
- caller: callerInfo,
- },
- },
- }),
- });
- }
- }
- }
-
- return;
- }
-
- case 'message_delta': {
- if (
- value.usage.input_tokens != null &&
- usage.input_tokens !== value.usage.input_tokens
- ) {
- usage.input_tokens = value.usage.input_tokens;
- }
- usage.output_tokens = value.usage.output_tokens;
-
- if (value.usage.cache_read_input_tokens != null) {
- usage.cache_read_input_tokens =
- value.usage.cache_read_input_tokens;
- }
- if (value.usage.cache_creation_input_tokens != null) {
- usage.cache_creation_input_tokens =
- value.usage.cache_creation_input_tokens;
- cacheCreationInputTokens =
- value.usage.cache_creation_input_tokens;
- }
- if (value.usage.iterations != null) {
- usage.iterations = value.usage.iterations;
- }
-
- finishReason = {
- unified: mapAnthropicStopReason({
- finishReason: value.delta.stop_reason,
- isJsonResponseFromTool,
- }),
- raw: value.delta.stop_reason ?? undefined,
- };
-
- stopSequence = value.delta.stop_sequence ?? null;
- container =
- value.delta.container != null
- ? {
- expiresAt: value.delta.container.expires_at,
- id: value.delta.container.id,
- skills:
- value.delta.container.skills?.map(skill => ({
- type: skill.type,
- skillId: skill.skill_id,
- version: skill.version,
- })) ?? null,
- }
- : null;
-
- if (value.context_management) {
- contextManagement = mapAnthropicResponseContextManagement(
- value.context_management,
- );
- }
-
- rawUsage = {
- ...rawUsage,
- ...(value.usage as JSONObject),
- };
-
- return;
- }
-
- case 'message_stop': {
- const anthropicMetadata = {
- usage: (rawUsage as JSONObject) ?? null,
- cacheCreationInputTokens,
- stopSequence,
- iterations: usage.iterations
- ? usage.iterations.map(iter => ({
- type: iter.type,
- inputTokens: iter.input_tokens,
- outputTokens: iter.output_tokens,
- }))
- : null,
- container,
- contextManagement,
- } satisfies AnthropicMessageMetadata;
-
- const providerMetadata: SharedV3ProviderMetadata = {
- anthropic: anthropicMetadata,
- };
-
- if (
- usedCustomProviderKey &&
- providerOptionsName !== 'anthropic'
- ) {
- providerMetadata[providerOptionsName] = anthropicMetadata;
- }
-
- controller.enqueue({
- type: 'finish',
- finishReason,
- usage: convertAnthropicMessagesUsage({ usage, rawUsage }),
- providerMetadata,
- });
- return;
- }
-
- case 'error': {
- controller.enqueue({ type: 'error', error: value.error });
- return;
- }
-
- default: {
- const _exhaustiveCheck: never = value;
- throw new Error(`Unsupported chunk type: ${_exhaustiveCheck}`);
- }
- }
- },
- }),
- );
-
- // The first chunk needs to be pulled immediately to check if it is an error
- const [streamForFirstChunk, streamForConsumer] = transformedStream.tee();
-
- const firstChunkReader = streamForFirstChunk.getReader();
- try {
- await firstChunkReader.read(); // streamStart comes first, ignored
-
- let result = await firstChunkReader.read();
-
- // when raw chunks are enabled, the first chunk is a raw chunk, so we need to read the next chunk
- if (result.value?.type === 'raw') {
- result = await firstChunkReader.read();
- }
-
- // The Anthropic API returns 200 responses when there are overloaded errors.
- // We handle the case where the first chunk is an error here and transform
- // it into an APICallError.
- if (result.value?.type === 'error') {
- const error = result.value.error as { message: string; type: string };
-
- throw new APICallError({
- message: error.message,
- url,
- requestBodyValues: body,
- statusCode: error.type === 'overloaded_error' ? 529 : 500,
- responseHeaders,
- responseBody: JSON.stringify(error),
- isRetryable: error.type === 'overloaded_error',
- });
- }
- } finally {
- firstChunkReader.cancel().catch(() => {});
- firstChunkReader.releaseLock();
- }
-
- return {
- stream: streamForConsumer,
- request: { body },
- response: { headers: responseHeaders },
- };
- }
-}
-
-/**
- * Returns the capabilities of a Claude model that are used for defaults and feature selection.
- *
- * @see https://docs.claude.com/en/docs/about-claude/models/overview#model-comparison-table
- * @see https://platform.claude.com/docs/en/build-with-claude/structured-outputs
- */
-function getModelCapabilities(modelId: string): {
- maxOutputTokens: number;
- supportsStructuredOutput: boolean;
- isKnownModel: boolean;
-} {
- if (
- modelId.includes('claude-sonnet-4-6') ||
- modelId.includes('claude-opus-4-6')
- ) {
- return {
- maxOutputTokens: 128000,
- supportsStructuredOutput: true,
- isKnownModel: true,
- };
- } else if (
- modelId.includes('claude-sonnet-4-5') ||
- modelId.includes('claude-opus-4-5') ||
- modelId.includes('claude-haiku-4-5')
- ) {
- return {
- maxOutputTokens: 64000,
- supportsStructuredOutput: true,
- isKnownModel: true,
- };
- } else if (modelId.includes('claude-opus-4-1')) {
- return {
- maxOutputTokens: 32000,
- supportsStructuredOutput: true,
- isKnownModel: true,
- };
- } else if (modelId.includes('claude-sonnet-4-')) {
- return {
- maxOutputTokens: 64000,
- supportsStructuredOutput: false,
- isKnownModel: true,
- };
- } else if (modelId.includes('claude-opus-4-')) {
- return {
- maxOutputTokens: 32000,
- supportsStructuredOutput: false,
- isKnownModel: true,
- };
- } else if (modelId.includes('claude-3-haiku')) {
- return {
- maxOutputTokens: 4096,
- supportsStructuredOutput: false,
- isKnownModel: true,
- };
- } else {
- return {
- maxOutputTokens: 4096,
- supportsStructuredOutput: false,
- isKnownModel: false,
- };
- }
-}
-
-function hasWebTool20260209WithoutCodeExecution(
- tools: AnthropicTool[] | undefined,
-): boolean {
- if (!tools) {
- return false;
- }
- let hasWebTool20260209 = false;
- let hasCodeExecutionTool = false;
- for (const tool of tools) {
- if (
- 'type' in tool &&
- (tool.type === 'web_fetch_20260209' ||
- tool.type === 'web_search_20260209')
- ) {
- hasWebTool20260209 = true;
- continue;
- }
- if (tool.name === 'code_execution') {
- hasCodeExecutionTool = true;
- break;
- }
- }
- return hasWebTool20260209 && !hasCodeExecutionTool;
-}
-
-function mapAnthropicResponseContextManagement(
- contextManagement: AnthropicResponseContextManagement | null | undefined,
-): AnthropicMessageMetadata['contextManagement'] | null {
- return contextManagement
- ? {
- appliedEdits: contextManagement.applied_edits
- .map(edit => {
- const strategy = edit.type;
-
- switch (strategy) {
- case 'clear_tool_uses_20250919':
- return {
- type: edit.type,
- clearedToolUses: edit.cleared_tool_uses,
- clearedInputTokens: edit.cleared_input_tokens,
- };
-
- case 'clear_thinking_20251015':
- return {
- type: edit.type,
- clearedThinkingTurns: edit.cleared_thinking_turns,
- clearedInputTokens: edit.cleared_input_tokens,
- };
-
- case 'compact_20260112':
- return {
- type: edit.type,
- };
- }
- })
- .filter(edit => edit !== undefined),
- }
- : null;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-messages-options.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-messages-options.ts
deleted file mode 100644
index 34e7530e0..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-messages-options.ts
+++ /dev/null
@@ -1,263 +0,0 @@
-import { z } from 'zod/v4';
-
-// https://docs.claude.com/en/docs/about-claude/models/overview
-export type AnthropicMessagesModelId =
- | 'claude-3-haiku-20240307'
- | 'claude-haiku-4-5-20251001'
- | 'claude-haiku-4-5'
- | 'claude-opus-4-0'
- | 'claude-opus-4-20250514'
- | 'claude-opus-4-1-20250805'
- | 'claude-opus-4-1'
- | 'claude-opus-4-5'
- | 'claude-opus-4-5-20251101'
- | 'claude-sonnet-4-0'
- | 'claude-sonnet-4-20250514'
- | 'claude-sonnet-4-5-20250929'
- | 'claude-sonnet-4-5'
- | 'claude-sonnet-4-6'
- | 'claude-opus-4-6'
- | (string & {});
-
-/**
- * Anthropic file part provider options for document-specific features.
- * These options apply to individual file parts (documents).
- */
-export const anthropicFilePartProviderOptions = z.object({
- /**
- * Citation configuration for this document.
- * When enabled, this document will generate citations in the response.
- */
- citations: z
- .object({
- /**
- * Enable citations for this document
- */
- enabled: z.boolean(),
- })
- .optional(),
-
- /**
- * Custom title for the document.
- * If not provided, the filename will be used.
- */
- title: z.string().optional(),
-
- /**
- * Context about the document that will be passed to the model
- * but not used towards cited content.
- * Useful for storing document metadata as text or stringified JSON.
- */
- context: z.string().optional(),
-});
-
-export type AnthropicFilePartProviderOptions = z.infer<
- typeof anthropicFilePartProviderOptions
->;
-
-export const anthropicLanguageModelOptions = z.object({
- /**
- * Whether to send reasoning to the model.
- *
- * This allows you to deactivate reasoning inputs for models that do not support them.
- */
- sendReasoning: z.boolean().optional(),
-
- /**
- * Determines how structured outputs are generated.
- *
- * - `outputFormat`: Use the `output_config.format` parameter to specify the structured output format.
- * - `jsonTool`: Use a special 'json' tool to specify the structured output format.
- * - `auto`: Use 'outputFormat' when supported, otherwise use 'jsonTool' (default).
- */
- structuredOutputMode: z.enum(['outputFormat', 'jsonTool', 'auto']).optional(),
-
- /**
- * Configuration for enabling Claude's extended thinking.
- *
- * When enabled, responses include thinking content blocks showing Claude's thinking process before the final answer.
- * Requires a minimum budget of 1,024 tokens and counts towards the `max_tokens` limit.
- */
- thinking: z
- .discriminatedUnion('type', [
- z.object({
- /** for Sonnet 4.6, Opus 4.6, and newer models */
- type: z.literal('adaptive'),
- }),
- z.object({
- /** for models before Opus 4.6, except Sonnet 4.6 still supports it */
- type: z.literal('enabled'),
- budgetTokens: z.number().optional(),
- }),
- z.object({
- type: z.literal('disabled'),
- }),
- ])
- .optional(),
-
- /**
- * Whether to disable parallel function calling during tool use. Default is false.
- * When set to true, Claude will use at most one tool per response.
- */
- disableParallelToolUse: z.boolean().optional(),
-
- /**
- * Cache control settings for this message.
- * See https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching
- */
- cacheControl: z
- .object({
- type: z.literal('ephemeral'),
- ttl: z.union([z.literal('5m'), z.literal('1h')]).optional(),
- })
- .optional(),
-
- /**
- * Metadata to include with the request.
- *
- * See https://platform.claude.com/docs/en/api/messages/create for details.
- */
- metadata: z
- .object({
- /**
- * An external identifier for the user associated with the request.
- *
- * Should be a UUID, hash value, or other opaque identifier.
- * Must not contain PII (name, email, phone number, etc.).
- */
- userId: z.string().optional(),
- })
- .optional(),
-
- /**
- * MCP servers to be utilized in this request.
- */
- mcpServers: z
- .array(
- z.object({
- type: z.literal('url'),
- name: z.string(),
- url: z.string(),
- authorizationToken: z.string().nullish(),
- toolConfiguration: z
- .object({
- enabled: z.boolean().nullish(),
- allowedTools: z.array(z.string()).nullish(),
- })
- .nullish(),
- }),
- )
- .optional(),
-
- /**
- * Agent Skills configuration. Skills enable Claude to perform specialized tasks
- * like document processing (PPTX, DOCX, PDF, XLSX) and data analysis.
- * Requires code execution tool to be enabled.
- */
- container: z
- .object({
- id: z.string().optional(),
- skills: z
- .array(
- z.object({
- type: z.union([z.literal('anthropic'), z.literal('custom')]),
- skillId: z.string(),
- version: z.string().optional(),
- }),
- )
- .optional(),
- })
- .optional(),
-
- /**
- * Whether to enable tool streaming (and structured output streaming).
- *
- * When set to false, the model will return all tool calls and results
- * at once after a delay.
- *
- * @default true
- */
- toolStreaming: z.boolean().optional(),
-
- /**
- * @default 'high'
- */
- effort: z.enum(['low', 'medium', 'high', 'max']).optional(),
-
- /**
- * Enable fast mode for faster inference (2.5x faster output token speeds).
- * Only supported with claude-opus-4-6.
- */
- speed: z.enum(['fast', 'standard']).optional(),
-
- /**
- * A set of beta features to enable.
- * Allow a provider to receive the full `betas` set if it needs it.
- */
- anthropicBeta: z.array(z.string()).optional(),
-
- contextManagement: z
- .object({
- edits: z.array(
- z.discriminatedUnion('type', [
- z.object({
- type: z.literal('clear_tool_uses_20250919'),
- trigger: z
- .discriminatedUnion('type', [
- z.object({
- type: z.literal('input_tokens'),
- value: z.number(),
- }),
- z.object({
- type: z.literal('tool_uses'),
- value: z.number(),
- }),
- ])
- .optional(),
- keep: z
- .object({
- type: z.literal('tool_uses'),
- value: z.number(),
- })
- .optional(),
- clearAtLeast: z
- .object({
- type: z.literal('input_tokens'),
- value: z.number(),
- })
- .optional(),
- clearToolInputs: z.boolean().optional(),
- excludeTools: z.array(z.string()).optional(),
- }),
- z.object({
- type: z.literal('clear_thinking_20251015'),
- keep: z
- .union([
- z.literal('all'),
- z.object({
- type: z.literal('thinking_turns'),
- value: z.number(),
- }),
- ])
- .optional(),
- }),
- z.object({
- type: z.literal('compact_20260112'),
- trigger: z
- .object({
- type: z.literal('input_tokens'),
- value: z.number(),
- })
- .optional(),
- pauseAfterCompaction: z.boolean().optional(),
- instructions: z.string().optional(),
- }),
- ]),
- ),
- })
- .optional(),
-});
-
-export type AnthropicLanguageModelOptions = z.infer<
- typeof anthropicLanguageModelOptions
->;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-prepare-tools.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-prepare-tools.ts
deleted file mode 100644
index 2e82aabdb..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-prepare-tools.ts
+++ /dev/null
@@ -1,416 +0,0 @@
-import {
- LanguageModelV3CallOptions,
- SharedV3Warning,
- UnsupportedFunctionalityError,
-} from '@ai-sdk/provider';
-import { AnthropicTool, AnthropicToolChoice } from './anthropic-messages-api';
-import { CacheControlValidator } from './get-cache-control';
-import { textEditor_20250728ArgsSchema } from './tool/text-editor_20250728';
-import { webSearch_20260209ArgsSchema } from './tool/web-search_20260209';
-import { webSearch_20250305ArgsSchema } from './tool/web-search_20250305';
-import { webFetch_20260209ArgsSchema } from './tool/web-fetch-20260209';
-import { webFetch_20250910ArgsSchema } from './tool/web-fetch-20250910';
-import { validateTypes } from '@ai-sdk/provider-utils';
-
-export interface AnthropicToolOptions {
- deferLoading?: boolean;
- allowedCallers?: Array<
- 'direct' | 'code_execution_20250825' | 'code_execution_20260120'
- >;
- eagerInputStreaming?: boolean;
-}
-
-export async function prepareTools({
- tools,
- toolChoice,
- disableParallelToolUse,
- cacheControlValidator,
- supportsStructuredOutput,
- supportsStrictTools,
-}: {
- tools: LanguageModelV3CallOptions['tools'];
- toolChoice: LanguageModelV3CallOptions['toolChoice'] | undefined;
- disableParallelToolUse?: boolean;
- cacheControlValidator?: CacheControlValidator;
-
- /**
- * Whether the model supports native structured output response format.
- */
- supportsStructuredOutput: boolean;
-
- /**
- * Whether the model supports strict mode on tool definitions.
- */
- supportsStrictTools: boolean;
-}): Promise<{
- tools: Array | undefined;
- toolChoice: AnthropicToolChoice | undefined;
- toolWarnings: SharedV3Warning[];
- betas: Set;
-}> {
- // when the tools array is empty, change it to undefined to prevent errors:
- tools = tools?.length ? tools : undefined;
-
- const toolWarnings: SharedV3Warning[] = [];
- const betas = new Set();
- const validator = cacheControlValidator || new CacheControlValidator();
-
- if (tools == null) {
- return { tools: undefined, toolChoice: undefined, toolWarnings, betas };
- }
-
- const anthropicTools: AnthropicTool[] = [];
-
- for (const tool of tools) {
- switch (tool.type) {
- case 'function': {
- const cacheControl = validator.getCacheControl(tool.providerOptions, {
- type: 'tool definition',
- canCache: true,
- });
-
- // Read Anthropic-specific provider options
- const anthropicOptions = tool.providerOptions?.anthropic as
- | AnthropicToolOptions
- | undefined;
- // eager_input_streaming is only supported on custom (function) tools
- const eagerInputStreaming = anthropicOptions?.eagerInputStreaming;
- const deferLoading = anthropicOptions?.deferLoading;
- const allowedCallers = anthropicOptions?.allowedCallers;
-
- if (!supportsStrictTools && tool.strict != null) {
- toolWarnings.push({
- type: 'unsupported',
- feature: 'strict',
- details: `Tool '${tool.name}' has strict: ${tool.strict}, but strict mode is not supported by this provider. The strict property will be ignored.`,
- });
- }
-
- anthropicTools.push({
- name: tool.name,
- description: tool.description,
- input_schema: tool.inputSchema,
- cache_control: cacheControl,
- ...(eagerInputStreaming ? { eager_input_streaming: true } : {}),
- ...(supportsStrictTools === true && tool.strict != null
- ? { strict: tool.strict }
- : {}),
- ...(deferLoading != null ? { defer_loading: deferLoading } : {}),
- ...(allowedCallers != null
- ? { allowed_callers: allowedCallers }
- : {}),
- ...(tool.inputExamples != null
- ? {
- input_examples: tool.inputExamples.map(
- example => example.input,
- ),
- }
- : {}),
- });
-
- if (supportsStructuredOutput === true) {
- betas.add('structured-outputs-2025-11-13');
- }
-
- if (tool.inputExamples != null || allowedCallers != null) {
- betas.add('advanced-tool-use-2025-11-20');
- }
-
- break;
- }
-
- case 'provider': {
- // Note: Provider-defined tools don't currently support providerOptions in the SDK,
- // so cache_control cannot be set on them. The Anthropic API supports caching all tools,
- // but the SDK would need to be updated to expose providerOptions on provider-defined tools.
- switch (tool.id) {
- case 'anthropic.code_execution_20250522': {
- betas.add('code-execution-2025-05-22');
- anthropicTools.push({
- type: 'code_execution_20250522',
- name: 'code_execution',
- cache_control: undefined,
- });
- break;
- }
- case 'anthropic.code_execution_20250825': {
- betas.add('code-execution-2025-08-25');
- anthropicTools.push({
- type: 'code_execution_20250825',
- name: 'code_execution',
- });
- break;
- }
- case 'anthropic.code_execution_20260120': {
- anthropicTools.push({
- type: 'code_execution_20260120',
- name: 'code_execution',
- });
- break;
- }
- case 'anthropic.computer_20250124': {
- betas.add('computer-use-2025-01-24');
- anthropicTools.push({
- name: 'computer',
- type: 'computer_20250124',
- display_width_px: tool.args.displayWidthPx as number,
- display_height_px: tool.args.displayHeightPx as number,
- display_number: tool.args.displayNumber as number,
- cache_control: undefined,
- });
- break;
- }
- case 'anthropic.computer_20251124': {
- betas.add('computer-use-2025-11-24');
- anthropicTools.push({
- name: 'computer',
- type: 'computer_20251124',
- display_width_px: tool.args.displayWidthPx as number,
- display_height_px: tool.args.displayHeightPx as number,
- display_number: tool.args.displayNumber as number,
- enable_zoom: tool.args.enableZoom as boolean,
- cache_control: undefined,
- });
- break;
- }
- case 'anthropic.computer_20241022': {
- betas.add('computer-use-2024-10-22');
- anthropicTools.push({
- name: 'computer',
- type: 'computer_20241022',
- display_width_px: tool.args.displayWidthPx as number,
- display_height_px: tool.args.displayHeightPx as number,
- display_number: tool.args.displayNumber as number,
- cache_control: undefined,
- });
- break;
- }
- case 'anthropic.text_editor_20250124': {
- betas.add('computer-use-2025-01-24');
- anthropicTools.push({
- name: 'str_replace_editor',
- type: 'text_editor_20250124',
- cache_control: undefined,
- });
- break;
- }
- case 'anthropic.text_editor_20241022': {
- betas.add('computer-use-2024-10-22');
- anthropicTools.push({
- name: 'str_replace_editor',
- type: 'text_editor_20241022',
- cache_control: undefined,
- });
- break;
- }
- case 'anthropic.text_editor_20250429': {
- betas.add('computer-use-2025-01-24');
- anthropicTools.push({
- name: 'str_replace_based_edit_tool',
- type: 'text_editor_20250429',
- cache_control: undefined,
- });
- break;
- }
- case 'anthropic.text_editor_20250728': {
- const args = await validateTypes({
- value: tool.args,
- schema: textEditor_20250728ArgsSchema,
- });
- anthropicTools.push({
- name: 'str_replace_based_edit_tool',
- type: 'text_editor_20250728',
- max_characters: args.maxCharacters,
- cache_control: undefined,
- });
- break;
- }
- case 'anthropic.bash_20250124': {
- betas.add('computer-use-2025-01-24');
- anthropicTools.push({
- name: 'bash',
- type: 'bash_20250124',
- cache_control: undefined,
- });
- break;
- }
- case 'anthropic.bash_20241022': {
- betas.add('computer-use-2024-10-22');
- anthropicTools.push({
- name: 'bash',
- type: 'bash_20241022',
- cache_control: undefined,
- });
- break;
- }
- case 'anthropic.memory_20250818': {
- betas.add('context-management-2025-06-27');
- anthropicTools.push({
- name: 'memory',
- type: 'memory_20250818',
- });
- break;
- }
- case 'anthropic.web_fetch_20250910': {
- betas.add('web-fetch-2025-09-10');
- const args = await validateTypes({
- value: tool.args,
- schema: webFetch_20250910ArgsSchema,
- });
- anthropicTools.push({
- type: 'web_fetch_20250910',
- name: 'web_fetch',
- max_uses: args.maxUses,
- allowed_domains: args.allowedDomains,
- blocked_domains: args.blockedDomains,
- citations: args.citations,
- max_content_tokens: args.maxContentTokens,
- cache_control: undefined,
- });
- break;
- }
- case 'anthropic.web_fetch_20260209': {
- betas.add('code-execution-web-tools-2026-02-09');
- const args = await validateTypes({
- value: tool.args,
- schema: webFetch_20260209ArgsSchema,
- });
- anthropicTools.push({
- type: 'web_fetch_20260209',
- name: 'web_fetch',
- max_uses: args.maxUses,
- allowed_domains: args.allowedDomains,
- blocked_domains: args.blockedDomains,
- citations: args.citations,
- max_content_tokens: args.maxContentTokens,
- cache_control: undefined,
- });
- break;
- }
- case 'anthropic.web_search_20250305': {
- const args = await validateTypes({
- value: tool.args,
- schema: webSearch_20250305ArgsSchema,
- });
- anthropicTools.push({
- type: 'web_search_20250305',
- name: 'web_search',
- max_uses: args.maxUses,
- allowed_domains: args.allowedDomains,
- blocked_domains: args.blockedDomains,
- user_location: args.userLocation,
- cache_control: undefined,
- });
- break;
- }
- case 'anthropic.web_search_20260209': {
- betas.add('code-execution-web-tools-2026-02-09');
- const args = await validateTypes({
- value: tool.args,
- schema: webSearch_20260209ArgsSchema,
- });
- anthropicTools.push({
- type: 'web_search_20260209',
- name: 'web_search',
- max_uses: args.maxUses,
- allowed_domains: args.allowedDomains,
- blocked_domains: args.blockedDomains,
- user_location: args.userLocation,
- cache_control: undefined,
- });
- break;
- }
-
- case 'anthropic.tool_search_regex_20251119': {
- anthropicTools.push({
- type: 'tool_search_tool_regex_20251119',
- name: 'tool_search_tool_regex',
- });
- break;
- }
-
- case 'anthropic.tool_search_bm25_20251119': {
- anthropicTools.push({
- type: 'tool_search_tool_bm25_20251119',
- name: 'tool_search_tool_bm25',
- });
- break;
- }
-
- default: {
- toolWarnings.push({
- type: 'unsupported',
- feature: `provider-defined tool ${tool.id}`,
- });
- break;
- }
- }
- break;
- }
-
- default: {
- toolWarnings.push({
- type: 'unsupported',
- feature: `tool ${tool}`,
- });
- break;
- }
- }
- }
-
- if (toolChoice == null) {
- return {
- tools: anthropicTools,
- toolChoice: disableParallelToolUse
- ? { type: 'auto', disable_parallel_tool_use: disableParallelToolUse }
- : undefined,
- toolWarnings,
- betas,
- };
- }
-
- const type = toolChoice.type;
-
- switch (type) {
- case 'auto':
- return {
- tools: anthropicTools,
- toolChoice: {
- type: 'auto',
- disable_parallel_tool_use: disableParallelToolUse,
- },
- toolWarnings,
- betas,
- };
- case 'required':
- return {
- tools: anthropicTools,
- toolChoice: {
- type: 'any',
- disable_parallel_tool_use: disableParallelToolUse,
- },
- toolWarnings,
- betas,
- };
- case 'none':
- // Anthropic does not support 'none' tool choice, so we remove the tools:
- return { tools: undefined, toolChoice: undefined, toolWarnings, betas };
- case 'tool':
- return {
- tools: anthropicTools,
- toolChoice: {
- type: 'tool',
- name: toolChoice.toolName,
- disable_parallel_tool_use: disableParallelToolUse,
- },
- toolWarnings,
- betas,
- };
- default: {
- const _exhaustiveCheck: never = type;
- throw new UnsupportedFunctionalityError({
- functionality: `tool choice type: ${_exhaustiveCheck}`,
- });
- }
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-provider.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-provider.ts
deleted file mode 100644
index f77cc3d9f..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-provider.ts
+++ /dev/null
@@ -1,177 +0,0 @@
-import {
- InvalidArgumentError,
- LanguageModelV3,
- NoSuchModelError,
- ProviderV3,
-} from '@ai-sdk/provider';
-import {
- FetchFunction,
- generateId,
- loadApiKey,
- loadOptionalSetting,
- withoutTrailingSlash,
- withUserAgentSuffix,
-} from '@ai-sdk/provider-utils';
-import { VERSION } from './version';
-import { AnthropicMessagesLanguageModel } from './anthropic-messages-language-model';
-import { AnthropicMessagesModelId } from './anthropic-messages-options';
-import { anthropicTools } from './anthropic-tools';
-
-export interface AnthropicProvider extends ProviderV3 {
- /**
- * Creates a model for text generation.
- */
- (modelId: AnthropicMessagesModelId): LanguageModelV3;
-
- /**
- * Creates a model for text generation.
- */
- languageModel(modelId: AnthropicMessagesModelId): LanguageModelV3;
-
- chat(modelId: AnthropicMessagesModelId): LanguageModelV3;
-
- messages(modelId: AnthropicMessagesModelId): LanguageModelV3;
-
- /**
- * @deprecated Use `embeddingModel` instead.
- */
- textEmbeddingModel(modelId: string): never;
-
- /**
- * Anthropic-specific computer use tool.
- */
- tools: typeof anthropicTools;
-}
-
-export interface AnthropicProviderSettings {
- /**
- * Use a different URL prefix for API calls, e.g. to use proxy servers.
- * The default prefix is `https://api.anthropic.com/v1`.
- */
- baseURL?: string;
-
- /**
- * API key that is being send using the `x-api-key` header.
- * It defaults to the `ANTHROPIC_API_KEY` environment variable.
- * Only one of `apiKey` or `authToken` is required.
- */
- apiKey?: string;
-
- /**
- * Auth token that is being sent using the `Authorization: Bearer` header.
- * It defaults to the `ANTHROPIC_AUTH_TOKEN` environment variable.
- * Only one of `apiKey` or `authToken` is required.
- */
- authToken?: string;
-
- /**
- * Custom headers to include in the requests.
- */
- headers?: Record;
-
- /**
- * Custom fetch implementation. You can use it as a middleware to intercept requests,
- * or to provide a custom fetch implementation for e.g. testing.
- */
- fetch?: FetchFunction;
-
- generateId?: () => string;
-
- /**
- * Custom provider name
- * Defaults to 'anthropic.messages'.
- */
- name?: string;
-}
-
-/**
- * Create an Anthropic provider instance.
- */
-export function createAnthropic(
- options: AnthropicProviderSettings = {},
-): AnthropicProvider {
- const baseURL =
- withoutTrailingSlash(
- loadOptionalSetting({
- settingValue: options.baseURL,
- environmentVariableName: 'ANTHROPIC_BASE_URL',
- }),
- ) ?? 'https://api.anthropic.com/v1';
-
- const providerName = options.name ?? 'anthropic.messages';
-
- // Only error if both are explicitly provided in options
- if (options.apiKey && options.authToken) {
- throw new InvalidArgumentError({
- argument: 'apiKey/authToken',
- message:
- 'Both apiKey and authToken were provided. Please use only one authentication method.',
- });
- }
-
- const getHeaders = () => {
- const authHeaders: Record = options.authToken
- ? { Authorization: `Bearer ${options.authToken}` }
- : {
- 'x-api-key': loadApiKey({
- apiKey: options.apiKey,
- environmentVariableName: 'ANTHROPIC_API_KEY',
- description: 'Anthropic',
- }),
- };
-
- return withUserAgentSuffix(
- {
- 'anthropic-version': '2023-06-01',
- ...authHeaders,
- ...options.headers,
- },
- `ai-sdk/anthropic/${VERSION}`,
- );
- };
-
- const createChatModel = (modelId: AnthropicMessagesModelId) =>
- new AnthropicMessagesLanguageModel(modelId, {
- provider: providerName,
- baseURL,
- headers: getHeaders,
- fetch: options.fetch,
- generateId: options.generateId ?? generateId,
- supportedUrls: () => ({
- 'image/*': [/^https?:\/\/.*$/],
- 'application/pdf': [/^https?:\/\/.*$/],
- }),
- });
-
- const provider = function (modelId: AnthropicMessagesModelId) {
- if (new.target) {
- throw new Error(
- 'The Anthropic model function cannot be called with the new keyword.',
- );
- }
-
- return createChatModel(modelId);
- };
-
- provider.specificationVersion = 'v3' as const;
- provider.languageModel = createChatModel;
- provider.chat = createChatModel;
- provider.messages = createChatModel;
-
- provider.embeddingModel = (modelId: string) => {
- throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' });
- };
- provider.textEmbeddingModel = provider.embeddingModel;
- provider.imageModel = (modelId: string) => {
- throw new NoSuchModelError({ modelId, modelType: 'imageModel' });
- };
-
- provider.tools = anthropicTools;
-
- return provider;
-}
-
-/**
- * Default Anthropic provider instance.
- */
-export const anthropic = createAnthropic();
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-tools.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-tools.ts
deleted file mode 100644
index d3f62d812..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/anthropic-tools.ts
+++ /dev/null
@@ -1,238 +0,0 @@
-import { bash_20241022 } from './tool/bash_20241022';
-import { bash_20250124 } from './tool/bash_20250124';
-import { codeExecution_20250522 } from './tool/code-execution_20250522';
-import { codeExecution_20250825 } from './tool/code-execution_20250825';
-import { codeExecution_20260120 } from './tool/code-execution_20260120';
-import { computer_20241022 } from './tool/computer_20241022';
-import { computer_20250124 } from './tool/computer_20250124';
-import { computer_20251124 } from './tool/computer_20251124';
-import { memory_20250818 } from './tool/memory_20250818';
-import { textEditor_20241022 } from './tool/text-editor_20241022';
-import { textEditor_20250124 } from './tool/text-editor_20250124';
-import { textEditor_20250429 } from './tool/text-editor_20250429';
-import { textEditor_20250728 } from './tool/text-editor_20250728';
-import { toolSearchBm25_20251119 } from './tool/tool-search-bm25_20251119';
-import { toolSearchRegex_20251119 } from './tool/tool-search-regex_20251119';
-import { webFetch_20260209 } from './tool/web-fetch-20260209';
-import { webFetch_20250910 } from './tool/web-fetch-20250910';
-import { webSearch_20260209 } from './tool/web-search_20260209';
-import { webSearch_20250305 } from './tool/web-search_20250305';
-
-export const anthropicTools = {
- /**
- * The bash tool enables Claude to execute shell commands in a persistent bash session,
- * allowing system operations, script execution, and command-line automation.
- *
- * Image results are supported.
- */
- bash_20241022,
-
- /**
- * The bash tool enables Claude to execute shell commands in a persistent bash session,
- * allowing system operations, script execution, and command-line automation.
- *
- * Image results are supported.
- */
- bash_20250124,
-
- /**
- * Claude can analyze data, create visualizations, perform complex calculations,
- * run system commands, create and edit files, and process uploaded files directly within
- * the API conversation.
- *
- * The code execution tool allows Claude to run Bash commands and manipulate files,
- * including writing code, in a secure, sandboxed environment.
- */
- codeExecution_20250522,
-
- /**
- * Claude can analyze data, create visualizations, perform complex calculations,
- * run system commands, create and edit files, and process uploaded files directly within
- * the API conversation.
- *
- * The code execution tool allows Claude to run both Python and Bash commands and manipulate files,
- * including writing code, in a secure, sandboxed environment.
- *
- * This is the latest version with enhanced Bash support and file operations.
- */
- codeExecution_20250825,
-
- /**
- * Claude can analyze data, create visualizations, perform complex calculations,
- * run system commands, create and edit files, and process uploaded files directly within
- * the API conversation.
- *
- * The code execution tool allows Claude to run both Python and Bash commands and manipulate files,
- * including writing code, in a secure, sandboxed environment.
- *
- * This is the recommended version. Does not require a beta header.
- *
- * Supported models: Claude Opus 4.6, Sonnet 4.6, Sonnet 4.5, Opus 4.5
- */
- codeExecution_20260120,
-
- /**
- * Claude can interact with computer environments through the computer use tool, which
- * provides screenshot capabilities and mouse/keyboard control for autonomous desktop interaction.
- *
- * Image results are supported.
- *
- * @param displayWidthPx - The width of the display being controlled by the model in pixels.
- * @param displayHeightPx - The height of the display being controlled by the model in pixels.
- * @param displayNumber - The display number to control (only relevant for X11 environments). If specified, the tool will be provided a display number in the tool definition.
- */
- computer_20241022,
-
- /**
- * Claude can interact with computer environments through the computer use tool, which
- * provides screenshot capabilities and mouse/keyboard control for autonomous desktop interaction.
- *
- * Image results are supported.
- *
- * @param displayWidthPx - The width of the display being controlled by the model in pixels.
- * @param displayHeightPx - The height of the display being controlled by the model in pixels.
- * @param displayNumber - The display number to control (only relevant for X11 environments). If specified, the tool will be provided a display number in the tool definition.
- */
- computer_20250124,
-
- /**
- * Claude can interact with computer environments through the computer use tool, which
- * provides screenshot capabilities and mouse/keyboard control for autonomous desktop interaction.
- *
- * This version adds the zoom action for detailed screen region inspection.
- *
- * Image results are supported.
- *
- * Supported models: Claude Opus 4.5
- *
- * @param displayWidthPx - The width of the display being controlled by the model in pixels.
- * @param displayHeightPx - The height of the display being controlled by the model in pixels.
- * @param displayNumber - The display number to control (only relevant for X11 environments). If specified, the tool will be provided a display number in the tool definition.
- * @param enableZoom - Enable zoom action. Set to true to allow Claude to zoom into specific screen regions. Default: false.
- */
- computer_20251124,
-
- /**
- * The memory tool enables Claude to store and retrieve information across conversations through a memory file directory.
- * Claude can create, read, update, and delete files that persist between sessions,
- * allowing it to build knowledge over time without keeping everything in the context window.
- * The memory tool operates client-side—you control where and how the data is stored through your own infrastructure.
- *
- * Supported models: Claude Sonnet 4.5, Claude Sonnet 4, Claude Opus 4.1, Claude Opus 4.
- */
- memory_20250818,
-
- /**
- * Claude can use an Anthropic-defined text editor tool to view and modify text files,
- * helping you debug, fix, and improve your code or other text documents. This allows Claude
- * to directly interact with your files, providing hands-on assistance rather than just suggesting changes.
- *
- * Supported models: Claude Sonnet 3.5
- */
- textEditor_20241022,
-
- /**
- * Claude can use an Anthropic-defined text editor tool to view and modify text files,
- * helping you debug, fix, and improve your code or other text documents. This allows Claude
- * to directly interact with your files, providing hands-on assistance rather than just suggesting changes.
- *
- * Supported models: Claude Sonnet 3.7
- */
- textEditor_20250124,
-
- /**
- * Claude can use an Anthropic-defined text editor tool to view and modify text files,
- * helping you debug, fix, and improve your code or other text documents. This allows Claude
- * to directly interact with your files, providing hands-on assistance rather than just suggesting changes.
- *
- * Note: This version does not support the "undo_edit" command.
- *
- * @deprecated Use textEditor_20250728 instead
- */
- textEditor_20250429,
-
- /**
- * Claude can use an Anthropic-defined text editor tool to view and modify text files,
- * helping you debug, fix, and improve your code or other text documents. This allows Claude
- * to directly interact with your files, providing hands-on assistance rather than just suggesting changes.
- *
- * Note: This version does not support the "undo_edit" command and adds optional max_characters parameter.
- *
- * Supported models: Claude Sonnet 4, Opus 4, and Opus 4.1
- *
- * @param maxCharacters - Optional maximum number of characters to view in the file
- */
- textEditor_20250728,
-
- /**
- * Creates a web fetch tool that gives Claude direct access to real-time web content.
- *
- * @param maxUses - The max_uses parameter limits the number of web fetches performed
- * @param allowedDomains - Only fetch from these domains
- * @param blockedDomains - Never fetch from these domains
- * @param citations - Unlike web search where citations are always enabled, citations are optional for web fetch. Set "citations": {"enabled": true} to enable Claude to cite specific passages from fetched documents.
- * @param maxContentTokens - The max_content_tokens parameter limits the amount of content that will be included in the context.
- */
- webFetch_20250910,
-
- /**
- * Creates a web fetch tool that gives Claude direct access to real-time web content.
- *
- * @param maxUses - The max_uses parameter limits the number of web fetches performed
- * @param allowedDomains - Only fetch from these domains
- * @param blockedDomains - Never fetch from these domains
- * @param citations - Unlike web search where citations are always enabled, citations are optional for web fetch. Set "citations": {"enabled": true} to enable Claude to cite specific passages from fetched documents.
- * @param maxContentTokens - The max_content_tokens parameter limits the amount of content that will be included in the context.
- */
- webFetch_20260209,
-
- /**
- * Creates a web search tool that gives Claude direct access to real-time web content.
- *
- * @param maxUses - Maximum number of web searches Claude can perform during the conversation.
- * @param allowedDomains - Optional list of domains that Claude is allowed to search.
- * @param blockedDomains - Optional list of domains that Claude should avoid when searching.
- * @param userLocation - Optional user location information to provide geographically relevant search results.
- */
- webSearch_20250305,
-
- /**
- * Creates a web search tool that gives Claude direct access to real-time web content.
- *
- * @param maxUses - Maximum number of web searches Claude can perform during the conversation.
- * @param allowedDomains - Optional list of domains that Claude is allowed to search.
- * @param blockedDomains - Optional list of domains that Claude should avoid when searching.
- * @param userLocation - Optional user location information to provide geographically relevant search results.
- */
- webSearch_20260209,
-
- /**
- * Creates a tool search tool that uses regex patterns to find tools.
- *
- * The tool search tool enables Claude to work with hundreds or thousands of tools
- * by dynamically discovering and loading them on-demand. Instead of loading all
- * tool definitions into the context window upfront, Claude searches your tool
- * catalog and loads only the tools it needs.
- *
- * Use `providerOptions: { anthropic: { deferLoading: true } }` on other tools
- * to mark them for deferred loading.
- *
- * Supported models: Claude Opus 4.5, Claude Sonnet 4.5
- */
- toolSearchRegex_20251119,
-
- /**
- * Creates a tool search tool that uses BM25 (natural language) to find tools.
- *
- * The tool search tool enables Claude to work with hundreds or thousands of tools
- * by dynamically discovering and loading them on-demand. Instead of loading all
- * tool definitions into the context window upfront, Claude searches your tool
- * catalog and loads only the tools it needs.
- *
- * Use `providerOptions: { anthropic: { deferLoading: true } }` on other tools
- * to mark them for deferred loading.
- *
- * Supported models: Claude Opus 4.5, Claude Sonnet 4.5
- */
- toolSearchBm25_20251119,
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/convert-anthropic-messages-usage.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/convert-anthropic-messages-usage.ts
deleted file mode 100644
index 679629448..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/convert-anthropic-messages-usage.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-import { JSONObject, LanguageModelV3Usage } from '@ai-sdk/provider';
-
-/**
- * Represents a single iteration in the usage breakdown.
- * When compaction occurs, the API returns an iterations array showing
- * usage for each sampling iteration (compaction + message).
- */
-export type AnthropicUsageIteration = {
- type: 'compaction' | 'message';
- input_tokens: number;
- output_tokens: number;
-};
-
-export type AnthropicMessagesUsage = {
- input_tokens: number;
- output_tokens: number;
- cache_creation_input_tokens?: number | null;
- cache_read_input_tokens?: number | null;
- /**
- * When compaction is triggered, this array contains usage for each
- * sampling iteration. The top-level input_tokens and output_tokens
- * do NOT include compaction iteration usage - to get total tokens
- * consumed and billed, sum across all entries in this array.
- */
- iterations?: AnthropicUsageIteration[] | null;
-};
-
-export function convertAnthropicMessagesUsage({
- usage,
- rawUsage,
-}: {
- usage: AnthropicMessagesUsage;
- rawUsage?: JSONObject;
-}): LanguageModelV3Usage {
- const cacheCreationTokens = usage.cache_creation_input_tokens ?? 0;
- const cacheReadTokens = usage.cache_read_input_tokens ?? 0;
-
- // When iterations is present (compaction occurred), sum across all iterations
- // to get the true total tokens consumed/billed. The top-level input_tokens
- // and output_tokens exclude compaction iteration usage.
- let inputTokens: number;
- let outputTokens: number;
-
- if (usage.iterations && usage.iterations.length > 0) {
- const totals = usage.iterations.reduce(
- (acc, iter) => ({
- input: acc.input + iter.input_tokens,
- output: acc.output + iter.output_tokens,
- }),
- { input: 0, output: 0 },
- );
- inputTokens = totals.input;
- outputTokens = totals.output;
- } else {
- inputTokens = usage.input_tokens;
- outputTokens = usage.output_tokens;
- }
-
- return {
- inputTokens: {
- total: inputTokens + cacheCreationTokens + cacheReadTokens,
- noCache: inputTokens,
- cacheRead: cacheReadTokens,
- cacheWrite: cacheCreationTokens,
- },
- outputTokens: {
- total: outputTokens,
- text: undefined,
- reasoning: undefined,
- },
- raw: rawUsage ?? usage,
- };
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/convert-to-anthropic-messages-prompt.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/convert-to-anthropic-messages-prompt.ts
deleted file mode 100644
index 610ad1cb5..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/convert-to-anthropic-messages-prompt.ts
+++ /dev/null
@@ -1,1119 +0,0 @@
-import {
- SharedV3Warning,
- LanguageModelV3DataContent,
- LanguageModelV3Message,
- LanguageModelV3Prompt,
- SharedV3ProviderMetadata,
- UnsupportedFunctionalityError,
-} from '@ai-sdk/provider';
-import {
- convertBase64ToUint8Array,
- convertToBase64,
- parseProviderOptions,
- validateTypes,
- isNonNullable,
- ToolNameMapping,
-} from '@ai-sdk/provider-utils';
-import {
- AnthropicAssistantMessage,
- AnthropicMessagesPrompt,
- anthropicReasoningMetadataSchema,
- AnthropicToolResultContent,
- AnthropicUserMessage,
- AnthropicWebFetchToolResultContent,
-} from './anthropic-messages-api';
-import { anthropicFilePartProviderOptions } from './anthropic-messages-options';
-import { CacheControlValidator } from './get-cache-control';
-import { codeExecution_20250522OutputSchema } from './tool/code-execution_20250522';
-import { codeExecution_20250825OutputSchema } from './tool/code-execution_20250825';
-import { codeExecution_20260120OutputSchema } from './tool/code-execution_20260120';
-import { toolSearchRegex_20251119OutputSchema as toolSearchOutputSchema } from './tool/tool-search-regex_20251119';
-import { webFetch_20250910OutputSchema } from './tool/web-fetch-20250910';
-import { webSearch_20250305OutputSchema } from './tool/web-search_20250305';
-
-function convertToString(data: LanguageModelV3DataContent): string {
- if (typeof data === 'string') {
- return new TextDecoder().decode(convertBase64ToUint8Array(data));
- }
-
- if (data instanceof Uint8Array) {
- return new TextDecoder().decode(data);
- }
-
- if (data instanceof URL) {
- throw new UnsupportedFunctionalityError({
- functionality: 'URL-based text documents are not supported for citations',
- });
- }
-
- throw new UnsupportedFunctionalityError({
- functionality: `unsupported data type for text documents: ${typeof data}`,
- });
-}
-
-/**
- * Checks if data is a URL (either a URL object or a URL string).
- */
-function isUrlData(
- data: LanguageModelV3DataContent,
-): data is URL | (string & { __brand: 'url-string' }) {
- return data instanceof URL || isUrlString(data);
-}
-
-function isUrlString(data: LanguageModelV3DataContent): boolean {
- return typeof data === 'string' && /^https?:\/\//i.test(data);
-}
-
-function getUrlString(data: LanguageModelV3DataContent): string {
- return data instanceof URL ? data.toString() : (data as string);
-}
-
-export async function convertToAnthropicMessagesPrompt({
- prompt,
- sendReasoning,
- warnings,
- cacheControlValidator,
- toolNameMapping,
-}: {
- prompt: LanguageModelV3Prompt;
- sendReasoning: boolean;
- warnings: SharedV3Warning[];
- cacheControlValidator?: CacheControlValidator;
- toolNameMapping: ToolNameMapping;
-}): Promise<{
- prompt: AnthropicMessagesPrompt;
- betas: Set;
-}> {
- const betas = new Set();
- const blocks = groupIntoBlocks(prompt);
- const validator = cacheControlValidator || new CacheControlValidator();
-
- let system: AnthropicMessagesPrompt['system'] = undefined;
- const messages: AnthropicMessagesPrompt['messages'] = [];
-
- async function shouldEnableCitations(
- providerMetadata: SharedV3ProviderMetadata | undefined,
- ): Promise {
- const anthropicOptions = await parseProviderOptions({
- provider: 'anthropic',
- providerOptions: providerMetadata,
- schema: anthropicFilePartProviderOptions,
- });
-
- return anthropicOptions?.citations?.enabled ?? false;
- }
-
- async function getDocumentMetadata(
- providerMetadata: SharedV3ProviderMetadata | undefined,
- ): Promise<{ title?: string; context?: string }> {
- const anthropicOptions = await parseProviderOptions({
- provider: 'anthropic',
- providerOptions: providerMetadata,
- schema: anthropicFilePartProviderOptions,
- });
-
- return {
- title: anthropicOptions?.title,
- context: anthropicOptions?.context,
- };
- }
-
- for (let i = 0; i < blocks.length; i++) {
- const block = blocks[i];
- const isLastBlock = i === blocks.length - 1;
- const type = block.type;
-
- switch (type) {
- case 'system': {
- if (system != null) {
- throw new UnsupportedFunctionalityError({
- functionality:
- 'Multiple system messages that are separated by user/assistant messages',
- });
- }
-
- system = block.messages.map(({ content, providerOptions }) => ({
- type: 'text',
- text: content,
- cache_control: validator.getCacheControl(providerOptions, {
- type: 'system message',
- canCache: true,
- }),
- }));
-
- break;
- }
-
- case 'user': {
- // combines all user and tool messages in this block into a single message:
- const anthropicContent: AnthropicUserMessage['content'] = [];
-
- for (const message of block.messages) {
- const { role, content } = message;
- switch (role) {
- case 'user': {
- for (let j = 0; j < content.length; j++) {
- const part = content[j];
-
- // cache control: first add cache control from part.
- // for the last part of a message,
- // check also if the message has cache control.
- const isLastPart = j === content.length - 1;
-
- const cacheControl =
- validator.getCacheControl(part.providerOptions, {
- type: 'user message part',
- canCache: true,
- }) ??
- (isLastPart
- ? validator.getCacheControl(message.providerOptions, {
- type: 'user message',
- canCache: true,
- })
- : undefined);
-
- switch (part.type) {
- case 'text': {
- anthropicContent.push({
- type: 'text',
- text: part.text,
- cache_control: cacheControl,
- });
- break;
- }
-
- case 'file': {
- if (part.mediaType.startsWith('image/')) {
- anthropicContent.push({
- type: 'image',
- source: isUrlData(part.data)
- ? {
- type: 'url',
- url: getUrlString(part.data),
- }
- : {
- type: 'base64',
- media_type:
- part.mediaType === 'image/*'
- ? 'image/jpeg'
- : part.mediaType,
- data: convertToBase64(part.data),
- },
- cache_control: cacheControl,
- });
- } else if (part.mediaType === 'application/pdf') {
- betas.add('pdfs-2024-09-25');
-
- const enableCitations = await shouldEnableCitations(
- part.providerOptions,
- );
-
- const metadata = await getDocumentMetadata(
- part.providerOptions,
- );
-
- anthropicContent.push({
- type: 'document',
- source: isUrlData(part.data)
- ? {
- type: 'url',
- url: getUrlString(part.data),
- }
- : {
- type: 'base64',
- media_type: 'application/pdf',
- data: convertToBase64(part.data),
- },
- title: metadata.title ?? part.filename,
- ...(metadata.context && { context: metadata.context }),
- ...(enableCitations && {
- citations: { enabled: true },
- }),
- cache_control: cacheControl,
- });
- } else if (part.mediaType === 'text/plain') {
- const enableCitations = await shouldEnableCitations(
- part.providerOptions,
- );
-
- const metadata = await getDocumentMetadata(
- part.providerOptions,
- );
-
- anthropicContent.push({
- type: 'document',
- source: isUrlData(part.data)
- ? {
- type: 'url',
- url: getUrlString(part.data),
- }
- : {
- type: 'text',
- media_type: 'text/plain',
- data: convertToString(part.data),
- },
- title: metadata.title ?? part.filename,
- ...(metadata.context && { context: metadata.context }),
- ...(enableCitations && {
- citations: { enabled: true },
- }),
- cache_control: cacheControl,
- });
- } else {
- throw new UnsupportedFunctionalityError({
- functionality: `media type: ${part.mediaType}`,
- });
- }
-
- break;
- }
- }
- }
-
- break;
- }
- case 'tool': {
- for (let i = 0; i < content.length; i++) {
- const part = content[i];
-
- if (part.type === 'tool-approval-response') {
- continue;
- }
-
- // cache control: first add cache control from part.
- // for the last part of a message,
- // check also if the message has cache control.
- const isLastPart = i === content.length - 1;
-
- const cacheControl =
- validator.getCacheControl(part.providerOptions, {
- type: 'tool result part',
- canCache: true,
- }) ??
- (isLastPart
- ? validator.getCacheControl(message.providerOptions, {
- type: 'tool result message',
- canCache: true,
- })
- : undefined);
-
- const output = part.output;
- let contentValue: AnthropicToolResultContent['content'];
- switch (output.type) {
- case 'content':
- contentValue = output.value
- .map(contentPart => {
- switch (contentPart.type) {
- case 'text':
- return {
- type: 'text' as const,
- text: contentPart.text,
- };
- case 'image-data': {
- return {
- type: 'image' as const,
- source: {
- type: 'base64' as const,
- media_type: contentPart.mediaType,
- data: contentPart.data,
- },
- };
- }
- case 'image-url': {
- return {
- type: 'image' as const,
- source: {
- type: 'url' as const,
- url: contentPart.url,
- },
- };
- }
- case 'file-url': {
- return {
- type: 'document' as const,
- source: {
- type: 'url' as const,
- url: contentPart.url,
- },
- };
- }
- case 'file-data': {
- if (contentPart.mediaType === 'application/pdf') {
- betas.add('pdfs-2024-09-25');
- return {
- type: 'document' as const,
- source: {
- type: 'base64' as const,
- media_type: contentPart.mediaType,
- data: contentPart.data,
- },
- };
- }
-
- warnings.push({
- type: 'other',
- message: `unsupported tool content part type: ${contentPart.type} with media type: ${contentPart.mediaType}`,
- });
-
- return undefined;
- }
- case 'custom': {
- const anthropicOptions = contentPart.providerOptions
- ?.anthropic as
- | { type: string; toolName?: string }
- | undefined;
- if (anthropicOptions?.type === 'tool-reference') {
- return {
- type: 'tool_reference' as const,
- tool_name: anthropicOptions.toolName!,
- };
- }
- warnings.push({
- type: 'other',
- message: `unsupported custom tool content part`,
- });
- return undefined;
- }
- default: {
- warnings.push({
- type: 'other',
- message: `unsupported tool content part type: ${contentPart.type}`,
- });
-
- return undefined;
- }
- }
- })
- .filter(isNonNullable);
- break;
- case 'text':
- case 'error-text':
- contentValue = output.value;
- break;
- case 'execution-denied':
- contentValue = output.reason ?? 'Tool execution denied.';
- break;
- case 'json':
- case 'error-json':
- default:
- contentValue = JSON.stringify(output.value);
- break;
- }
-
- anthropicContent.push({
- type: 'tool_result',
- tool_use_id: part.toolCallId,
- content: contentValue,
- is_error:
- output.type === 'error-text' || output.type === 'error-json'
- ? true
- : undefined,
- cache_control: cacheControl,
- });
- }
-
- break;
- }
- default: {
- const _exhaustiveCheck: never = role;
- throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
- }
- }
- }
-
- messages.push({ role: 'user', content: anthropicContent });
-
- break;
- }
-
- case 'assistant': {
- // combines multiple assistant messages in this block into a single message:
- const anthropicContent: AnthropicAssistantMessage['content'] = [];
-
- const mcpToolUseIds = new Set();
-
- for (let j = 0; j < block.messages.length; j++) {
- const message = block.messages[j];
- const isLastMessage = j === block.messages.length - 1;
- const { content } = message;
-
- for (let k = 0; k < content.length; k++) {
- const part = content[k];
- const isLastContentPart = k === content.length - 1;
-
- // cache control: first add cache control from part.
- // for the last part of a message,
- // check also if the message has cache control.
- const cacheControl =
- validator.getCacheControl(part.providerOptions, {
- type: 'assistant message part',
- canCache: true,
- }) ??
- (isLastContentPart
- ? validator.getCacheControl(message.providerOptions, {
- type: 'assistant message',
- canCache: true,
- })
- : undefined);
-
- switch (part.type) {
- case 'text': {
- // Check if this is a compaction block (via providerMetadata)
- const textMetadata = part.providerOptions?.anthropic as
- | { type?: string }
- | undefined;
-
- if (textMetadata?.type === 'compaction') {
- anthropicContent.push({
- type: 'compaction',
- content: part.text,
- cache_control: cacheControl,
- });
- } else {
- anthropicContent.push({
- type: 'text',
- text:
- // trim the last text part if it's the last message in the block
- // because Anthropic does not allow trailing whitespace
- // in pre-filled assistant responses
- isLastBlock && isLastMessage && isLastContentPart
- ? part.text.trim()
- : part.text,
-
- cache_control: cacheControl,
- });
- }
- break;
- }
-
- case 'reasoning': {
- if (sendReasoning) {
- const reasoningMetadata = await parseProviderOptions({
- provider: 'anthropic',
- providerOptions: part.providerOptions,
- schema: anthropicReasoningMetadataSchema,
- });
-
- if (reasoningMetadata != null) {
- if (reasoningMetadata.signature != null) {
- // Note: thinking blocks cannot have cache_control directly
- // They are cached implicitly when in previous assistant turns
- // Validate to provide helpful error message
- validator.getCacheControl(part.providerOptions, {
- type: 'thinking block',
- canCache: false,
- });
- anthropicContent.push({
- type: 'thinking',
- thinking: part.text,
- signature: reasoningMetadata.signature,
- });
- } else if (reasoningMetadata.redactedData != null) {
- // Note: redacted thinking blocks cannot have cache_control directly
- // They are cached implicitly when in previous assistant turns
- // Validate to provide helpful error message
- validator.getCacheControl(part.providerOptions, {
- type: 'redacted thinking block',
- canCache: false,
- });
- anthropicContent.push({
- type: 'redacted_thinking',
- data: reasoningMetadata.redactedData,
- });
- } else {
- warnings.push({
- type: 'other',
- message: 'unsupported reasoning metadata',
- });
- }
- } else {
- warnings.push({
- type: 'other',
- message: 'unsupported reasoning metadata',
- });
- }
- } else {
- warnings.push({
- type: 'other',
- message:
- 'sending reasoning content is disabled for this model',
- });
- }
- break;
- }
-
- case 'tool-call': {
- if (part.providerExecuted) {
- const providerToolName = toolNameMapping.toProviderToolName(
- part.toolName,
- );
- const isMcpToolUse =
- part.providerOptions?.anthropic?.type === 'mcp-tool-use';
-
- if (isMcpToolUse) {
- mcpToolUseIds.add(part.toolCallId);
-
- const serverName =
- part.providerOptions?.anthropic?.serverName;
-
- if (serverName == null || typeof serverName !== 'string') {
- warnings.push({
- type: 'other',
- message:
- 'mcp tool use server name is required and must be a string',
- });
- break;
- }
-
- anthropicContent.push({
- type: 'mcp_tool_use',
- id: part.toolCallId,
- name: part.toolName,
- input: part.input,
- server_name: serverName,
- cache_control: cacheControl,
- });
- } else if (
- // code execution 20250825:
- providerToolName === 'code_execution' &&
- part.input != null &&
- typeof part.input === 'object' &&
- 'type' in part.input &&
- typeof part.input.type === 'string' &&
- (part.input.type === 'bash_code_execution' ||
- part.input.type === 'text_editor_code_execution')
- ) {
- anthropicContent.push({
- type: 'server_tool_use',
- id: part.toolCallId,
- name: part.input.type, // map back to subtool name
- input: part.input,
- cache_control: cacheControl,
- });
- } else if (
- // code execution 20250825 programmatic tool calling:
- // Strip the fake 'programmatic-tool-call' type before sending to Anthropic
- providerToolName === 'code_execution' &&
- part.input != null &&
- typeof part.input === 'object' &&
- 'type' in part.input &&
- part.input.type === 'programmatic-tool-call'
- ) {
- const { type: _, ...inputWithoutType } = part.input as {
- type: string;
- code: string;
- };
- anthropicContent.push({
- type: 'server_tool_use',
- id: part.toolCallId,
- name: 'code_execution',
- input: inputWithoutType,
- cache_control: cacheControl,
- });
- } else {
- if (
- providerToolName === 'code_execution' || // code execution 20250522
- providerToolName === 'web_fetch' ||
- providerToolName === 'web_search'
- ) {
- anthropicContent.push({
- type: 'server_tool_use',
- id: part.toolCallId,
- name: providerToolName,
- input: part.input,
- cache_control: cacheControl,
- });
- } else if (
- providerToolName === 'tool_search_tool_regex' ||
- providerToolName === 'tool_search_tool_bm25'
- ) {
- anthropicContent.push({
- type: 'server_tool_use',
- id: part.toolCallId,
- name: providerToolName,
- input: part.input,
- cache_control: cacheControl,
- });
- } else {
- warnings.push({
- type: 'other',
- message: `provider executed tool call for tool ${part.toolName} is not supported`,
- });
- }
- }
-
- break;
- }
-
- // Extract caller info from provider options for programmatic tool calling
- const callerOptions = part.providerOptions?.anthropic as
- | { caller?: { type: string; toolId?: string } }
- | undefined;
- const caller = callerOptions?.caller
- ? (callerOptions.caller.type === 'code_execution_20250825' ||
- callerOptions.caller.type ===
- 'code_execution_20260120') &&
- callerOptions.caller.toolId
- ? {
- type: callerOptions.caller.type as
- | 'code_execution_20250825'
- | 'code_execution_20260120',
- tool_id: callerOptions.caller.toolId,
- }
- : callerOptions.caller.type === 'direct'
- ? { type: 'direct' as const }
- : undefined
- : undefined;
-
- anthropicContent.push({
- type: 'tool_use',
- id: part.toolCallId,
- name: part.toolName,
- input: part.input,
- ...(caller && { caller }),
- cache_control: cacheControl,
- });
- break;
- }
-
- case 'tool-result': {
- const providerToolName = toolNameMapping.toProviderToolName(
- part.toolName,
- );
-
- if (mcpToolUseIds.has(part.toolCallId)) {
- const output = part.output;
-
- if (output.type !== 'json' && output.type !== 'error-json') {
- warnings.push({
- type: 'other',
- message: `provider executed tool result output type ${output.type} for tool ${part.toolName} is not supported`,
- });
-
- break;
- }
-
- anthropicContent.push({
- type: 'mcp_tool_result',
- tool_use_id: part.toolCallId,
- is_error: output.type === 'error-json',
- content: output.value as unknown as
- | string
- | Array<{ type: 'text'; text: string }>,
- cache_control: cacheControl,
- });
- } else if (providerToolName === 'code_execution') {
- const output = part.output;
-
- // Handle error types for code_execution tools (e.g., from programmatic tool calling)
- if (
- output.type === 'error-text' ||
- output.type === 'error-json'
- ) {
- let errorInfo: { type?: string; errorCode?: string } = {};
- try {
- if (typeof output.value === 'string') {
- errorInfo = JSON.parse(output.value);
- } else if (
- typeof output.value === 'object' &&
- output.value !== null
- ) {
- errorInfo = output.value as typeof errorInfo;
- }
- } catch {}
-
- if (errorInfo.type === 'code_execution_tool_result_error') {
- anthropicContent.push({
- type: 'code_execution_tool_result',
- tool_use_id: part.toolCallId,
- content: {
- type: 'code_execution_tool_result_error' as const,
- error_code: errorInfo.errorCode ?? 'unknown',
- },
- cache_control: cacheControl,
- });
- } else {
- anthropicContent.push({
- type: 'bash_code_execution_tool_result',
- tool_use_id: part.toolCallId,
- cache_control: cacheControl,
- content: {
- type: 'bash_code_execution_tool_result_error' as const,
- error_code: errorInfo.errorCode ?? 'unknown',
- },
- });
- }
- break;
- }
-
- if (output.type !== 'json') {
- warnings.push({
- type: 'other',
- message: `provider executed tool result output type ${output.type} for tool ${part.toolName} is not supported`,
- });
-
- break;
- }
-
- if (
- output.value == null ||
- typeof output.value !== 'object' ||
- !('type' in output.value) ||
- typeof output.value.type !== 'string'
- ) {
- warnings.push({
- type: 'other',
- message: `provider executed tool result output value is not a valid code execution result for tool ${part.toolName}`,
- });
- break;
- }
-
- // to distinguish between code execution 20250522, 20250825,
- // and encrypted results (from web_fetch_20260209/web_search_20260209 injection),
- // we check the type property in output.value
- if (output.value.type === 'code_execution_result') {
- // code execution 20250522
- const codeExecutionOutput = await validateTypes({
- value: output.value,
- schema: codeExecution_20250522OutputSchema,
- });
-
- anthropicContent.push({
- type: 'code_execution_tool_result',
- tool_use_id: part.toolCallId,
- content: {
- type: codeExecutionOutput.type,
- stdout: codeExecutionOutput.stdout,
- stderr: codeExecutionOutput.stderr,
- return_code: codeExecutionOutput.return_code,
- content: codeExecutionOutput.content ?? [],
- },
- cache_control: cacheControl,
- });
- } else if (
- output.value.type === 'encrypted_code_execution_result'
- ) {
- // code execution 20260120 encrypted result
- const codeExecutionOutput = await validateTypes({
- value: output.value,
- schema: codeExecution_20260120OutputSchema,
- });
-
- if (
- codeExecutionOutput.type ===
- 'encrypted_code_execution_result'
- ) {
- anthropicContent.push({
- type: 'code_execution_tool_result',
- tool_use_id: part.toolCallId,
- content: {
- type: codeExecutionOutput.type,
- encrypted_stdout:
- codeExecutionOutput.encrypted_stdout,
- stderr: codeExecutionOutput.stderr,
- return_code: codeExecutionOutput.return_code,
- content: codeExecutionOutput.content ?? [],
- },
- cache_control: cacheControl,
- });
- }
- } else {
- // code execution 20250825
- const codeExecutionOutput = await validateTypes({
- value: output.value,
- schema: codeExecution_20250825OutputSchema,
- });
-
- if (codeExecutionOutput.type === 'code_execution_result') {
- anthropicContent.push({
- type: 'code_execution_tool_result',
- tool_use_id: part.toolCallId,
- content: {
- type: codeExecutionOutput.type,
- stdout: codeExecutionOutput.stdout,
- stderr: codeExecutionOutput.stderr,
- return_code: codeExecutionOutput.return_code,
- content: codeExecutionOutput.content ?? [],
- },
- cache_control: cacheControl,
- });
- } else if (
- codeExecutionOutput.type ===
- 'bash_code_execution_result' ||
- codeExecutionOutput.type ===
- 'bash_code_execution_tool_result_error'
- ) {
- anthropicContent.push({
- type: 'bash_code_execution_tool_result',
- tool_use_id: part.toolCallId,
- cache_control: cacheControl,
- content: codeExecutionOutput,
- });
- } else {
- anthropicContent.push({
- type: 'text_editor_code_execution_tool_result',
- tool_use_id: part.toolCallId,
- cache_control: cacheControl,
- content: codeExecutionOutput,
- });
- }
- }
- break;
- }
-
- if (providerToolName === 'web_fetch') {
- const output = part.output;
-
- if (output.type === 'error-json') {
- let errorValue: { errorCode?: string } = {};
- try {
- if (typeof output.value === 'string') {
- errorValue = JSON.parse(output.value);
- } else if (
- typeof output.value === 'object' &&
- output.value !== null
- ) {
- errorValue = output.value as typeof errorValue;
- }
- } catch {
- // If parsing fails, treat the value as-is
- const extractedErrorCode = (
- output.value as Record
- )?.errorCode;
- errorValue = {
- errorCode:
- typeof extractedErrorCode === 'string'
- ? extractedErrorCode
- : 'unavailable',
- };
- }
-
- anthropicContent.push({
- type: 'web_fetch_tool_result',
- tool_use_id: part.toolCallId,
- content: {
- type: 'web_fetch_tool_result_error',
- error_code: errorValue.errorCode ?? 'unavailable',
- },
- cache_control: cacheControl,
- });
-
- break;
- }
-
- if (output.type !== 'json') {
- warnings.push({
- type: 'other',
- message: `provider executed tool result output type ${output.type} for tool ${part.toolName} is not supported`,
- });
-
- break;
- }
-
- // ideally we'd switch schema based on the tool version (e.g.
- // web_fetch_20260209 vs web_fetch_20250910), but since both
- // versions share an identical output schema, we use one here.
- const webFetchOutput = await validateTypes({
- value: output.value,
- schema: webFetch_20250910OutputSchema,
- });
-
- anthropicContent.push({
- type: 'web_fetch_tool_result',
- tool_use_id: part.toolCallId,
- content: {
- type: 'web_fetch_result',
- url: webFetchOutput.url,
- retrieved_at: webFetchOutput.retrievedAt,
- content: {
- type: 'document',
- title: webFetchOutput.content.title,
- citations: webFetchOutput.content.citations,
- source: {
- type: webFetchOutput.content.source.type,
- media_type: webFetchOutput.content.source.mediaType,
- data: webFetchOutput.content.source.data,
- } as Extract<
- AnthropicWebFetchToolResultContent['content'],
- { type: 'web_fetch_result' }
- >['content']['source'],
- },
- },
- cache_control: cacheControl,
- });
-
- break;
- }
-
- if (providerToolName === 'web_search') {
- const output = part.output;
-
- if (output.type !== 'json') {
- warnings.push({
- type: 'other',
- message: `provider executed tool result output type ${output.type} for tool ${part.toolName} is not supported`,
- });
-
- break;
- }
-
- // ideally we'd switch schema based on the tool version (e.g.
- // web_search_20260209 vs web_search_20250305), but since both
- // versions share an identical output schema, we use one here.
- const webSearchOutput = await validateTypes({
- value: output.value,
- schema: webSearch_20250305OutputSchema,
- });
-
- anthropicContent.push({
- type: 'web_search_tool_result',
- tool_use_id: part.toolCallId,
- content: webSearchOutput.map(result => ({
- url: result.url,
- title: result.title,
- page_age: result.pageAge,
- encrypted_content: result.encryptedContent,
- type: result.type,
- })),
- cache_control: cacheControl,
- });
-
- break;
- }
-
- if (
- providerToolName === 'tool_search_tool_regex' ||
- providerToolName === 'tool_search_tool_bm25'
- ) {
- const output = part.output;
-
- if (output.type !== 'json') {
- warnings.push({
- type: 'other',
- message: `provider executed tool result output type ${output.type} for tool ${part.toolName} is not supported`,
- });
-
- break;
- }
-
- const toolSearchOutput = await validateTypes({
- value: output.value,
- schema: toolSearchOutputSchema,
- });
-
- // Convert tool references back to API format
- const toolReferences = toolSearchOutput.map(ref => ({
- type: 'tool_reference' as const,
- tool_name: ref.toolName,
- }));
-
- anthropicContent.push({
- type: 'tool_search_tool_result',
- tool_use_id: part.toolCallId,
- content: {
- type: 'tool_search_tool_search_result',
- tool_references: toolReferences,
- },
- cache_control: cacheControl,
- });
-
- break;
- }
-
- warnings.push({
- type: 'other',
- message: `provider executed tool result for tool ${part.toolName} is not supported`,
- });
-
- break;
- }
- }
- }
- }
-
- messages.push({ role: 'assistant', content: anthropicContent });
-
- break;
- }
-
- default: {
- const _exhaustiveCheck: never = type;
- throw new Error(`content type: ${_exhaustiveCheck}`);
- }
- }
- }
-
- return {
- prompt: { system, messages },
- betas,
- };
-}
-
-type SystemBlock = {
- type: 'system';
- messages: Array;
-};
-type AssistantBlock = {
- type: 'assistant';
- messages: Array;
-};
-type UserBlock = {
- type: 'user';
- messages: Array;
-};
-
-function groupIntoBlocks(
- prompt: LanguageModelV3Prompt,
-): Array {
- const blocks: Array = [];
- let currentBlock: SystemBlock | AssistantBlock | UserBlock | undefined =
- undefined;
-
- for (const message of prompt) {
- const { role } = message;
- switch (role) {
- case 'system': {
- if (currentBlock?.type !== 'system') {
- currentBlock = { type: 'system', messages: [] };
- blocks.push(currentBlock);
- }
-
- currentBlock.messages.push(message);
- break;
- }
- case 'assistant': {
- if (currentBlock?.type !== 'assistant') {
- currentBlock = { type: 'assistant', messages: [] };
- blocks.push(currentBlock);
- }
-
- currentBlock.messages.push(message);
- break;
- }
- case 'user': {
- if (currentBlock?.type !== 'user') {
- currentBlock = { type: 'user', messages: [] };
- blocks.push(currentBlock);
- }
-
- currentBlock.messages.push(message);
- break;
- }
- case 'tool': {
- if (currentBlock?.type !== 'user') {
- currentBlock = { type: 'user', messages: [] };
- blocks.push(currentBlock);
- }
-
- currentBlock.messages.push(message);
- break;
- }
- default: {
- const _exhaustiveCheck: never = role;
- throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
- }
- }
- }
-
- return blocks;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/forward-anthropic-container-id-from-last-step.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/forward-anthropic-container-id-from-last-step.ts
deleted file mode 100644
index c2b356be6..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/forward-anthropic-container-id-from-last-step.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { JSONObject } from '@ai-sdk/provider';
-import { AnthropicMessageMetadata } from './anthropic-message-metadata';
-
-/**
- * Sets the Anthropic container ID in the provider options based on
- * any previous step's provider metadata.
- *
- * Searches backwards through steps to find the most recent container ID.
- * You can use this function in `prepareStep` to forward the container ID between steps.
- */
-export function forwardAnthropicContainerIdFromLastStep({
- steps,
-}: {
- steps: Array<{
- providerMetadata?: Record;
- }>;
-}): undefined | { providerOptions?: Record } {
- // Search backwards through steps to find the most recent container ID
- for (let i = steps.length - 1; i >= 0; i--) {
- const containerId = (
- steps[i].providerMetadata?.anthropic as
- | AnthropicMessageMetadata
- | undefined
- )?.container?.id;
-
- if (containerId) {
- return {
- providerOptions: {
- anthropic: {
- container: { id: containerId },
- },
- },
- };
- }
- }
-
- return undefined;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/get-cache-control.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/get-cache-control.ts
deleted file mode 100644
index 2c3018d83..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/get-cache-control.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import { SharedV3Warning, SharedV3ProviderMetadata } from '@ai-sdk/provider';
-import { AnthropicCacheControl } from './anthropic-messages-api';
-
-// Anthropic allows a maximum of 4 cache breakpoints per request
-const MAX_CACHE_BREAKPOINTS = 4;
-
-// Helper function to extract cache_control from provider metadata
-// Allows both cacheControl and cache_control for flexibility
-function getCacheControl(
- providerMetadata: SharedV3ProviderMetadata | undefined,
-): AnthropicCacheControl | undefined {
- const anthropic = providerMetadata?.anthropic;
-
- // allow both cacheControl and cache_control:
- const cacheControlValue = anthropic?.cacheControl ?? anthropic?.cache_control;
-
- // Pass through value assuming it is of the correct type.
- // The Anthropic API will validate the value.
- return cacheControlValue as AnthropicCacheControl | undefined;
-}
-
-export class CacheControlValidator {
- private breakpointCount = 0;
- private warnings: SharedV3Warning[] = [];
-
- getCacheControl(
- providerMetadata: SharedV3ProviderMetadata | undefined,
- context: { type: string; canCache: boolean },
- ): AnthropicCacheControl | undefined {
- const cacheControlValue = getCacheControl(providerMetadata);
-
- if (!cacheControlValue) {
- return undefined;
- }
-
- // Validate that cache_control is allowed in this context
- if (!context.canCache) {
- this.warnings.push({
- type: 'unsupported',
- feature: 'cache_control on non-cacheable context',
- details: `cache_control cannot be set on ${context.type}. It will be ignored.`,
- });
- return undefined;
- }
-
- // Validate cache breakpoint limit
- this.breakpointCount++;
- if (this.breakpointCount > MAX_CACHE_BREAKPOINTS) {
- this.warnings.push({
- type: 'unsupported',
- feature: 'cacheControl breakpoint limit',
- details: `Maximum ${MAX_CACHE_BREAKPOINTS} cache breakpoints exceeded (found ${this.breakpointCount}). This breakpoint will be ignored.`,
- });
- return undefined;
- }
-
- return cacheControlValue;
- }
-
- getWarnings(): SharedV3Warning[] {
- return this.warnings;
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/index.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/index.ts
deleted file mode 100644
index bb57c24a6..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/index.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-export type {
- AnthropicMessageMetadata,
- AnthropicUsageIteration,
-} from './anthropic-message-metadata';
-export type {
- AnthropicLanguageModelOptions,
- /** @deprecated Use `AnthropicLanguageModelOptions` instead. */
- AnthropicLanguageModelOptions as AnthropicProviderOptions,
-} from './anthropic-messages-options';
-export type { AnthropicToolOptions } from './anthropic-prepare-tools';
-export { anthropic, createAnthropic } from './anthropic-provider';
-export type {
- AnthropicProvider,
- AnthropicProviderSettings,
-} from './anthropic-provider';
-export { forwardAnthropicContainerIdFromLastStep } from './forward-anthropic-container-id-from-last-step';
-export { VERSION } from './version';
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/internal/index.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/internal/index.ts
deleted file mode 100644
index 42804b235..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/internal/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export { AnthropicMessagesLanguageModel } from '../anthropic-messages-language-model';
-export { anthropicTools } from '../anthropic-tools';
-export type { AnthropicMessagesModelId } from '../anthropic-messages-options';
-export { prepareTools } from '../anthropic-prepare-tools';
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/map-anthropic-stop-reason.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/map-anthropic-stop-reason.ts
deleted file mode 100644
index 990690413..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/map-anthropic-stop-reason.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { LanguageModelV3FinishReason } from '@ai-sdk/provider';
-
-/**
- * @see https://docs.anthropic.com/en/api/messages#response-stop-reason
- */
-export function mapAnthropicStopReason({
- finishReason,
- isJsonResponseFromTool,
-}: {
- finishReason: string | null | undefined;
- isJsonResponseFromTool?: boolean;
-}): LanguageModelV3FinishReason['unified'] {
- switch (finishReason) {
- case 'pause_turn':
- case 'end_turn':
- case 'stop_sequence':
- return 'stop';
- case 'refusal':
- return 'content-filter';
- case 'tool_use':
- return isJsonResponseFromTool ? 'stop' : 'tool-calls';
- case 'max_tokens':
- case 'model_context_window_exceeded':
- return 'length';
- case 'compaction':
- return 'other';
- default:
- return 'other';
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/bash_20241022.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/bash_20241022.ts
deleted file mode 100644
index 74c0fd61f..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/bash_20241022.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import {
- createProviderToolFactory,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-const bash_20241022InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- command: z.string(),
- restart: z.boolean().optional(),
- }),
- ),
-);
-
-export const bash_20241022 = createProviderToolFactory<
- {
- /**
- * The bash command to run. Required unless the tool is being restarted.
- */
- command: string;
-
- /**
- * Specifying true will restart this tool. Otherwise, leave this unspecified.
- */
- restart?: boolean;
- },
- {}
->({
- id: 'anthropic.bash_20241022',
- inputSchema: bash_20241022InputSchema,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/bash_20250124.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/bash_20250124.ts
deleted file mode 100644
index 901d6ff50..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/bash_20250124.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import {
- createProviderToolFactory,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-const bash_20250124InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- command: z.string(),
- restart: z.boolean().optional(),
- }),
- ),
-);
-
-export const bash_20250124 = createProviderToolFactory<
- {
- /**
- * The bash command to run. Required unless the tool is being restarted.
- */
- command: string;
-
- /**
- * Specifying true will restart this tool. Otherwise, leave this unspecified.
- */
- restart?: boolean;
- },
- {}
->({
- id: 'anthropic.bash_20250124',
- inputSchema: bash_20250124InputSchema,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/code-execution_20250522.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/code-execution_20250522.ts
deleted file mode 100644
index 5d92aef0c..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/code-execution_20250522.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const codeExecution_20250522OutputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- type: z.literal('code_execution_result'),
- stdout: z.string(),
- stderr: z.string(),
- return_code: z.number(),
- content: z
- .array(
- z.object({
- type: z.literal('code_execution_output'),
- file_id: z.string(),
- }),
- )
- .optional()
- .default([]),
- }),
- ),
-);
-
-const codeExecution_20250522InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- code: z.string(),
- }),
- ),
-);
-
-const factory = createProviderToolFactoryWithOutputSchema<
- {
- /**
- * The Python code to execute.
- */
- code: string;
- },
- {
- type: 'code_execution_result';
- stdout: string;
- stderr: string;
- return_code: number;
- content: Array<{ type: 'code_execution_output'; file_id: string }>;
- },
- {}
->({
- id: 'anthropic.code_execution_20250522',
- inputSchema: codeExecution_20250522InputSchema,
- outputSchema: codeExecution_20250522OutputSchema,
-});
-
-export const codeExecution_20250522 = (
- args: Parameters[0] = {},
-) => {
- return factory(args);
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/code-execution_20250825.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/code-execution_20250825.ts
deleted file mode 100644
index 30a21e73c..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/code-execution_20250825.ts
+++ /dev/null
@@ -1,281 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const codeExecution_20250825OutputSchema = lazySchema(() =>
- zodSchema(
- z.discriminatedUnion('type', [
- z.object({
- type: z.literal('code_execution_result'),
- stdout: z.string(),
- stderr: z.string(),
- return_code: z.number(),
- content: z
- .array(
- z.object({
- type: z.literal('code_execution_output'),
- file_id: z.string(),
- }),
- )
- .optional()
- .default([]),
- }),
- z.object({
- type: z.literal('bash_code_execution_result'),
- content: z.array(
- z.object({
- type: z.literal('bash_code_execution_output'),
- file_id: z.string(),
- }),
- ),
- stdout: z.string(),
- stderr: z.string(),
- return_code: z.number(),
- }),
- z.object({
- type: z.literal('bash_code_execution_tool_result_error'),
- error_code: z.string(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution_tool_result_error'),
- error_code: z.string(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution_view_result'),
- content: z.string(),
- file_type: z.string(),
- num_lines: z.number().nullable(),
- start_line: z.number().nullable(),
- total_lines: z.number().nullable(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution_create_result'),
- is_file_update: z.boolean(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution_str_replace_result'),
- lines: z.array(z.string()).nullable(),
- new_lines: z.number().nullable(),
- new_start: z.number().nullable(),
- old_lines: z.number().nullable(),
- old_start: z.number().nullable(),
- }),
- ]),
- ),
-);
-
-export const codeExecution_20250825InputSchema = lazySchema(() =>
- zodSchema(
- z.discriminatedUnion('type', [
- // Programmatic tool calling format (mapped from { code } by AI SDK)
- z.object({
- type: z.literal('programmatic-tool-call'),
- code: z.string(),
- }),
- z.object({
- type: z.literal('bash_code_execution'),
- command: z.string(),
- }),
- z.discriminatedUnion('command', [
- z.object({
- type: z.literal('text_editor_code_execution'),
- command: z.literal('view'),
- path: z.string(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution'),
- command: z.literal('create'),
- path: z.string(),
- file_text: z.string().nullish(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution'),
- command: z.literal('str_replace'),
- path: z.string(),
- old_str: z.string(),
- new_str: z.string(),
- }),
- ]),
- ]),
- ),
-);
-
-const factory = createProviderToolFactoryWithOutputSchema<
- | {
- type: 'programmatic-tool-call';
- /**
- * Programmatic tool calling: Python code to execute when code_execution
- * is used with allowedCallers to trigger client-executed tools.
- */
- code: string;
- }
- | {
- type: 'bash_code_execution';
-
- /**
- * Shell command to execute.
- */
- command: string;
- }
- | {
- type: 'text_editor_code_execution';
- command: 'view';
-
- /**
- * The path to the file to view.
- */
- path: string;
- }
- | {
- type: 'text_editor_code_execution';
- command: 'create';
-
- /**
- * The path to the file to edit.
- */
- path: string;
-
- /**
- * The text of the file to edit.
- */
- file_text?: string | null;
- }
- | {
- type: 'text_editor_code_execution';
- command: 'str_replace';
-
- /**
- * The path to the file to edit.
- */
- path: string;
-
- /**
- * The string to replace.
- */
- old_str: string;
-
- /**
- * The new string to replace the old string with.
- */
- new_str: string;
- },
- | {
- /**
- * Programmatic tool calling result: returned when code_execution runs code
- * that calls client-executed tools via allowedCallers.
- */
- type: 'code_execution_result';
-
- /**
- * Output from successful execution
- */
- stdout: string;
-
- /**
- * Error messages if execution fails
- */
- stderr: string;
-
- /**
- * 0 for success, non-zero for failure
- */
- return_code: number;
-
- /**
- * Output file Id list
- */
- content: Array<{ type: 'code_execution_output'; file_id: string }>;
- }
- | {
- type: 'bash_code_execution_result';
-
- /**
- * Output file Id list
- */
- content: Array<{
- type: 'bash_code_execution_output';
- file_id: string;
- }>;
-
- /**
- * Output from successful execution
- */
- stdout: string;
-
- /**
- * Error messages if execution fails
- */
- stderr: string;
-
- /**
- * 0 for success, non-zero for failure
- */
- return_code: number;
- }
- | {
- type: 'bash_code_execution_tool_result_error';
-
- /**
- * Available options: invalid_tool_input, unavailable, too_many_requests,
- * execution_time_exceeded, output_file_too_large.
- */
- error_code: string;
- }
- | {
- type: 'text_editor_code_execution_tool_result_error';
-
- /**
- * Available options: invalid_tool_input, unavailable, too_many_requests,
- * execution_time_exceeded, file_not_found.
- */
- error_code: string;
- }
- | {
- type: 'text_editor_code_execution_view_result';
-
- content: string;
-
- /**
- * The type of the file. Available options: text, image, pdf.
- */
- file_type: string;
-
- num_lines: number | null;
- start_line: number | null;
- total_lines: number | null;
- }
- | {
- type: 'text_editor_code_execution_create_result';
-
- is_file_update: boolean;
- }
- | {
- type: 'text_editor_code_execution_str_replace_result';
-
- lines: string[] | null;
- new_lines: number | null;
- new_start: number | null;
- old_lines: number | null;
- old_start: number | null;
- },
- {
- // no arguments
- }
->({
- id: 'anthropic.code_execution_20250825',
- inputSchema: codeExecution_20250825InputSchema,
- outputSchema: codeExecution_20250825OutputSchema,
- // Programmatic tool calling: tool results may be deferred to a later turn
- // when code execution triggers a client-executed tool that needs to be
- // resolved before the code execution result can be returned.
- supportsDeferredResults: true,
-});
-
-export const codeExecution_20250825 = (
- args: Parameters[0] = {},
-) => {
- return factory(args);
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/code-execution_20260120.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/code-execution_20260120.ts
deleted file mode 100644
index cfa2e32fa..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/code-execution_20260120.ts
+++ /dev/null
@@ -1,315 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const codeExecution_20260120OutputSchema = lazySchema(() =>
- zodSchema(
- z.discriminatedUnion('type', [
- z.object({
- type: z.literal('code_execution_result'),
- stdout: z.string(),
- stderr: z.string(),
- return_code: z.number(),
- content: z
- .array(
- z.object({
- type: z.literal('code_execution_output'),
- file_id: z.string(),
- }),
- )
- .optional()
- .default([]),
- }),
- z.object({
- type: z.literal('encrypted_code_execution_result'),
- encrypted_stdout: z.string(),
- stderr: z.string(),
- return_code: z.number(),
- content: z
- .array(
- z.object({
- type: z.literal('code_execution_output'),
- file_id: z.string(),
- }),
- )
- .optional()
- .default([]),
- }),
- z.object({
- type: z.literal('bash_code_execution_result'),
- content: z.array(
- z.object({
- type: z.literal('bash_code_execution_output'),
- file_id: z.string(),
- }),
- ),
- stdout: z.string(),
- stderr: z.string(),
- return_code: z.number(),
- }),
- z.object({
- type: z.literal('bash_code_execution_tool_result_error'),
- error_code: z.string(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution_tool_result_error'),
- error_code: z.string(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution_view_result'),
- content: z.string(),
- file_type: z.string(),
- num_lines: z.number().nullable(),
- start_line: z.number().nullable(),
- total_lines: z.number().nullable(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution_create_result'),
- is_file_update: z.boolean(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution_str_replace_result'),
- lines: z.array(z.string()).nullable(),
- new_lines: z.number().nullable(),
- new_start: z.number().nullable(),
- old_lines: z.number().nullable(),
- old_start: z.number().nullable(),
- }),
- ]),
- ),
-);
-
-export const codeExecution_20260120InputSchema = lazySchema(() =>
- zodSchema(
- z.discriminatedUnion('type', [
- z.object({
- type: z.literal('programmatic-tool-call'),
- code: z.string(),
- }),
- z.object({
- type: z.literal('bash_code_execution'),
- command: z.string(),
- }),
- z.discriminatedUnion('command', [
- z.object({
- type: z.literal('text_editor_code_execution'),
- command: z.literal('view'),
- path: z.string(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution'),
- command: z.literal('create'),
- path: z.string(),
- file_text: z.string().nullish(),
- }),
- z.object({
- type: z.literal('text_editor_code_execution'),
- command: z.literal('str_replace'),
- path: z.string(),
- old_str: z.string(),
- new_str: z.string(),
- }),
- ]),
- ]),
- ),
-);
-
-const factory = createProviderToolFactoryWithOutputSchema<
- | {
- type: 'programmatic-tool-call';
- /**
- * Programmatic tool calling: Python code to execute when code_execution
- * is used with allowedCallers to trigger client-executed tools.
- */
- code: string;
- }
- | {
- type: 'bash_code_execution';
-
- /**
- * Shell command to execute.
- */
- command: string;
- }
- | {
- type: 'text_editor_code_execution';
- command: 'view';
-
- /**
- * The path to the file to view.
- */
- path: string;
- }
- | {
- type: 'text_editor_code_execution';
- command: 'create';
-
- /**
- * The path to the file to edit.
- */
- path: string;
-
- /**
- * The text of the file to edit.
- */
- file_text?: string | null;
- }
- | {
- type: 'text_editor_code_execution';
- command: 'str_replace';
-
- /**
- * The path to the file to edit.
- */
- path: string;
-
- /**
- * The string to replace.
- */
- old_str: string;
-
- /**
- * The new string to replace the old string with.
- */
- new_str: string;
- },
- | {
- /**
- * Programmatic tool calling result: returned when code_execution runs code
- * that calls client-executed tools via allowedCallers.
- */
- type: 'code_execution_result';
-
- /**
- * Output from successful execution
- */
- stdout: string;
-
- /**
- * Error messages if execution fails
- */
- stderr: string;
-
- /**
- * 0 for success, non-zero for failure
- */
- return_code: number;
-
- /**
- * Output file Id list
- */
- content: Array<{ type: 'code_execution_output'; file_id: string }>;
- }
- | {
- type: 'encrypted_code_execution_result';
-
- /**
- * Encrypted output from successful execution
- */
- encrypted_stdout: string;
-
- /**
- * Error messages if execution fails
- */
- stderr: string;
-
- /**
- * 0 for success, non-zero for failure
- */
- return_code: number;
-
- /**
- * Output file Id list
- */
- content: Array<{ type: 'code_execution_output'; file_id: string }>;
- }
- | {
- type: 'bash_code_execution_result';
-
- /**
- * Output file Id list
- */
- content: Array<{
- type: 'bash_code_execution_output';
- file_id: string;
- }>;
-
- /**
- * Output from successful execution
- */
- stdout: string;
-
- /**
- * Error messages if execution fails
- */
- stderr: string;
-
- /**
- * 0 for success, non-zero for failure
- */
- return_code: number;
- }
- | {
- type: 'bash_code_execution_tool_result_error';
-
- /**
- * Available options: invalid_tool_input, unavailable, too_many_requests,
- * execution_time_exceeded, output_file_too_large.
- */
- error_code: string;
- }
- | {
- type: 'text_editor_code_execution_tool_result_error';
-
- /**
- * Available options: invalid_tool_input, unavailable, too_many_requests,
- * execution_time_exceeded, file_not_found.
- */
- error_code: string;
- }
- | {
- type: 'text_editor_code_execution_view_result';
-
- content: string;
-
- /**
- * The type of the file. Available options: text, image, pdf.
- */
- file_type: string;
-
- num_lines: number | null;
- start_line: number | null;
- total_lines: number | null;
- }
- | {
- type: 'text_editor_code_execution_create_result';
-
- is_file_update: boolean;
- }
- | {
- type: 'text_editor_code_execution_str_replace_result';
-
- lines: string[] | null;
- new_lines: number | null;
- new_start: number | null;
- old_lines: number | null;
- old_start: number | null;
- },
- {
- // no arguments
- }
->({
- id: 'anthropic.code_execution_20260120',
- inputSchema: codeExecution_20260120InputSchema,
- outputSchema: codeExecution_20260120OutputSchema,
- supportsDeferredResults: true,
-});
-
-export const codeExecution_20260120 = (
- args: Parameters[0] = {},
-) => {
- return factory(args);
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/computer_20241022.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/computer_20241022.ts
deleted file mode 100644
index de7b99f69..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/computer_20241022.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-import {
- createProviderToolFactory,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-const computer_20241022InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- action: z.enum([
- 'key',
- 'type',
- 'mouse_move',
- 'left_click',
- 'left_click_drag',
- 'right_click',
- 'middle_click',
- 'double_click',
- 'screenshot',
- 'cursor_position',
- ]),
- coordinate: z.array(z.number().int()).optional(),
- text: z.string().optional(),
- }),
- ),
-);
-
-export const computer_20241022 = createProviderToolFactory<
- {
- /**
- * The action to perform. The available actions are:
- * - `key`: Press a key or key-combination on the keyboard.
- * - This supports xdotool's `key` syntax.
- * - Examples: "a", "Return", "alt+Tab", "ctrl+s", "Up", "KP_0" (for the numpad 0 key).
- * - `type`: Type a string of text on the keyboard.
- * - `cursor_position`: Get the current (x, y) pixel coordinate of the cursor on the screen.
- * - `mouse_move`: Move the cursor to a specified (x, y) pixel coordinate on the screen.
- * - `left_click`: Click the left mouse button.
- * - `left_click_drag`: Click and drag the cursor to a specified (x, y) pixel coordinate on the screen.
- * - `right_click`: Click the right mouse button.
- * - `middle_click`: Click the middle mouse button.
- * - `double_click`: Double-click the left mouse button.
- * - `screenshot`: Take a screenshot of the screen.
- */
- action:
- | 'key'
- | 'type'
- | 'mouse_move'
- | 'left_click'
- | 'left_click_drag'
- | 'right_click'
- | 'middle_click'
- | 'double_click'
- | 'screenshot'
- | 'cursor_position';
-
- /**
- * (x, y): The x (pixels from the left edge) and y (pixels from the top edge) coordinates to move the mouse to. Required only by `action=mouse_move` and `action=left_click_drag`.
- */
- coordinate?: number[];
-
- /**
- * Required only by `action=type` and `action=key`.
- */
- text?: string;
- },
- {
- /**
- * The width of the display being controlled by the model in pixels.
- */
- displayWidthPx: number;
-
- /**
- * The height of the display being controlled by the model in pixels.
- */
- displayHeightPx: number;
-
- /**
- * The display number to control (only relevant for X11 environments). If specified, the tool will be provided a display number in the tool definition.
- */
- displayNumber?: number;
- }
->({
- id: 'anthropic.computer_20241022',
- inputSchema: computer_20241022InputSchema,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/computer_20250124.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/computer_20250124.ts
deleted file mode 100644
index 2a111d231..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/computer_20250124.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-import {
- createProviderToolFactory,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-const computer_20250124InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- action: z.enum([
- 'key',
- 'hold_key',
- 'type',
- 'cursor_position',
- 'mouse_move',
- 'left_mouse_down',
- 'left_mouse_up',
- 'left_click',
- 'left_click_drag',
- 'right_click',
- 'middle_click',
- 'double_click',
- 'triple_click',
- 'scroll',
- 'wait',
- 'screenshot',
- ]),
- coordinate: z.tuple([z.number().int(), z.number().int()]).optional(),
- duration: z.number().optional(),
- scroll_amount: z.number().optional(),
- scroll_direction: z.enum(['up', 'down', 'left', 'right']).optional(),
- start_coordinate: z
- .tuple([z.number().int(), z.number().int()])
- .optional(),
- text: z.string().optional(),
- }),
- ),
-);
-
-export const computer_20250124 = createProviderToolFactory<
- {
- /**
- * - `key`: Press a key or key-combination on the keyboard.
- * - This supports xdotool's `key` syntax.
- * - Examples: "a", "Return", "alt+Tab", "ctrl+s", "Up", "KP_0" (for the numpad 0 key).
- * - `hold_key`: Hold down a key or multiple keys for a specified duration (in seconds). Supports the same syntax as `key`.
- * - `type`: Type a string of text on the keyboard.
- * - `cursor_position`: Get the current (x, y) pixel coordinate of the cursor on the screen.
- * - `mouse_move`: Move the cursor to a specified (x, y) pixel coordinate on the screen.
- * - `left_mouse_down`: Press the left mouse button.
- * - `left_mouse_up`: Release the left mouse button.
- * - `left_click`: Click the left mouse button at the specified (x, y) pixel coordinate on the screen. You can also include a key combination to hold down while clicking using the `text` parameter.
- * - `left_click_drag`: Click and drag the cursor from `start_coordinate` to a specified (x, y) pixel coordinate on the screen.
- * - `right_click`: Click the right mouse button at the specified (x, y) pixel coordinate on the screen.
- * - `middle_click`: Click the middle mouse button at the specified (x, y) pixel coordinate on the screen.
- * - `double_click`: Double-click the left mouse button at the specified (x, y) pixel coordinate on the screen.
- * - `triple_click`: Triple-click the left mouse button at the specified (x, y) pixel coordinate on the screen.
- * - `scroll`: Scroll the screen in a specified direction by a specified amount of clicks of the scroll wheel, at the specified (x, y) pixel coordinate. DO NOT use PageUp/PageDown to scroll.
- * - `wait`: Wait for a specified duration (in seconds).
- * - `screenshot`: Take a screenshot of the screen.
- */
- action:
- | 'key'
- | 'hold_key'
- | 'type'
- | 'cursor_position'
- | 'mouse_move'
- | 'left_mouse_down'
- | 'left_mouse_up'
- | 'left_click'
- | 'left_click_drag'
- | 'right_click'
- | 'middle_click'
- | 'double_click'
- | 'triple_click'
- | 'scroll'
- | 'wait'
- | 'screenshot';
-
- /**
- * (x, y): The x (pixels from the left edge) and y (pixels from the top edge) coordinates to move the mouse to. Required only by `action=mouse_move` and `action=left_click_drag`.
- */
- coordinate?: [number, number];
-
- /**
- * The duration to hold the key down for. Required only by `action=hold_key` and `action=wait`.
- */
- duration?: number;
-
- /**
- * The number of 'clicks' to scroll. Required only by `action=scroll`.
- */
- scroll_amount?: number;
-
- /**
- * The direction to scroll the screen. Required only by `action=scroll`.
- */
- scroll_direction?: 'up' | 'down' | 'left' | 'right';
-
- /**
- * (x, y): The x (pixels from the left edge) and y (pixels from the top edge) coordinates to start the drag from. Required only by `action=left_click_drag`.
- */
- start_coordinate?: [number, number];
-
- /**
- * Required only by `action=type`, `action=key`, and `action=hold_key`. Can also be used by click or scroll actions to hold down keys while clicking or scrolling.
- */
- text?: string;
- },
- {
- /**
- * The width of the display being controlled by the model in pixels.
- */
- displayWidthPx: number;
-
- /**
- * The height of the display being controlled by the model in pixels.
- */
- displayHeightPx: number;
-
- /**
- * The display number to control (only relevant for X11 environments). If specified, the tool will be provided a display number in the tool definition.
- */
- displayNumber?: number;
- }
->({
- id: 'anthropic.computer_20250124',
- inputSchema: computer_20250124InputSchema,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/computer_20251124.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/computer_20251124.ts
deleted file mode 100644
index 9c7b397f8..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/computer_20251124.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-import {
- createProviderToolFactory,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-const computer_20251124InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- action: z.enum([
- 'key',
- 'hold_key',
- 'type',
- 'cursor_position',
- 'mouse_move',
- 'left_mouse_down',
- 'left_mouse_up',
- 'left_click',
- 'left_click_drag',
- 'right_click',
- 'middle_click',
- 'double_click',
- 'triple_click',
- 'scroll',
- 'wait',
- 'screenshot',
- 'zoom',
- ]),
- coordinate: z.tuple([z.number().int(), z.number().int()]).optional(),
- duration: z.number().optional(),
- region: z
- .tuple([
- z.number().int(),
- z.number().int(),
- z.number().int(),
- z.number().int(),
- ])
- .optional(),
- scroll_amount: z.number().optional(),
- scroll_direction: z.enum(['up', 'down', 'left', 'right']).optional(),
- start_coordinate: z
- .tuple([z.number().int(), z.number().int()])
- .optional(),
- text: z.string().optional(),
- }),
- ),
-);
-
-export const computer_20251124 = createProviderToolFactory<
- {
- /**
- * - `key`: Press a key or key-combination on the keyboard.
- * - This supports xdotool's `key` syntax.
- * - Examples: "a", "Return", "alt+Tab", "ctrl+s", "Up", "KP_0" (for the numpad 0 key).
- * - `hold_key`: Hold down a key or multiple keys for a specified duration (in seconds). Supports the same syntax as `key`.
- * - `type`: Type a string of text on the keyboard.
- * - `cursor_position`: Get the current (x, y) pixel coordinate of the cursor on the screen.
- * - `mouse_move`: Move the cursor to a specified (x, y) pixel coordinate on the screen.
- * - `left_mouse_down`: Press the left mouse button.
- * - `left_mouse_up`: Release the left mouse button.
- * - `left_click`: Click the left mouse button at the specified (x, y) pixel coordinate on the screen. You can also include a key combination to hold down while clicking using the `text` parameter.
- * - `left_click_drag`: Click and drag the cursor from `start_coordinate` to a specified (x, y) pixel coordinate on the screen.
- * - `right_click`: Click the right mouse button at the specified (x, y) pixel coordinate on the screen.
- * - `middle_click`: Click the middle mouse button at the specified (x, y) pixel coordinate on the screen.
- * - `double_click`: Double-click the left mouse button at the specified (x, y) pixel coordinate on the screen.
- * - `triple_click`: Triple-click the left mouse button at the specified (x, y) pixel coordinate on the screen.
- * - `scroll`: Scroll the screen in a specified direction by a specified amount of clicks of the scroll wheel, at the specified (x, y) pixel coordinate. DO NOT use PageUp/PageDown to scroll.
- * - `wait`: Wait for a specified duration (in seconds).
- * - `screenshot`: Take a screenshot of the screen.
- * - `zoom`: View a specific region of the screen at full resolution. Requires `enableZoom: true` in tool definition. Takes a `region` parameter with coordinates `[x1, y1, x2, y2]` defining top-left and bottom-right corners of the area to inspect.
- */
- action:
- | 'key'
- | 'hold_key'
- | 'type'
- | 'cursor_position'
- | 'mouse_move'
- | 'left_mouse_down'
- | 'left_mouse_up'
- | 'left_click'
- | 'left_click_drag'
- | 'right_click'
- | 'middle_click'
- | 'double_click'
- | 'triple_click'
- | 'scroll'
- | 'wait'
- | 'screenshot'
- | 'zoom';
-
- /**
- * (x, y): The x (pixels from the left edge) and y (pixels from the top edge) coordinates to move the mouse to. Required only by `action=mouse_move` and `action=left_click_drag`.
- */
- coordinate?: [number, number];
-
- /**
- * The duration to hold the key down for. Required only by `action=hold_key` and `action=wait`.
- */
- duration?: number;
-
- /**
- * [x1, y1, x2, y2]: The coordinates defining the region to zoom into. x1, y1 is the top-left corner and x2, y2 is the bottom-right corner. Required only by `action=zoom`.
- */
- region?: [number, number, number, number];
-
- /**
- * The number of 'clicks' to scroll. Required only by `action=scroll`.
- */
- scroll_amount?: number;
-
- /**
- * The direction to scroll the screen. Required only by `action=scroll`.
- */
- scroll_direction?: 'up' | 'down' | 'left' | 'right';
-
- /**
- * (x, y): The x (pixels from the left edge) and y (pixels from the top edge) coordinates to start the drag from. Required only by `action=left_click_drag`.
- */
- start_coordinate?: [number, number];
-
- /**
- * Required only by `action=type`, `action=key`, and `action=hold_key`. Can also be used by click or scroll actions to hold down keys while clicking or scrolling.
- */
- text?: string;
- },
- {
- /**
- * The width of the display being controlled by the model in pixels.
- */
- displayWidthPx: number;
-
- /**
- * The height of the display being controlled by the model in pixels.
- */
- displayHeightPx: number;
-
- /**
- * The display number to control (only relevant for X11 environments). If specified, the tool will be provided a display number in the tool definition.
- */
- displayNumber?: number;
-
- /**
- * Enable zoom action. Set to true to allow Claude to zoom into specific screen regions. Default: false.
- */
- enableZoom?: boolean;
- }
->({
- id: 'anthropic.computer_20251124',
- inputSchema: computer_20251124InputSchema,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/memory_20250818.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/memory_20250818.ts
deleted file mode 100644
index f4a103028..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/memory_20250818.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import {
- createProviderToolFactory,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-const memory_20250818InputSchema = lazySchema(() =>
- zodSchema(
- z.discriminatedUnion('command', [
- z.object({
- command: z.literal('view'),
- path: z.string(),
- view_range: z.tuple([z.number(), z.number()]).optional(),
- }),
- z.object({
- command: z.literal('create'),
- path: z.string(),
- file_text: z.string(),
- }),
- z.object({
- command: z.literal('str_replace'),
- path: z.string(),
- old_str: z.string(),
- new_str: z.string(),
- }),
- z.object({
- command: z.literal('insert'),
- path: z.string(),
- insert_line: z.number(),
- insert_text: z.string(),
- }),
- z.object({
- command: z.literal('delete'),
- path: z.string(),
- }),
- z.object({
- command: z.literal('rename'),
- old_path: z.string(),
- new_path: z.string(),
- }),
- ]),
- ),
-);
-
-export const memory_20250818 = createProviderToolFactory<
- | { command: 'view'; path: string; view_range?: [number, number] }
- | { command: 'create'; path: string; file_text: string }
- | { command: 'str_replace'; path: string; old_str: string; new_str: string }
- | {
- command: 'insert';
- path: string;
- insert_line: number;
- insert_text: string;
- }
- | { command: 'delete'; path: string }
- | { command: 'rename'; old_path: string; new_path: string },
- {}
->({
- id: 'anthropic.memory_20250818',
- inputSchema: memory_20250818InputSchema,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/text-editor_20241022.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/text-editor_20241022.ts
deleted file mode 100644
index 7263d7673..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/text-editor_20241022.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import {
- createProviderToolFactory,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-const textEditor_20241022InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- command: z.enum(['view', 'create', 'str_replace', 'insert', 'undo_edit']),
- path: z.string(),
- file_text: z.string().optional(),
- insert_line: z.number().int().optional(),
- new_str: z.string().optional(),
- insert_text: z.string().optional(),
- old_str: z.string().optional(),
- view_range: z.array(z.number().int()).optional(),
- }),
- ),
-);
-
-export const textEditor_20241022 = createProviderToolFactory<
- {
- /**
- * The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`, `undo_edit`.
- */
- command: 'view' | 'create' | 'str_replace' | 'insert' | 'undo_edit';
-
- /**
- * Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`.
- */
- path: string;
-
- /**
- * Required parameter of `create` command, with the content of the file to be created.
- */
- file_text?: string;
-
- /**
- * Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`.
- */
- insert_line?: number;
-
- /**
- * Optional parameter of `str_replace` command containing the new string (if not given, no string will be added).
- */
- new_str?: string;
-
- /**
- * Required parameter of `insert` command containing the text to insert.
- */
- insert_text?: string;
-
- /**
- * Required parameter of `str_replace` command containing the string in `path` to replace.
- */
- old_str?: string;
-
- /**
- * Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.
- */
- view_range?: number[];
- },
- {}
->({
- id: 'anthropic.text_editor_20241022',
- inputSchema: textEditor_20241022InputSchema,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/text-editor_20250124.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/text-editor_20250124.ts
deleted file mode 100644
index 9dfb9dbfd..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/text-editor_20250124.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import {
- createProviderToolFactory,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-const textEditor_20250124InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- command: z.enum(['view', 'create', 'str_replace', 'insert', 'undo_edit']),
- path: z.string(),
- file_text: z.string().optional(),
- insert_line: z.number().int().optional(),
- new_str: z.string().optional(),
- insert_text: z.string().optional(),
- old_str: z.string().optional(),
- view_range: z.array(z.number().int()).optional(),
- }),
- ),
-);
-
-export const textEditor_20250124 = createProviderToolFactory<
- {
- /**
- * The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`, `undo_edit`.
- */
- command: 'view' | 'create' | 'str_replace' | 'insert' | 'undo_edit';
-
- /**
- * Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`.
- */
- path: string;
-
- /**
- * Required parameter of `create` command, with the content of the file to be created.
- */
- file_text?: string;
-
- /**
- * Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`.
- */
- insert_line?: number;
-
- /**
- * Optional parameter of `str_replace` command containing the new string (if not given, no string will be added).
- */
- new_str?: string;
-
- /**
- * Required parameter of `insert` command containing the text to insert.
- */
- insert_text?: string;
-
- /**
- * Required parameter of `str_replace` command containing the string in `path` to replace.
- */
- old_str?: string;
-
- /**
- * Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.
- */
- view_range?: number[];
- },
- {}
->({
- id: 'anthropic.text_editor_20250124',
- inputSchema: textEditor_20250124InputSchema,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/text-editor_20250429.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/text-editor_20250429.ts
deleted file mode 100644
index 86e468ea2..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/text-editor_20250429.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-import {
- createProviderToolFactory,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-const textEditor_20250429InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- command: z.enum(['view', 'create', 'str_replace', 'insert']),
- path: z.string(),
- file_text: z.string().optional(),
- insert_line: z.number().int().optional(),
- new_str: z.string().optional(),
- insert_text: z.string().optional(),
- old_str: z.string().optional(),
- view_range: z.array(z.number().int()).optional(),
- }),
- ),
-);
-
-export const textEditor_20250429 = createProviderToolFactory<
- {
- /**
- * The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`.
- * Note: `undo_edit` is not supported in Claude 4 models.
- */
- command: 'view' | 'create' | 'str_replace' | 'insert';
-
- /**
- * Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`.
- */
- path: string;
-
- /**
- * Required parameter of `create` command, with the content of the file to be created.
- */
- file_text?: string;
-
- /**
- * Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`.
- */
- insert_line?: number;
-
- /**
- * Optional parameter of `str_replace` command containing the new string (if not given, no string will be added).
- */
- new_str?: string;
-
- /**
- * Required parameter of `insert` command containing the text to insert.
- */
- insert_text?: string;
-
- /**
- * Required parameter of `str_replace` command containing the string in `path` to replace.
- */
- old_str?: string;
-
- /**
- * Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.
- */
- view_range?: number[];
- },
- {}
->({
- id: 'anthropic.text_editor_20250429',
- inputSchema: textEditor_20250429InputSchema,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/text-editor_20250728.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/text-editor_20250728.ts
deleted file mode 100644
index 10c820ec0..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/text-editor_20250728.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import { createProviderToolFactory } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-import { lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-
-export const textEditor_20250728ArgsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- maxCharacters: z.number().optional(),
- }),
- ),
-);
-
-const textEditor_20250728InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- command: z.enum(['view', 'create', 'str_replace', 'insert']),
- path: z.string(),
- file_text: z.string().optional(),
- insert_line: z.number().int().optional(),
- new_str: z.string().optional(),
- insert_text: z.string().optional(),
- old_str: z.string().optional(),
- view_range: z.array(z.number().int()).optional(),
- }),
- ),
-);
-
-const factory = createProviderToolFactory<
- {
- /**
- * The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`.
- * Note: `undo_edit` is not supported in Claude 4 models.
- */
- command: 'view' | 'create' | 'str_replace' | 'insert';
-
- /**
- * Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`.
- */
- path: string;
-
- /**
- * Required parameter of `create` command, with the content of the file to be created.
- */
- file_text?: string;
-
- /**
- * Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`.
- */
- insert_line?: number;
-
- /**
- * Optional parameter of `str_replace` command containing the new string (if not given, no string will be added).
- */
- new_str?: string;
-
- /**
- * Required parameter of `insert` command containing the text to insert.
- */
- insert_text?: string;
-
- /**
- * Required parameter of `str_replace` command containing the string in `path` to replace.
- */
- old_str?: string;
-
- /**
- * Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.
- */
- view_range?: number[];
- },
- {
- /**
- * Optional parameter to control truncation when viewing large files. Only compatible with text_editor_20250728 and later versions.
- */
- maxCharacters?: number;
- }
->({
- id: 'anthropic.text_editor_20250728',
- inputSchema: textEditor_20250728InputSchema,
-});
-
-export const textEditor_20250728 = (
- args: Parameters[0] = {}, // default
-) => {
- return factory(args);
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/tool-search-bm25_20251119.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/tool-search-bm25_20251119.ts
deleted file mode 100644
index fa1a081c4..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/tool-search-bm25_20251119.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-/**
- * Output schema for tool search results - returns tool references
- * that are automatically expanded into full tool definitions by the API.
- */
-export const toolSearchBm25_20251119OutputSchema = lazySchema(() =>
- zodSchema(
- z.array(
- z.object({
- type: z.literal('tool_reference'),
- toolName: z.string(),
- }),
- ),
- ),
-);
-
-/**
- * Input schema for BM25-based tool search.
- * Claude uses natural language queries to search for tools.
- */
-const toolSearchBm25_20251119InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- /**
- * A natural language query to search for tools.
- * Claude will use BM25 text search to find relevant tools.
- */
- query: z.string(),
- /**
- * Maximum number of tools to return. Optional.
- */
- limit: z.number().optional(),
- }),
- ),
-);
-
-const factory = createProviderToolFactoryWithOutputSchema<
- {
- /**
- * A natural language query to search for tools.
- * Claude will use BM25 text search to find relevant tools.
- */
- query: string;
- /**
- * Maximum number of tools to return. Optional.
- */
- limit?: number;
- },
- Array<{
- type: 'tool_reference';
- /**
- * The name of the discovered tool.
- */
- toolName: string;
- }>,
- {}
->({
- id: 'anthropic.tool_search_bm25_20251119',
- inputSchema: toolSearchBm25_20251119InputSchema,
- outputSchema: toolSearchBm25_20251119OutputSchema,
- supportsDeferredResults: true,
-});
-
-/**
- * Creates a tool search tool that uses BM25 (natural language) to find tools.
- *
- * The tool search tool enables Claude to work with hundreds or thousands of tools
- * by dynamically discovering and loading them on-demand. Instead of loading all
- * tool definitions into the context window upfront, Claude searches your tool
- * catalog and loads only the tools it needs.
- *
- * When Claude uses this tool, it uses natural language queries (NOT regex patterns)
- * to search for tools using BM25 text search.
- *
- * **Important**: This tool should never have `deferLoading: true` in providerOptions.
- *
- * @example
- * ```ts
- * import { anthropicTools } from '@ai-sdk/anthropic';
- *
- * const tools = {
- * toolSearch: anthropicTools.toolSearchBm25_20251119(),
- * // Other tools with deferLoading...
- * };
- * ```
- *
- * @see https://docs.anthropic.com/en/docs/agents-and-tools/tool-search-tool
- */
-export const toolSearchBm25_20251119 = (
- args: Parameters[0] = {},
-) => {
- return factory(args);
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/tool-search-regex_20251119.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/tool-search-regex_20251119.ts
deleted file mode 100644
index dacda51c7..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/tool-search-regex_20251119.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-/**
- * Output schema for tool search results - returns tool references
- * that are automatically expanded into full tool definitions by the API.
- */
-export const toolSearchRegex_20251119OutputSchema = lazySchema(() =>
- zodSchema(
- z.array(
- z.object({
- type: z.literal('tool_reference'),
- toolName: z.string(),
- }),
- ),
- ),
-);
-
-/**
- * Input schema for regex-based tool search.
- * Claude constructs regex patterns using Python's re.search() syntax.
- */
-const toolSearchRegex_20251119InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- /**
- * A regex pattern to search for tools.
- * Uses Python re.search() syntax. Maximum 200 characters.
- *
- * Examples:
- * - "weather" - matches tool names/descriptions containing "weather"
- * - "get_.*_data" - matches tools like get_user_data, get_weather_data
- * - "database.*query|query.*database" - OR patterns for flexibility
- * - "(?i)slack" - case-insensitive search
- */
- pattern: z.string(),
- /**
- * Maximum number of tools to return. Optional.
- */
- limit: z.number().optional(),
- }),
- ),
-);
-
-const factory = createProviderToolFactoryWithOutputSchema<
- {
- /**
- * A regex pattern to search for tools.
- * Uses Python re.search() syntax. Maximum 200 characters.
- *
- * Examples:
- * - "weather" - matches tool names/descriptions containing "weather"
- * - "get_.*_data" - matches tools like get_user_data, get_weather_data
- * - "database.*query|query.*database" - OR patterns for flexibility
- * - "(?i)slack" - case-insensitive search
- */
- pattern: string;
- /**
- * Maximum number of tools to return. Optional.
- */
- limit?: number;
- },
- Array<{
- type: 'tool_reference';
- /**
- * The name of the discovered tool.
- */
- toolName: string;
- }>,
- {}
->({
- id: 'anthropic.tool_search_regex_20251119',
- inputSchema: toolSearchRegex_20251119InputSchema,
- outputSchema: toolSearchRegex_20251119OutputSchema,
- supportsDeferredResults: true,
-});
-
-/**
- * Creates a tool search tool that uses regex patterns to find tools.
- *
- * The tool search tool enables Claude to work with hundreds or thousands of tools
- * by dynamically discovering and loading them on-demand. Instead of loading all
- * tool definitions into the context window upfront, Claude searches your tool
- * catalog and loads only the tools it needs.
- *
- * When Claude uses this tool, it constructs regex patterns using Python's
- * re.search() syntax (NOT natural language queries).
- *
- * **Important**: This tool should never have `deferLoading: true` in providerOptions.
- *
- * @example
- * ```ts
- * import { anthropicTools } from '@ai-sdk/anthropic';
- *
- * const tools = {
- * toolSearch: anthropicTools.toolSearchRegex_20251119(),
- * // Other tools with deferLoading...
- * };
- * ```
- *
- * @see https://docs.anthropic.com/en/docs/agents-and-tools/tool-search-tool
- */
-export const toolSearchRegex_20251119 = (
- args: Parameters[0] = {},
-) => {
- return factory(args);
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/web-fetch-20250910.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/web-fetch-20250910.ts
deleted file mode 100644
index de8d33eed..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/web-fetch-20250910.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const webFetch_20250910ArgsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- maxUses: z.number().optional(),
- allowedDomains: z.array(z.string()).optional(),
- blockedDomains: z.array(z.string()).optional(),
- citations: z.object({ enabled: z.boolean() }).optional(),
- maxContentTokens: z.number().optional(),
- }),
- ),
-);
-
-export const webFetch_20250910OutputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- type: z.literal('web_fetch_result'),
- url: z.string(),
- content: z.object({
- type: z.literal('document'),
- title: z.string().nullable(),
- citations: z.object({ enabled: z.boolean() }).optional(),
- source: z.union([
- z.object({
- type: z.literal('base64'),
- mediaType: z.literal('application/pdf'),
- data: z.string(),
- }),
- z.object({
- type: z.literal('text'),
- mediaType: z.literal('text/plain'),
- data: z.string(),
- }),
- ]),
- }),
- retrievedAt: z.string().nullable(),
- }),
- ),
-);
-
-const webFetch_20250910InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- url: z.string(),
- }),
- ),
-);
-
-const factory = createProviderToolFactoryWithOutputSchema<
- {
- /**
- * The URL to fetch.
- */
- url: string;
- },
- {
- type: 'web_fetch_result';
-
- /**
- * Fetched content URL
- */
- url: string;
-
- /**
- * Fetched content.
- */
- content: {
- type: 'document';
-
- /**
- * Title of the document
- */
- title: string | null;
-
- /**
- * Citation configuration for the document
- */
- citations?: { enabled: boolean };
-
- source:
- | {
- type: 'base64';
- mediaType: 'application/pdf';
- data: string;
- }
- | {
- type: 'text';
- mediaType: 'text/plain';
- data: string;
- };
- };
-
- /**
- * ISO 8601 timestamp when the content was retrieved
- */
- retrievedAt: string | null;
- },
- {
- /**
- * The maxUses parameter limits the number of web fetches performed
- */
- maxUses?: number;
-
- /**
- * Only fetch from these domains
- */
- allowedDomains?: string[];
-
- /**
- * Never fetch from these domains
- */
- blockedDomains?: string[];
-
- /**
- * Unlike web search where citations are always enabled, citations are optional for
- * web fetch. Set "citations": {"enabled": true} to enable Claude to cite specific passages
- * from fetched documents.
- */
- citations?: {
- enabled: boolean;
- };
-
- /**
- * The maxContentTokens parameter limits the amount of content that will be included in the context.
- */
- maxContentTokens?: number;
- }
->({
- id: 'anthropic.web_fetch_20250910',
- inputSchema: webFetch_20250910InputSchema,
- outputSchema: webFetch_20250910OutputSchema,
- supportsDeferredResults: true,
-});
-
-export const webFetch_20250910 = (
- args: Parameters[0] = {}, // default
-) => {
- return factory(args);
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/web-fetch-20260209.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/web-fetch-20260209.ts
deleted file mode 100644
index 80a208653..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/web-fetch-20260209.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const webFetch_20260209ArgsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- maxUses: z.number().optional(),
- allowedDomains: z.array(z.string()).optional(),
- blockedDomains: z.array(z.string()).optional(),
- citations: z.object({ enabled: z.boolean() }).optional(),
- maxContentTokens: z.number().optional(),
- }),
- ),
-);
-
-export const webFetch_20260209OutputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- type: z.literal('web_fetch_result'),
- url: z.string(),
- content: z.object({
- type: z.literal('document'),
- title: z.string().nullable(),
- citations: z.object({ enabled: z.boolean() }).optional(),
- source: z.union([
- z.object({
- type: z.literal('base64'),
- mediaType: z.literal('application/pdf'),
- data: z.string(),
- }),
- z.object({
- type: z.literal('text'),
- mediaType: z.literal('text/plain'),
- data: z.string(),
- }),
- ]),
- }),
- retrievedAt: z.string().nullable(),
- }),
- ),
-);
-
-const webFetch_20260209InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- url: z.string(),
- }),
- ),
-);
-
-const factory = createProviderToolFactoryWithOutputSchema<
- {
- /**
- * The URL to fetch.
- */
- url: string;
- },
- {
- type: 'web_fetch_result';
-
- /**
- * Fetched content URL
- */
- url: string;
-
- /**
- * Fetched content.
- */
- content: {
- type: 'document';
-
- /**
- * Title of the document
- */
- title: string | null;
-
- /**
- * Citation configuration for the document
- */
- citations?: { enabled: boolean };
-
- source:
- | {
- type: 'base64';
- mediaType: 'application/pdf';
- data: string;
- }
- | {
- type: 'text';
- mediaType: 'text/plain';
- data: string;
- };
- };
-
- /**
- * ISO 8601 timestamp when the content was retrieved
- */
- retrievedAt: string | null;
- },
- {
- /**
- * The maxUses parameter limits the number of web fetches performed
- */
- maxUses?: number;
-
- /**
- * Only fetch from these domains
- */
- allowedDomains?: string[];
-
- /**
- * Never fetch from these domains
- */
- blockedDomains?: string[];
-
- /**
- * Unlike web search where citations are always enabled, citations are optional for
- * web fetch. Set "citations": {"enabled": true} to enable Claude to cite specific passages
- * from fetched documents.
- */
- citations?: {
- enabled: boolean;
- };
-
- /**
- * The maxContentTokens parameter limits the amount of content that will be included in the context.
- */
- maxContentTokens?: number;
- }
->({
- id: 'anthropic.web_fetch_20260209',
- inputSchema: webFetch_20260209InputSchema,
- outputSchema: webFetch_20260209OutputSchema,
- supportsDeferredResults: true,
-});
-
-export const webFetch_20260209 = (
- args: Parameters[0] = {}, // default
-) => {
- return factory(args);
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/web-search_20250305.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/web-search_20250305.ts
deleted file mode 100644
index b83f764e9..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/web-search_20250305.ts
+++ /dev/null
@@ -1,136 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const webSearch_20250305ArgsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- maxUses: z.number().optional(),
- allowedDomains: z.array(z.string()).optional(),
- blockedDomains: z.array(z.string()).optional(),
- userLocation: z
- .object({
- type: z.literal('approximate'),
- city: z.string().optional(),
- region: z.string().optional(),
- country: z.string().optional(),
- timezone: z.string().optional(),
- })
- .optional(),
- }),
- ),
-);
-
-export const webSearch_20250305OutputSchema = lazySchema(() =>
- zodSchema(
- z.array(
- z.object({
- url: z.string(),
- title: z.string().nullable(),
- pageAge: z.string().nullable(),
- encryptedContent: z.string(),
- type: z.literal('web_search_result'),
- }),
- ),
- ),
-);
-
-const webSearch_20250305InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- query: z.string(),
- }),
- ),
-);
-
-const factory = createProviderToolFactoryWithOutputSchema<
- {
- /**
- * The search query to execute.
- */
- query: string;
- },
- Array<{
- type: 'web_search_result';
-
- /**
- * The URL of the source page.
- */
- url: string;
-
- /**
- * The title of the source page.
- */
- title: string | null;
-
- /**
- * When the site was last updated
- */
- pageAge: string | null;
-
- /**
- * Encrypted content that must be passed back in multi-turn conversations for citations
- */
- encryptedContent: string;
- }>,
- {
- /**
- * Maximum number of web searches Claude can perform during the conversation.
- */
- maxUses?: number;
-
- /**
- * Optional list of domains that Claude is allowed to search.
- */
- allowedDomains?: string[];
-
- /**
- * Optional list of domains that Claude should avoid when searching.
- */
- blockedDomains?: string[];
-
- /**
- * Optional user location information to provide geographically relevant search results.
- */
- userLocation?: {
- /**
- * The type of location (must be approximate)
- */
- type: 'approximate';
-
- /**
- * The city name
- */
- city?: string;
-
- /**
- * The region or state
- */
- region?: string;
-
- /**
- * The country
- */
- country?: string;
-
- /**
- * The IANA timezone ID.
- */
- timezone?: string;
- };
- }
->({
- id: 'anthropic.web_search_20250305',
- inputSchema: webSearch_20250305InputSchema,
- outputSchema: webSearch_20250305OutputSchema,
- supportsDeferredResults: true,
-});
-
-export const webSearch_20250305 = (
- args: Parameters[0] = {}, // default
-) => {
- return factory(args);
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/web-search_20260209.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/web-search_20260209.ts
deleted file mode 100644
index a34ae31ac..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/tool/web-search_20260209.ts
+++ /dev/null
@@ -1,136 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const webSearch_20260209ArgsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- maxUses: z.number().optional(),
- allowedDomains: z.array(z.string()).optional(),
- blockedDomains: z.array(z.string()).optional(),
- userLocation: z
- .object({
- type: z.literal('approximate'),
- city: z.string().optional(),
- region: z.string().optional(),
- country: z.string().optional(),
- timezone: z.string().optional(),
- })
- .optional(),
- }),
- ),
-);
-
-export const webSearch_20260209OutputSchema = lazySchema(() =>
- zodSchema(
- z.array(
- z.object({
- url: z.string(),
- title: z.string().nullable(),
- pageAge: z.string().nullable(),
- encryptedContent: z.string(),
- type: z.literal('web_search_result'),
- }),
- ),
- ),
-);
-
-const webSearch_20260209InputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- query: z.string(),
- }),
- ),
-);
-
-const factory = createProviderToolFactoryWithOutputSchema<
- {
- /**
- * The search query to execute.
- */
- query: string;
- },
- Array<{
- type: 'web_search_result';
-
- /**
- * The URL of the source page.
- */
- url: string;
-
- /**
- * The title of the source page.
- */
- title: string | null;
-
- /**
- * When the site was last updated
- */
- pageAge: string | null;
-
- /**
- * Encrypted content that must be passed back in multi-turn conversations for citations
- */
- encryptedContent: string;
- }>,
- {
- /**
- * Maximum number of web searches Claude can perform during the conversation.
- */
- maxUses?: number;
-
- /**
- * Optional list of domains that Claude is allowed to search.
- */
- allowedDomains?: string[];
-
- /**
- * Optional list of domains that Claude should avoid when searching.
- */
- blockedDomains?: string[];
-
- /**
- * Optional user location information to provide geographically relevant search results.
- */
- userLocation?: {
- /**
- * The type of location (must be approximate)
- */
- type: 'approximate';
-
- /**
- * The city name
- */
- city?: string;
-
- /**
- * The region or state
- */
- region?: string;
-
- /**
- * The country
- */
- country?: string;
-
- /**
- * The IANA timezone ID.
- */
- timezone?: string;
- };
- }
->({
- id: 'anthropic.web_search_20260209',
- inputSchema: webSearch_20260209InputSchema,
- outputSchema: webSearch_20260209OutputSchema,
- supportsDeferredResults: true,
-});
-
-export const webSearch_20260209 = (
- args: Parameters[0] = {}, // default
-) => {
- return factory(args);
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/version.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/version.ts
deleted file mode 100644
index 7a35d46f5..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/anthropic/src/version.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-// Version string of this package injected at build time.
-declare const __PACKAGE_VERSION__: string | undefined;
-export const VERSION: string =
- typeof __PACKAGE_VERSION__ !== 'undefined'
- ? __PACKAGE_VERSION__
- : '0.0.0-test';
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/CHANGELOG.md b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/CHANGELOG.md
deleted file mode 100644
index 72d7a68c0..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/CHANGELOG.md
+++ /dev/null
@@ -1,1718 +0,0 @@
-# @ai-sdk/gateway
-
-## 3.0.80
-
-### Patch Changes
-
-- 0db5cd8: Backport: chore(provider/gateway): update gateway model settings files
-
-## 3.0.79
-
-### Patch Changes
-
-- 3caa544: chore(provider/xai): update Grok 4.20 model IDs to their non-beta versions
-
-## 3.0.78
-
-### Patch Changes
-
-- 763e178: Backport: chore(provider/gateway): update gateway model settings files
-
-## 3.0.77
-
-### Patch Changes
-
-- d99eb91: Backport: chore(provider/gateway): update gateway model settings files
-- 055cd68: fix: publish v6 to latest npm dist tag
-- Updated dependencies [055cd68]
- - @ai-sdk/provider-utils@4.0.21
-
-## 3.0.76
-
-### Patch Changes
-
-- 25af909: Backport: chore(provider/gateway): update gateway model settings files
-
-## 3.0.75
-
-### Patch Changes
-
-- f95e0c0: Backport: chore(provider/gateway): update gateway model settings files
-
-## 3.0.74
-
-### Patch Changes
-
-- 7324b56: Backport: chore(provider/gateway): update gateway model settings files
-
-## 3.0.73
-
-### Patch Changes
-
-- ac0c407: Backport: chore(provider/gateway): update gateway model settings files
-- e748159: Backport: chore(provider/gateway): update gateway model settings files
-
-## 3.0.72
-
-### Patch Changes
-
-- 5ffb1ad: feat(provider/google): add `gemini-embedding-2-preview` and fix multimodal embedding support with `embedMany`
-- f5bf0c6: Backport: chore(provider/gateway): update gateway model settings files
-
-## 3.0.71
-
-### Patch Changes
-
-- 55ccbe2: chore(provider/xai): remove obsolete Grok 2 models now that they are shut down in their API
-
-## 3.0.70
-
-### Patch Changes
-
-- ca0b430: chore(provider/gateway): update gateway model settings files
-
-## 3.0.69
-
-### Patch Changes
-
-- efdaefc: chore(provider/gateway): update gateway model settings files
-
-## 3.0.68
-
-### Patch Changes
-
-- Updated dependencies [64ac0fd]
- - @ai-sdk/provider-utils@4.0.20
-
-## 3.0.67
-
-### Patch Changes
-
-- 2589004: feat(provider/openai): add GPT-5.4 model support
-
-## 3.0.66
-
-### Patch Changes
-
-- Updated dependencies [ad4cfc2]
- - @ai-sdk/provider-utils@4.0.19
-
-## 3.0.65
-
-### Patch Changes
-
-- Updated dependencies [824b295]
- - @ai-sdk/provider-utils@4.0.18
-
-## 3.0.64
-
-### Patch Changes
-
-- db3d4ca: chore(provider/gateway): update gateway model settings files
-
-## 3.0.63
-
-### Patch Changes
-
-- 1b01ec1: feat(gateway): add providerTimeouts to provider options
-- 8df8e11: chore(provider/gateway): update gateway model settings files
-
-## 3.0.62
-
-### Patch Changes
-
-- 10bec50: feat(provider/google): add `gemini-3.1-flash-lite-preview`
-
-## 3.0.61
-
-### Patch Changes
-
-- Updated dependencies [08336f1]
- - @ai-sdk/provider-utils@4.0.17
-
-## 3.0.60
-
-### Patch Changes
-
-- 29e9f4d: chore(provider/gateway): update gateway model settings files
-
-## 3.0.59
-
-### Patch Changes
-
-- Updated dependencies [58bc42d]
- - @ai-sdk/provider-utils@4.0.16
-
-## 3.0.58
-
-### Patch Changes
-
-- 1330f2f: chore(provider/gateway): update gateway model settings files
-
-## 3.0.57
-
-### Patch Changes
-
-- ba63bc2: chore(provider/gateway): update gateway model settings files
-
-## 3.0.56
-
-### Patch Changes
-
-- 45f0a7f: feat(provider/google): add support for gemini-3.1-flash-image-preview
-
-## 3.0.55
-
-### Patch Changes
-
-- e8172b6: feat (provider/gateway): pass through project id when available for o11y
-
-## 3.0.54
-
-### Patch Changes
-
-- 0c9395b: feat(provider/openai): add `gpt-5.3-codex`
-
-## 3.0.53
-
-### Patch Changes
-
-- 73b7e09: feat (provider/gateway): add SSE support for video generation with heartbeat keep-alive
-
-## 3.0.52
-
-### Patch Changes
-
-- 363fa44: chore(provider/gateway): update gateway model settings files
-
-## 3.0.51
-
-### Patch Changes
-
-- 765b013: feat(provider/google): add support for `gemini-3.1-pro-preview`
-
-## 3.0.50
-
-### Patch Changes
-
-- a433cd3: chore(provider/gateway): update gateway model settings files
-
-## 3.0.49
-
-### Patch Changes
-
-- 5f693c8: chore(provider/gateway): update gateway model settings files
-
-## 3.0.48
-
-### Patch Changes
-
-- 2a1c664: feat(provider/anthropic): add support for new Claude Sonnet 4.6 model
-
-## 3.0.47
-
-### Patch Changes
-
-- 6bbd05b: chore(provider/gateway): update gateway model settings files
-
-## 3.0.46
-
-### Patch Changes
-
-- f75f18c: chore(provider/gateway): update gateway model settings files
-
-## 3.0.45
-
-### Patch Changes
-
-- e858654: fix (provider/gateway): Fixed error handling in Gateway models by making asGatewayError async in both image and video model implementations.
-
-## 3.0.44
-
-### Patch Changes
-
-- Updated dependencies [4024a3a]
- - @ai-sdk/provider-utils@4.0.15
-
-## 3.0.43
-
-### Patch Changes
-
-- b424e50: chore(provider/gateway): update gateway model settings files
-
-## 3.0.42
-
-### Patch Changes
-
-- 1819bc1: fix (provider/gateway): add missing warning types for video response parsing
-
-## 3.0.41
-
-### Patch Changes
-
-- 99fbed8: feat: normalize provider specific model options type names and ensure they are exported
-
-## 3.0.40
-
-### Patch Changes
-
-- a2208a2: fix (provider/gateway): added custom error class and message for client side timeouts
-
-## 3.0.39
-
-### Patch Changes
-
-- eea5d30: fix: image generation via Gateway warning schema mismatch
-
-## 3.0.38
-
-### Patch Changes
-
-- 70028ab: feat: report image generation usage info in Gateway
-
-## 3.0.37
-
-### Patch Changes
-
-- Updated dependencies [7168375]
- - @ai-sdk/provider@3.0.8
- - @ai-sdk/provider-utils@4.0.14
-
-## 3.0.36
-
-### Patch Changes
-
-- 9892c58: feat(anthropic): add support for Opus 4.6
-
-## 3.0.35
-
-### Patch Changes
-
-- 8e2eaac: chore(provider/gateway): update gateway model settings files
-
-## 3.0.34
-
-### Patch Changes
-
-- 4867635: feat (provider/gateway): add video generation support
-
-## 3.0.33
-
-### Patch Changes
-
-- ae30443: fix(google): remove shut down `gemini-2.5-flash-image-preview`
-
-## 3.0.32
-
-### Patch Changes
-
-- Updated dependencies [53f6731]
- - @ai-sdk/provider@3.0.7
- - @ai-sdk/provider-utils@4.0.13
-
-## 3.0.31
-
-### Patch Changes
-
-- Updated dependencies [96936e5]
- - @ai-sdk/provider-utils@4.0.12
-
-## 3.0.30
-
-### Patch Changes
-
-- 1a74972: chore(provider/gateway): update gateway model settings files
-
-## 3.0.29
-
-### Patch Changes
-
-- Updated dependencies [2810850]
- - @ai-sdk/provider-utils@4.0.11
- - @ai-sdk/provider@3.0.6
-
-## 3.0.28
-
-### Patch Changes
-
-- 1524271: chore: add skill information to README files
-
-## 3.0.27
-
-### Patch Changes
-
-- 0acff64: feat (provider/gateway): add parallel search tool
-
-## 3.0.26
-
-### Patch Changes
-
-- a8be296: chore(provider/gateway): update gateway model settings files
-
-## 3.0.25
-
-### Patch Changes
-
-- 15a78c7: chore(provider/gateway): update gateway model settings files
-
-## 3.0.24
-
-### Patch Changes
-
-- Updated dependencies [462ad00]
- - @ai-sdk/provider-utils@4.0.10
-
-## 3.0.23
-
-### Patch Changes
-
-- cbf1704: chore(provider/gateway): update gateway model settings files
-
-## 3.0.22
-
-### Patch Changes
-
-- 4de5a1d: chore: excluded tests from src folder in npm package
-- Updated dependencies [4de5a1d]
- - @ai-sdk/provider@3.0.5
- - @ai-sdk/provider-utils@4.0.9
-
-## 3.0.21
-
-### Patch Changes
-
-- 2b8369d: chore: add docs to package dist
-
-## 3.0.20
-
-### Patch Changes
-
-- 8dc54db: chore: add src folders to package bundle
-
-## 3.0.19
-
-### Patch Changes
-
-- c60fdd8: Inline fullMessage variable in GatewayError constructor
-
-## 3.0.18
-
-### Patch Changes
-
-- 7af4eb4: chore(provider/gateway): update gateway model settings files
-
-## 3.0.17
-
-### Patch Changes
-
-- 66d78d5: chore(provider/gateway): update gateway model settings files
-
-## 3.0.16
-
-### Patch Changes
-
-- Updated dependencies [5c090e7]
- - @ai-sdk/provider@3.0.4
- - @ai-sdk/provider-utils@4.0.8
-
-## 3.0.15
-
-### Patch Changes
-
-- Updated dependencies [46f46e4]
- - @ai-sdk/provider-utils@4.0.7
-
-## 3.0.14
-
-### Patch Changes
-
-- Updated dependencies [1b11dcb]
- - @ai-sdk/provider-utils@4.0.6
- - @ai-sdk/provider@3.0.3
-
-## 3.0.13
-
-### Patch Changes
-
-- 92b339b: feat (provider/gateway): add'l perplexity search tool params
-
-## 3.0.12
-
-### Patch Changes
-
-- Updated dependencies [34d1c8a]
- - @ai-sdk/provider-utils@4.0.5
-
-## 3.0.11
-
-### Patch Changes
-
-- 891a60a: feat (provider/gateway): add provider-defined perplexity search
-
-## 3.0.10
-
-### Patch Changes
-
-- 2696fd2: chore(provider/gateway): Update gateway model settings files
-
-## 3.0.9
-
-### Patch Changes
-
-- Updated dependencies [d937c8f]
- - @ai-sdk/provider@3.0.2
- - @ai-sdk/provider-utils@4.0.4
-
-## 3.0.8
-
-### Patch Changes
-
-- 8ec1984: fix(gateway): bump `@vercel/oidc` to 3.1.0
-
-## 3.0.7
-
-### Patch Changes
-
-- Updated dependencies [0b429d4]
- - @ai-sdk/provider-utils@4.0.3
-
-## 3.0.6
-
-### Patch Changes
-
-- 74c0157: feat (provider/gateway): support image editing
-
-## 3.0.5
-
-### Patch Changes
-
-- 7ee2d12: chore (provider/gateway): bump specification version header to reflect v3
-
-## 3.0.4
-
-### Patch Changes
-
-- 863d34f: fix: trigger release to update `@latest`
-- Updated dependencies [863d34f]
- - @ai-sdk/provider@3.0.1
- - @ai-sdk/provider-utils@4.0.2
-
-## 3.0.3
-
-### Patch Changes
-
-- 1dad057: fix(gateway): add error handling for oidc refresh
-
-## 3.0.2
-
-### Patch Changes
-
-- Updated dependencies [29264a3]
- - @ai-sdk/provider-utils@4.0.1
-
-## 3.0.1
-
-### Patch Changes
-
-- c0c8a0e: Add zai/glm-4.7 model support
-
-## 3.0.0
-
-### Major Changes
-
-- 387980f: fix: major version bump for AI SDK v6
-
-## 2.0.0
-
-### Major Changes
-
-- dee8b05: ai SDK 6 beta
-- 2f8b0c8: fix(gateway): bump `@vercel/oidc` to latest
-
-### Minor Changes
-
-- 78928cb: release: start 5.1 beta
-
-### Patch Changes
-
-- 0c3b58b: fix(provider): add specificationVersion to ProviderV3
-- ea9ca31: feat(provider/gateway): Add new xAI models
-- 5dd4c6a: fix(provider/gateway): Fix Gateway image model provider options not passing through
-- 5d21222: feat(provider/gateway): Add gpt-5-codex to Gateway model string autocomplete
-- 0adc679: feat(provider): shared spec v3
-- 7294355: feat (provider/gateway): update route path version and embed format
-- e8694af: feat(provider/gateway): Server-side image request splitting
-- 8d9e8ad: chore(provider): remove generics from EmbeddingModelV3
-
- Before
-
- ```ts
- model.textEmbeddingModel("my-model-id");
- ```
-
- After
-
- ```ts
- model.embeddingModel("my-model-id");
- ```
-
-- aaf5ebf: feat(provider/gateway): Add new Qwen models to Gateway model string autocomplete
-- 95f65c2: chore: use import \* from zod/v4
-- c823faf: feat(provider/gateway): Add new Gemini preview models to Gateway model string autocomplete
-- 2b6a848: feat (provider/gateway): add models provider option for model routing
-- 0c4822d: feat: `EmbeddingModelV3`
-- 34ee8d0: feat (provider/gateway): add support for request-scoped byok
-- 1890317: feat (provider/gateway): improve auth error messages
-- 636e614: feat(provider/gateway): Add DeepSeek V3.2 Exp to Gateway language model settings
-- 7ccb36f: feat(provider/gateway): Add LongCat Thinking model to Gateway autocomplete
-- ed329cb: feat: `Provider-V3`
-- 5f66123: chore(provider/gateway): Update gateway language model settings
-- 1cad0ab: feat: add provider version to user-agent header
-- bca7e61: feat(provider/gateway): Change default maxImagesPerCall per-provider
-- 8dac895: feat: `LanguageModelV3`
-- 3e83633: add getCredits() gateway method
-- 1d8ea2c: feat(provider/gateway): Add GPT-5 pro to Gateway model string autocomplete
-- ef62178: feat(gateway): oidc refresh with `@vercel/oidc`
-- 0a2ff8a: feat (provider/gateway): add user and tags provider options
-- ee71658: feat (provider/gateway): add zero data retention provider option
-- 457318b: chore(provider,ai): switch to SharedV3Warning and unified warnings
-- 9061dc0: feat: image editing
-- 7d73922: feat(provider/gateway): Add MiniMax M2 to Gateway autocomplete
-- e6bfe91: feat(provider/gateway): Update DeepSeek model string autocomplete
-- acc14d8: feat (provider/gateway): add 'only' to provider options
-- f83903d: getCredits style improvements
-- 0e29b8b: chore(provider/gateway): lazy schema loading
-- 366f50b: chore(provider): add deprecated textEmbeddingModel and textEmbedding aliases
-- cdd0bc2: feat (provider/gateway): add intellect-3 model id
-- 96322b7: feat(provider/gateway): Add GPT OSS Safeguard 20B to Gateway model string autocomplete
-- 4616b86: chore: update zod peer depenedency version
-- 2d166e4: feat(provider/gateway): add support for image models
-- 6c766ef: feat(provider/gateway): Add DeepSeek V3.1 Terminus to Gateway autocomplete
-- 7b1b1b1: fix(provider/gateway): add "react-native" as export condition for browser behavior
-
- This avoids the use of native Node APIs in bundles created for React Native / Expo apps
-
-- 3782645: bump `@vercel/oidc` to 3.0.5
-- f18ef7f: feat(openai): add gpt-5.2 models
-- 1425df5: feat(provider/gateway): Add Imagen 4 Ultra Generate to model string autocomplete list
-- 9f6149e: feat(provider/gateway): Add Sonnet 4.5 to Gateway model string autocomplete
-- cc5170d: feat(provider/gateway): update gateway model string autocomplete
-- a90dca6: feat(provider/gateway): Add zAI GLM 4.6 to Gateway language model settings
-- b1624f0: feat (provider/gateway): add trinity-mini model id
-- cbf52cd: feat: expose raw finish reason
-- 870297d: feat(google): gemini-3-flash
-- f0b2157: fix: revert zod import change
-- Updated dependencies
- - @ai-sdk/provider@3.0.0
- - @ai-sdk/provider-utils@4.0.0
-
-## 2.0.0-beta.93
-
-### Patch Changes
-
-- 7294355: feat (provider/gateway): update route path version and embed format
-
-## 2.0.0-beta.92
-
-### Patch Changes
-
-- Updated dependencies [475189e]
- - @ai-sdk/provider@3.0.0-beta.32
- - @ai-sdk/provider-utils@4.0.0-beta.59
-
-## 2.0.0-beta.91
-
-### Patch Changes
-
-- Updated dependencies [2625a04]
- - @ai-sdk/provider@3.0.0-beta.31
- - @ai-sdk/provider-utils@4.0.0-beta.58
-
-## 2.0.0-beta.90
-
-### Patch Changes
-
-- cbf52cd: feat: expose raw finish reason
-- Updated dependencies [cbf52cd]
- - @ai-sdk/provider@3.0.0-beta.30
- - @ai-sdk/provider-utils@4.0.0-beta.57
-
-## 2.0.0-beta.89
-
-### Patch Changes
-
-- Updated dependencies [9549c9e]
- - @ai-sdk/provider@3.0.0-beta.29
- - @ai-sdk/provider-utils@4.0.0-beta.56
-
-## 2.0.0-beta.88
-
-### Patch Changes
-
-- Updated dependencies [50b70d6]
- - @ai-sdk/provider-utils@4.0.0-beta.55
-
-## 2.0.0-beta.87
-
-### Patch Changes
-
-- ee71658: feat (provider/gateway): add zero data retention provider option
-
-## 2.0.0-beta.86
-
-### Patch Changes
-
-- 9061dc0: feat: image editing
-- Updated dependencies [9061dc0]
- - @ai-sdk/provider-utils@4.0.0-beta.54
- - @ai-sdk/provider@3.0.0-beta.28
-
-## 2.0.0-beta.85
-
-### Patch Changes
-
-- 870297d: feat(google): gemini-3-flash
-
-## 2.0.0-beta.84
-
-### Patch Changes
-
-- 366f50b: chore(provider): add deprecated textEmbeddingModel and textEmbedding aliases
-- Updated dependencies [366f50b]
- - @ai-sdk/provider@3.0.0-beta.27
- - @ai-sdk/provider-utils@4.0.0-beta.53
-
-## 2.0.0-beta.83
-
-### Patch Changes
-
-- Updated dependencies [763d04a]
- - @ai-sdk/provider-utils@4.0.0-beta.52
-
-## 2.0.0-beta.82
-
-### Patch Changes
-
-- Updated dependencies [c1efac4]
- - @ai-sdk/provider-utils@4.0.0-beta.51
-
-## 2.0.0-beta.81
-
-### Patch Changes
-
-- Updated dependencies [32223c8]
- - @ai-sdk/provider-utils@4.0.0-beta.50
-
-## 2.0.0-beta.80
-
-### Patch Changes
-
-- Updated dependencies [83e5744]
- - @ai-sdk/provider-utils@4.0.0-beta.49
-
-## 2.0.0-beta.79
-
-### Patch Changes
-
-- Updated dependencies [960ec8f]
- - @ai-sdk/provider-utils@4.0.0-beta.48
-
-## 2.0.0-beta.78
-
-### Patch Changes
-
-- f18ef7f: feat(openai): add gpt-5.2 models
-
-## 2.0.0-beta.77
-
-### Patch Changes
-
-- Updated dependencies [e9e157f]
- - @ai-sdk/provider-utils@4.0.0-beta.47
-
-## 2.0.0-beta.76
-
-### Patch Changes
-
-- 34ee8d0: feat (provider/gateway): add support for request-scoped byok
-
-## 2.0.0-beta.75
-
-### Patch Changes
-
-- Updated dependencies [81e29ab]
- - @ai-sdk/provider-utils@4.0.0-beta.46
-
-## 2.0.0-beta.74
-
-### Patch Changes
-
-- Updated dependencies [3bd2689]
- - @ai-sdk/provider@3.0.0-beta.26
- - @ai-sdk/provider-utils@4.0.0-beta.45
-
-## 2.0.0-beta.73
-
-### Patch Changes
-
-- Updated dependencies [53f3368]
- - @ai-sdk/provider@3.0.0-beta.25
- - @ai-sdk/provider-utils@4.0.0-beta.44
-
-## 2.0.0-beta.72
-
-### Patch Changes
-
-- Updated dependencies [dce03c4]
- - @ai-sdk/provider-utils@4.0.0-beta.43
- - @ai-sdk/provider@3.0.0-beta.24
-
-## 2.0.0-beta.71
-
-### Patch Changes
-
-- Updated dependencies [3ed5519]
- - @ai-sdk/provider-utils@4.0.0-beta.42
-
-## 2.0.0-beta.70
-
-### Patch Changes
-
-- Updated dependencies [1bd7d32]
- - @ai-sdk/provider-utils@4.0.0-beta.41
- - @ai-sdk/provider@3.0.0-beta.23
-
-## 2.0.0-beta.69
-
-### Patch Changes
-
-- b1624f0: feat (provider/gateway): add trinity-mini model id
-
-## 2.0.0-beta.68
-
-### Patch Changes
-
-- Updated dependencies [544d4e8]
- - @ai-sdk/provider-utils@4.0.0-beta.40
- - @ai-sdk/provider@3.0.0-beta.22
-
-## 2.0.0-beta.67
-
-### Patch Changes
-
-- Updated dependencies [954c356]
- - @ai-sdk/provider-utils@4.0.0-beta.39
- - @ai-sdk/provider@3.0.0-beta.21
-
-## 2.0.0-beta.66
-
-### Patch Changes
-
-- Updated dependencies [03849b0]
- - @ai-sdk/provider-utils@4.0.0-beta.38
-
-## 2.0.0-beta.65
-
-### Patch Changes
-
-- cdd0bc2: feat (provider/gateway): add intellect-3 model id
-
-## 2.0.0-beta.64
-
-### Patch Changes
-
-- 457318b: chore(provider,ai): switch to SharedV3Warning and unified warnings
-- Updated dependencies [457318b]
- - @ai-sdk/provider@3.0.0-beta.20
- - @ai-sdk/provider-utils@4.0.0-beta.37
-
-## 2.0.0-beta.63
-
-### Patch Changes
-
-- 8d9e8ad: chore(provider): remove generics from EmbeddingModelV3
-
- Before
-
- ```ts
- model.textEmbeddingModel("my-model-id");
- ```
-
- After
-
- ```ts
- model.embeddingModel("my-model-id");
- ```
-
-- Updated dependencies [8d9e8ad]
- - @ai-sdk/provider@3.0.0-beta.19
- - @ai-sdk/provider-utils@4.0.0-beta.36
-
-## 2.0.0-beta.62
-
-### Patch Changes
-
-- Updated dependencies [10d819b]
- - @ai-sdk/provider@3.0.0-beta.18
- - @ai-sdk/provider-utils@4.0.0-beta.35
-
-## 2.0.0-beta.61
-
-### Patch Changes
-
-- e8694af: feat(provider/gateway): Server-side image request splitting
-
-## 2.0.0-beta.60
-
-### Patch Changes
-
-- Updated dependencies [db913bd]
- - @ai-sdk/provider@3.0.0-beta.17
- - @ai-sdk/provider-utils@4.0.0-beta.34
-
-## 2.0.0-beta.59
-
-### Patch Changes
-
-- 5dd4c6a: fix(provider/gateway): Fix Gateway image model provider options not passing through
-
-## 2.0.0-beta.58
-
-### Patch Changes
-
-- 1425df5: feat(provider/gateway): Add Imagen 4 Ultra Generate to model string autocomplete list
-
-## 2.0.0-beta.57
-
-### Patch Changes
-
-- bca7e61: feat(provider/gateway): Change default maxImagesPerCall per-provider
-
-## 2.0.0-beta.56
-
-### Patch Changes
-
-- 2d166e4: feat(provider/gateway): add support for image models
-
-## 2.0.0-beta.55
-
-### Patch Changes
-
-- cc5170d: feat(provider/gateway): update gateway model string autocomplete
-
-## 2.0.0-beta.54
-
-### Patch Changes
-
-- 5f66123: chore(provider/gateway): Update gateway language model settings
-
-## 2.0.0-beta.53
-
-### Patch Changes
-
-- 3782645: bump `@vercel/oidc` to 3.0.5
-
-## 2.0.0-beta.52
-
-### Patch Changes
-
-- Updated dependencies [b681d7d]
- - @ai-sdk/provider@3.0.0-beta.16
- - @ai-sdk/provider-utils@4.0.0-beta.33
-
-## 2.0.0-beta.51
-
-### Patch Changes
-
-- Updated dependencies [32d8dbb]
- - @ai-sdk/provider-utils@4.0.0-beta.32
-
-## 2.0.0-beta.50
-
-### Patch Changes
-
-- Updated dependencies [bb36798]
- - @ai-sdk/provider@3.0.0-beta.15
- - @ai-sdk/provider-utils@4.0.0-beta.31
-
-## 2.0.0-beta.49
-
-### Patch Changes
-
-- Updated dependencies [4f16c37]
- - @ai-sdk/provider-utils@4.0.0-beta.30
-
-## 2.0.0-beta.48
-
-### Patch Changes
-
-- Updated dependencies [af3780b]
- - @ai-sdk/provider@3.0.0-beta.14
- - @ai-sdk/provider-utils@4.0.0-beta.29
-
-## 2.0.0-beta.47
-
-### Patch Changes
-
-- 96322b7: feat(provider/gateway): Add GPT OSS Safeguard 20B to Gateway model string autocomplete
-
-## 2.0.0-beta.46
-
-### Patch Changes
-
-- Updated dependencies [016b111]
- - @ai-sdk/provider-utils@4.0.0-beta.28
-
-## 2.0.0-beta.45
-
-### Patch Changes
-
-- Updated dependencies [37c58a0]
- - @ai-sdk/provider@3.0.0-beta.13
- - @ai-sdk/provider-utils@4.0.0-beta.27
-
-## 2.0.0-beta.44
-
-### Patch Changes
-
-- 7d73922: feat(provider/gateway): Add MiniMax M2 to Gateway autocomplete
-
-## 2.0.0-beta.43
-
-### Patch Changes
-
-- Updated dependencies [d1bdadb]
- - @ai-sdk/provider@3.0.0-beta.12
- - @ai-sdk/provider-utils@4.0.0-beta.26
-
-## 2.0.0-beta.42
-
-### Patch Changes
-
-- Updated dependencies [4c44a5b]
- - @ai-sdk/provider@3.0.0-beta.11
- - @ai-sdk/provider-utils@4.0.0-beta.25
-
-## 2.0.0-beta.41
-
-### Patch Changes
-
-- 0c3b58b: fix(provider): add specificationVersion to ProviderV3
-- Updated dependencies [0c3b58b]
- - @ai-sdk/provider@3.0.0-beta.10
- - @ai-sdk/provider-utils@4.0.0-beta.24
-
-## 2.0.0-beta.40
-
-### Patch Changes
-
-- Updated dependencies [a755db5]
- - @ai-sdk/provider@3.0.0-beta.9
- - @ai-sdk/provider-utils@4.0.0-beta.23
-
-## 2.0.0-beta.39
-
-### Patch Changes
-
-- Updated dependencies [58920e0]
- - @ai-sdk/provider-utils@4.0.0-beta.22
-
-## 2.0.0-beta.38
-
-### Patch Changes
-
-- Updated dependencies [293a6b7]
- - @ai-sdk/provider-utils@4.0.0-beta.21
-
-## 2.0.0-beta.37
-
-### Patch Changes
-
-- 2b6a848: feat (provider/gateway): add models provider option for model routing
-
-## 2.0.0-beta.36
-
-### Patch Changes
-
-- Updated dependencies [fca786b]
- - @ai-sdk/provider-utils@4.0.0-beta.20
-
-## 2.0.0-beta.35
-
-### Patch Changes
-
-- Updated dependencies [3794514]
- - @ai-sdk/provider-utils@4.0.0-beta.19
- - @ai-sdk/provider@3.0.0-beta.8
-
-## 2.0.0-beta.34
-
-### Major Changes
-
-- 2f8b0c8: fix(gateway): bump `@vercel/oidc` to latest
-
-## 2.0.0-beta.33
-
-### Patch Changes
-
-- 1890317: feat (provider/gateway): improve auth error messages
-
-## 2.0.0-beta.32
-
-### Patch Changes
-
-- Updated dependencies [81d4308]
- - @ai-sdk/provider@3.0.0-beta.7
- - @ai-sdk/provider-utils@4.0.0-beta.18
-
-## 2.0.0-beta.31
-
-### Patch Changes
-
-- Updated dependencies [703459a]
- - @ai-sdk/provider-utils@4.0.0-beta.17
-
-## 2.0.0-beta.30
-
-### Patch Changes
-
-- 0a2ff8a: feat (provider/gateway): add user and tags provider options
-
-## 2.0.0-beta.29
-
-### Patch Changes
-
-- Updated dependencies [6306603]
- - @ai-sdk/provider-utils@4.0.0-beta.16
-
-## 2.0.0-beta.28
-
-### Patch Changes
-
-- f0b2157: fix: revert zod import change
-- Updated dependencies [f0b2157]
- - @ai-sdk/provider-utils@4.0.0-beta.15
-
-## 2.0.0-beta.27
-
-### Patch Changes
-
-- Updated dependencies [3b1d015]
- - @ai-sdk/provider-utils@4.0.0-beta.14
-
-## 2.0.0-beta.26
-
-### Patch Changes
-
-- Updated dependencies [d116b4b]
- - @ai-sdk/provider-utils@4.0.0-beta.13
-
-## 2.0.0-beta.25
-
-### Patch Changes
-
-- Updated dependencies [7e32fea]
- - @ai-sdk/provider-utils@4.0.0-beta.12
-
-## 2.0.0-beta.24
-
-### Patch Changes
-
-- 0e29b8b: chore(provider/gateway): lazy schema loading
-
-## 2.0.0-beta.23
-
-### Patch Changes
-
-- acc14d8: feat (provider/gateway): add 'only' to provider options
-
-## 2.0.0-beta.22
-
-### Patch Changes
-
-- 95f65c2: chore: use import \* from zod/v4
-- Updated dependencies
- - @ai-sdk/provider-utils@4.0.0-beta.11
-
-## 2.0.0-beta.21
-
-### Patch Changes
-
-- 7b1b1b1: fix(provider/gateway): add "react-native" as export condition for browser behavior
-
- This avoids the use of native Node APIs in bundles created for React Native / Expo apps
-
-## 2.0.0-beta.20
-
-### Major Changes
-
-- dee8b05: ai SDK 6 beta
-
-### Patch Changes
-
-- Updated dependencies [dee8b05]
- - @ai-sdk/provider@3.0.0-beta.6
- - @ai-sdk/provider-utils@4.0.0-beta.10
-
-## 1.1.0-beta.19
-
-### Patch Changes
-
-- Updated dependencies [521c537]
- - @ai-sdk/provider-utils@3.1.0-beta.9
-
-## 1.1.0-beta.18
-
-### Patch Changes
-
-- Updated dependencies [e06565c]
- - @ai-sdk/provider-utils@3.1.0-beta.8
-
-## 1.1.0-beta.17
-
-### Patch Changes
-
-- 1d8ea2c: feat(provider/gateway): Add GPT-5 pro to Gateway model string autocomplete
-
-## 1.1.0-beta.16
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.1.0-beta.5
- - @ai-sdk/provider-utils@3.1.0-beta.7
-
-## 1.1.0-beta.15
-
-### Patch Changes
-
-- ef62178: feat(gateway): oidc refresh with `@vercel/oidc`
-
-## 1.1.0-beta.14
-
-### Patch Changes
-
-- a90dca6: feat(provider/gateway): Add zAI GLM 4.6 to Gateway language model settings
-
-## 1.1.0-beta.13
-
-### Patch Changes
-
-- 0adc679: feat(provider): shared spec v3
-- Updated dependencies
- - @ai-sdk/provider-utils@3.1.0-beta.6
- - @ai-sdk/provider@2.1.0-beta.4
-
-## 1.1.0-beta.12
-
-### Patch Changes
-
-- e6bfe91: feat(provider/gateway): Update DeepSeek model string autocomplete
-
-## 1.1.0-beta.11
-
-### Patch Changes
-
-- 636e614: feat(provider/gateway): Add DeepSeek V3.2 Exp to Gateway language model settings
-
-## 1.1.0-beta.10
-
-### Patch Changes
-
-- 9f6149e: feat(provider/gateway): Add Sonnet 4.5 to Gateway model string autocomplete
-
-## 1.1.0-beta.9
-
-### Patch Changes
-
-- 8dac895: feat: `LanguageModelV3`
-- Updated dependencies [8dac895]
- - @ai-sdk/provider-utils@3.1.0-beta.5
- - @ai-sdk/provider@2.1.0-beta.3
-
-## 1.1.0-beta.8
-
-### Patch Changes
-
-- c823faf: feat(provider/gateway): Add new Gemini preview models to Gateway model string autocomplete
-
-## 1.1.0-beta.7
-
-### Patch Changes
-
-- 4616b86: chore: update zod peer depenedency version
-- Updated dependencies [4616b86]
- - @ai-sdk/provider-utils@3.1.0-beta.4
-
-## 1.1.0-beta.6
-
-### Patch Changes
-
-- aaf5ebf: feat(provider/gateway): Add new Qwen models to Gateway model string autocomplete
-- ed329cb: feat: `Provider-V3`
-- Updated dependencies
- - @ai-sdk/provider@2.1.0-beta.2
- - @ai-sdk/provider-utils@3.1.0-beta.3
-
-## 1.1.0-beta.5
-
-### Patch Changes
-
-- 5d21222: feat(provider/gateway): Add gpt-5-codex to Gateway model string autocomplete
-- 0c4822d: feat: `EmbeddingModelV3`
-- 1cad0ab: feat: add provider version to user-agent header
-- Updated dependencies [0c4822d]
- - @ai-sdk/provider@2.1.0-beta.1
- - @ai-sdk/provider-utils@3.1.0-beta.2
-
-## 1.1.0-beta.4
-
-### Patch Changes
-
-- 7ccb36f: feat(provider/gateway): Add LongCat Thinking model to Gateway autocomplete
-- 6c766ef: feat(provider/gateway): Add DeepSeek V3.1 Terminus to Gateway autocomplete
-
-## 1.1.0-beta.3
-
-### Patch Changes
-
-- ea9ca31: feat(provider/gateway): Add new xAI models
-
-## 1.1.0-beta.2
-
-### Patch Changes
-
-- 3e83633: add getCredits() gateway method
-- f83903d: getCredits style improvements
-
-## 1.1.0-beta.1
-
-### Patch Changes
-
-- Updated dependencies [cbb1d35]
- - @ai-sdk/provider-utils@3.1.0-beta.1
-
-## 1.1.0-beta.0
-
-### Minor Changes
-
-- 78928cb: release: start 5.1 beta
-
-### Patch Changes
-
-- Updated dependencies [78928cb]
- - @ai-sdk/provider@2.1.0-beta.0
- - @ai-sdk/provider-utils@3.1.0-beta.0
-
-## 1.0.23
-
-### Patch Changes
-
-- f49f924: feat (provider/gateway): add qwen3 next model ids
-
-## 1.0.22
-
-### Patch Changes
-
-- Updated dependencies [0294b58]
- - @ai-sdk/provider-utils@3.0.9
-
-## 1.0.21
-
-### Patch Changes
-
-- 4ee3719: feat(provider/gateway): Add Meituan LongCat Flash Chat to autocomplete
-
-## 1.0.20
-
-### Patch Changes
-
-- 350a328: feat(provider/gateway): Add stealth models to Gateway autocomplete
-
-## 1.0.19
-
-### Patch Changes
-
-- 034287f: feat (provider/gateway): add qwen3-max model id
-- dee1afe: feat(provider/gateway): Fix embeddings `providerOptions`
-
-## 1.0.18
-
-### Patch Changes
-
-- 5d59a8c: feat (provider/gateway): add moonshotai/kimi-k2-0905 model id
-
-## 1.0.17
-
-### Patch Changes
-
-- b6005cd: feat(provider/gateway): Add Voyage embedding models
-
-## 1.0.16
-
-### Patch Changes
-
-- Updated dependencies [99964ed]
- - @ai-sdk/provider-utils@3.0.8
-
-## 1.0.15
-
-### Patch Changes
-
-- 980633d: feat(provider/gateway): Add xAI Grok Code Fast 1
-- 1c5b88d: feat (provider/gateway): add new model ids
-
-## 1.0.14
-
-### Patch Changes
-
-- Updated dependencies [886e7cd]
- - @ai-sdk/provider-utils@3.0.7
-
-## 1.0.13
-
-### Patch Changes
-
-- c9994f9: feat(provider/gateway): Add cache pricing fields to model metadata
-- Updated dependencies [1b5a3d3]
- - @ai-sdk/provider-utils@3.0.6
-
-## 1.0.12
-
-### Patch Changes
-
-- 50e2029: feat (provider/gateway): add deepseek v3.1 thinking model id
-- b8478f0: feat (provider/gateway): add mistral medium model id
-
-## 1.0.11
-
-### Patch Changes
-
-- 926259f: feat(provider/gateway): Expose model type in model spec
-- c000f96: feat(provider/gateway): Add DeepSeek V3.1
-
-## 1.0.10
-
-### Patch Changes
-
-- Updated dependencies [0857788]
- - @ai-sdk/provider-utils@3.0.5
-
-## 1.0.9
-
-### Patch Changes
-
-- 8b96f99: feat(provider/gateway): Add DeepSeek v3.1 Base
-
-## 1.0.8
-
-### Patch Changes
-
-- Updated dependencies [68751f9]
- - @ai-sdk/provider-utils@3.0.4
-
-## 1.0.7
-
-### Patch Changes
-
-- 28a4006: feat (provider/gateway): add gemini-2.5-flash-lite model id
-
-## 1.0.6
-
-### Patch Changes
-
-- eefa730: refactor(provider/gateway): Make claude-sonnet-4 and similar the primary model slug for Anthropic v4 models
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.3
-
-## 1.0.5
-
-### Patch Changes
-
-- cf7b2ad: feat(provider/gateway): Add GLM-4.5V
-- Updated dependencies [38ac190]
- - @ai-sdk/provider-utils@3.0.2
-
-## 1.0.4
-
-### Patch Changes
-
-- 35f93ce: feat (provider/gateway): add new model ids
-
-## 1.0.3
-
-### Patch Changes
-
-- 893aed6: feat (provider/gateway): add anthropic claude 4.1 opus model id
-
-## 1.0.2
-
-### Patch Changes
-
-- 444df49: feat (provider/gateway): update model ids
-
-## 1.0.1
-
-### Patch Changes
-
-- 028fb9c: refactor(provider/gateway): Cleanup old gateway-embedding-options file
-- 6331826: feat(provider/gateway): Hide Cohere embedding models with no pricing info
-- Updated dependencies [90d212f]
- - @ai-sdk/provider-utils@3.0.1
-
-## 1.0.0
-
-### Patch Changes
-
-- 9e16bfd: feat (provider/gateway): update model ids
-- 0477a13: feat (provider/gateway): Add OpenAI embedding support
-- 26b6dd0: feat (providers/gateway): include deployment and request id
-- 30ab1de: feat (provider/gateway): add grok-4 model id
-- e2aceaf: feat: add raw chunk support
-- 97fedf9: feat (providers/gateway): include description and pricing info in model list
-- c91586a: chore (providers/gateway): update language model ids
-- 3cbcbb7: feat (providers/gateway): share common gateway error transform logic
-- fedb55e: feat (provider/gateway): add z.ai and glm-4.5 models
-- 6c2c708: feat (providers/gateway): initial gateway provider
-- 721775e: feat(provider/gateway): Generate new Gateway embedding model settings file
-- 70ebead: feat (provider/gateway): add qwen3 coder model id
-- f3639fa: feat (providers/gateway): improve oidc api key client auth flow
-- 8bd3624: feat (provider/gateway): update model ids to include vercel
-- c145d62: feat (providers/gateway): add createGateway shorthand alias for createGatewayProvider
-- f77bc38: chore (providers/gateway): update language model ids
-- 989ac75: chore (providers/gateway): update chat model ids
-- 7742ba3: feat (providers/gateway): add gateway error types with error detail
-- c190907: fix (provider/gateway): use zod v4
-- d1a034f: feature: using Zod 4 for internal stuff
-- d454e4b: fix (providers/gateway): fix timestamp error when streaming objects
-- cf1e00e: feat (provider/gateway): add devstral model id
-- cc21603: feat (provider/gateway): Add AI Gateway provider options (ordering)
-- 205077b: fix: improve Zod compatibility
-- e001ea1: fix (provider/gateway): remove unnecessary 'x-' prefix on auth method header
-- 27deb4d: feat (provider/gateway): Add providerMetadata to embeddings response
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0
- - @ai-sdk/provider@2.0.0
-
-## 1.0.0-beta.19
-
-### Patch Changes
-
-- 721775e: feat(provider/gateway): Generate new Gateway embedding model settings file
-- Updated dependencies [88a8ee5]
- - @ai-sdk/provider-utils@3.0.0-beta.10
-
-## 1.0.0-beta.18
-
-### Patch Changes
-
-- 27deb4d: feat (provider/gateway): Add providerMetadata to embeddings response
-- Updated dependencies [27deb4d]
- - @ai-sdk/provider@2.0.0-beta.2
- - @ai-sdk/provider-utils@3.0.0-beta.9
-
-## 1.0.0-beta.17
-
-### Patch Changes
-
-- Updated dependencies [dd5fd43]
- - @ai-sdk/provider-utils@3.0.0-beta.8
-
-## 1.0.0-beta.16
-
-### Patch Changes
-
-- fedb55e: feat (provider/gateway): add z.ai and glm-4.5 models
-
-## 1.0.0-beta.15
-
-### Patch Changes
-
-- Updated dependencies [e7fcc86]
- - @ai-sdk/provider-utils@3.0.0-beta.7
-
-## 1.0.0-beta.14
-
-### Patch Changes
-
-- Updated dependencies [ac34802]
- - @ai-sdk/provider-utils@3.0.0-beta.6
-
-## 1.0.0-beta.13
-
-### Patch Changes
-
-- 0477a13: feat (provider/gateway): Add OpenAI embedding support
-- cf1e00e: feat (provider/gateway): add devstral model id
-- cc21603: feat (provider/gateway): Add AI Gateway provider options (ordering)
-
-## 1.0.0-beta.12
-
-### Patch Changes
-
-- 70ebead: feat (provider/gateway): add qwen3 coder model id
-
-## 1.0.0-beta.11
-
-### Patch Changes
-
-- 8bd3624: feat (provider/gateway): update model ids to include vercel
-- e001ea1: fix (provider/gateway): remove unnecessary 'x-' prefix on auth method header
-
-## 1.0.0-beta.10
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-beta.5
-
-## 1.0.0-beta.9
-
-### Patch Changes
-
-- 205077b: fix: improve Zod compatibility
-- Updated dependencies [205077b]
- - @ai-sdk/provider-utils@3.0.0-beta.4
-
-## 1.0.0-beta.8
-
-### Patch Changes
-
-- Updated dependencies [05d2819]
- - @ai-sdk/provider-utils@3.0.0-beta.3
-
-## 1.0.0-beta.7
-
-### Patch Changes
-
-- c190907: fix (provider/gateway): use zod v4
-
-## 1.0.0-beta.6
-
-### Patch Changes
-
-- 9e16bfd: feat (provider/gateway): update model ids
-
-## 1.0.0-beta.5
-
-### Patch Changes
-
-- 30ab1de: feat (provider/gateway): add grok-4 model id
-
-## 1.0.0-beta.4
-
-### Patch Changes
-
-- 97fedf9: feat (providers/gateway): include description and pricing info in model list
-
-## 1.0.0-beta.3
-
-### Patch Changes
-
-- f3639fa: feat (providers/gateway): improve oidc api key client auth flow
-- d454e4b: fix (providers/gateway): fix timestamp error when streaming objects
-
-## 1.0.0-beta.2
-
-### Patch Changes
-
-- c91586a: chore (providers/gateway): update language model ids
-- d1a034f: feature: using Zod 4 for internal stuff
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-beta.2
-
-## 1.0.0-beta.1
-
-### Patch Changes
-
-- f77bc38: chore (providers/gateway): update language model ids
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-beta.1
- - @ai-sdk/provider-utils@3.0.0-beta.1
-
-## 1.0.0-alpha.15
-
-### Patch Changes
-
-- c145d62: feat (providers/gateway): add createGateway shorthand alias for createGatewayProvider
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-alpha.15
- - @ai-sdk/provider-utils@3.0.0-alpha.15
-
-## 1.0.0-alpha.14
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-alpha.14
- - @ai-sdk/provider-utils@3.0.0-alpha.14
-
-## 1.0.0-alpha.13
-
-### Patch Changes
-
-- Updated dependencies [68ecf2f]
- - @ai-sdk/provider@2.0.0-alpha.13
- - @ai-sdk/provider-utils@3.0.0-alpha.13
-
-## 1.0.0-alpha.12
-
-### Patch Changes
-
-- e2aceaf: feat: add raw chunk support
-- Updated dependencies [e2aceaf]
- - @ai-sdk/provider@2.0.0-alpha.12
- - @ai-sdk/provider-utils@3.0.0-alpha.12
-
-## 1.0.0-alpha.11
-
-### Patch Changes
-
-- Updated dependencies [c1e6647]
- - @ai-sdk/provider@2.0.0-alpha.11
- - @ai-sdk/provider-utils@3.0.0-alpha.11
-
-## 1.0.0-alpha.10
-
-### Patch Changes
-
-- Updated dependencies [c4df419]
- - @ai-sdk/provider@2.0.0-alpha.10
- - @ai-sdk/provider-utils@3.0.0-alpha.10
-
-## 1.0.0-alpha.9
-
-### Patch Changes
-
-- 26b6dd0: feat (providers/gateway): include deployment and request id
-- Updated dependencies [811dff3]
- - @ai-sdk/provider@2.0.0-alpha.9
- - @ai-sdk/provider-utils@3.0.0-alpha.9
-
-## 1.0.0-alpha.8
-
-### Patch Changes
-
-- 3cbcbb7: feat (providers/gateway): share common gateway error transform logic
-- 989ac75: chore (providers/gateway): update chat model ids
-- 7742ba3: feat (providers/gateway): add gateway error types with error detail
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-alpha.8
- - @ai-sdk/provider@2.0.0-alpha.8
-
-## 1.0.0-alpha.7
-
-### Patch Changes
-
-- Updated dependencies [5c56081]
- - @ai-sdk/provider@2.0.0-alpha.7
- - @ai-sdk/provider-utils@3.0.0-alpha.7
-
-## 1.0.0-alpha.6
-
-### Patch Changes
-
-- 6c2c708: feat (providers/gateway): initial gateway provider
-- Updated dependencies [0d2c085]
- - @ai-sdk/provider@2.0.0-alpha.6
- - @ai-sdk/provider-utils@3.0.0-alpha.6
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/LICENSE b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/LICENSE
deleted file mode 100644
index 6c16c29f4..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/LICENSE
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright 2023 Vercel, Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
\ No newline at end of file
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/README.md b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/README.md
deleted file mode 100644
index 579a96c3d..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/README.md
+++ /dev/null
@@ -1,44 +0,0 @@
-# AI SDK - Gateway Provider
-
-The Gateway provider for the [AI SDK](https://ai-sdk.dev/docs) allows the use of a wide variety of AI models and providers.
-
-## Setup
-
-The Gateway provider is available in the `@ai-sdk/gateway` module. You can install it with
-
-```bash
-npm i @ai-sdk/gateway
-```
-
-## Skill for Coding Agents
-
-If you use coding agents such as Claude Code or Cursor, we highly recommend adding the AI SDK skill to your repository:
-
-```shell
-npx skills add vercel/ai
-```
-
-## Provider Instance
-
-You can import the default provider instance `gateway` from `@ai-sdk/gateway`:
-
-```ts
-import { gateway } from '@ai-sdk/gateway';
-```
-
-## Example
-
-```ts
-import { gateway } from '@ai-sdk/gateway';
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: gateway('xai/grok-3-beta'),
- prompt:
- 'Tell me about the history of the San Francisco Mission-style burrito.',
-});
-```
-
-## Documentation
-
-Please check out the [AI SDK documentation](https://ai-sdk.dev/docs) for more information.
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/docs/00-ai-gateway.mdx b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/docs/00-ai-gateway.mdx
deleted file mode 100644
index 822e2b69e..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/docs/00-ai-gateway.mdx
+++ /dev/null
@@ -1,742 +0,0 @@
----
-title: AI Gateway
-description: Learn how to use the AI Gateway provider with the AI SDK.
----
-
-# AI Gateway Provider
-
-The [AI Gateway](https://vercel.com/docs/ai-gateway) provider connects you to models from multiple AI providers through a single interface. Instead of integrating with each provider separately, you can access OpenAI, Anthropic, Google, Meta, xAI, and other providers and their models.
-
-## Features
-
-- Access models from multiple providers without having to install additional provider modules/dependencies
-- Use the same code structure across different AI providers
-- Switch between models and providers easily
-- Automatic authentication when deployed on Vercel
-- View pricing information across providers
-- Observability for AI model usage through the Vercel dashboard
-
-## Setup
-
-The Vercel AI Gateway provider is part of the AI SDK.
-
-## Basic Usage
-
-For most use cases, you can use the AI Gateway directly with a model string:
-
-```ts
-// use plain model string with global provider
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: 'openai/gpt-5',
- prompt: 'Hello world',
-});
-```
-
-```ts
-// use provider instance (requires version 5.0.36 or later)
-import { generateText, gateway } from 'ai';
-
-const { text } = await generateText({
- model: gateway('openai/gpt-5'),
- prompt: 'Hello world',
-});
-```
-
-The AI SDK automatically uses the AI Gateway when you pass a model string in the `creator/model-name` format.
-
-## Provider Instance
-
-
- The `gateway` provider instance is available from the `ai` package in version
- 5.0.36 and later.
-
-
-You can also import the default provider instance `gateway` from `ai`:
-
-```ts
-import { gateway } from 'ai';
-```
-
-You may want to create a custom provider instance when you need to:
-
-- Set custom configuration options (API key, base URL, headers)
-- Use the provider in a [provider registry](/docs/ai-sdk-core/provider-management)
-- Wrap the provider with [middleware](/docs/ai-sdk-core/middleware)
-- Use different settings for different parts of your application
-
-To create a custom provider instance, import `createGateway` from `ai`:
-
-```ts
-import { createGateway } from 'ai';
-
-const gateway = createGateway({
- apiKey: process.env.AI_GATEWAY_API_KEY ?? '',
-});
-```
-
-You can use the following optional settings to customize the AI Gateway provider instance:
-
-- **baseURL** _string_
-
- Use a different URL prefix for API calls. The default prefix is `https://ai-gateway.vercel.sh/v3/ai`.
-
-- **apiKey** _string_
-
- API key that is being sent using the `Authorization` header. It defaults to
- the `AI_GATEWAY_API_KEY` environment variable.
-
-- **headers** _Record<string,string>_
-
- Custom headers to include in the requests.
-
-- **fetch** _(input: RequestInfo, init?: RequestInit) => Promise<Response>_
-
- Custom [fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch) implementation.
- Defaults to the global `fetch` function.
- You can use it as a middleware to intercept requests,
- or to provide a custom fetch implementation for e.g. testing.
-
-- **metadataCacheRefreshMillis** _number_
-
- How frequently to refresh the metadata cache in milliseconds. Defaults to 5 minutes (300,000ms).
-
-## Authentication
-
-The Gateway provider supports two authentication methods:
-
-### API Key Authentication
-
-Set your API key via environment variable:
-
-```bash
-AI_GATEWAY_API_KEY=your_api_key_here
-```
-
-Or pass it directly to the provider:
-
-```ts
-import { createGateway } from 'ai';
-
-const gateway = createGateway({
- apiKey: 'your_api_key_here',
-});
-```
-
-### OIDC Authentication (Vercel Deployments)
-
-When deployed to Vercel, the AI Gateway provider supports authenticating using [OIDC (OpenID Connect)
-tokens](https://vercel.com/docs/oidc) without API Keys.
-
-#### How OIDC Authentication Works
-
-1. **In Production/Preview Deployments**:
-
- - OIDC authentication is automatically handled
- - No manual configuration needed
- - Tokens are automatically obtained and refreshed
-
-2. **In Local Development**:
- - First, install and authenticate with the [Vercel CLI](https://vercel.com/docs/cli)
- - Run `vercel env pull` to download your project's OIDC token locally
- - For automatic token management:
- - Use `vercel dev` to start your development server - this will handle token refreshing automatically
- - For manual token management:
- - If not using `vercel dev`, note that OIDC tokens expire after 12 hours
- - You'll need to run `vercel env pull` again to refresh the token before it expires
-
-
- If an API Key is present (either passed directly or via environment), it will
- always be used, even if invalid.
-
-
-Read more about using OIDC tokens in the [Vercel AI Gateway docs](https://vercel.com/docs/ai-gateway#using-the-ai-gateway-with-a-vercel-oidc-token).
-
-## Bring Your Own Key (BYOK)
-
-You can connect your own provider credentials to use with Vercel AI Gateway. This lets you use your existing provider accounts and access private resources.
-
-To set up BYOK, add your provider credentials in your Vercel team's AI Gateway settings. Once configured, AI Gateway automatically uses your credentials. No code changes are needed.
-
-Learn more in the [BYOK documentation](https://vercel.com/docs/ai-gateway/byok).
-
-## Language Models
-
-You can create language models using a provider instance. The first argument is the model ID in the format `creator/model-name`:
-
-```ts
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: 'openai/gpt-5',
- prompt: 'Explain quantum computing in simple terms',
-});
-```
-
-AI Gateway language models can also be used in the `streamText` function and support structured data generation with [`Output`](/docs/reference/ai-sdk-core/output) (see [AI SDK Core](/docs/ai-sdk-core)).
-
-## Available Models
-
-The AI Gateway supports models from OpenAI, Anthropic, Google, Meta, xAI, Mistral, DeepSeek, Amazon Bedrock, Cohere, Perplexity, Alibaba, and other providers.
-
-For the complete list of available models, see the [AI Gateway documentation](https://vercel.com/docs/ai-gateway).
-
-## Dynamic Model Discovery
-
-You can discover available models programmatically:
-
-```ts
-import { gateway, generateText } from 'ai';
-
-const availableModels = await gateway.getAvailableModels();
-
-// List all available models
-availableModels.models.forEach(model => {
- console.log(`${model.id}: ${model.name}`);
- if (model.description) {
- console.log(` Description: ${model.description}`);
- }
- if (model.pricing) {
- console.log(` Input: $${model.pricing.input}/token`);
- console.log(` Output: $${model.pricing.output}/token`);
- if (model.pricing.cachedInputTokens) {
- console.log(
- ` Cached input (read): $${model.pricing.cachedInputTokens}/token`,
- );
- }
- if (model.pricing.cacheCreationInputTokens) {
- console.log(
- ` Cache creation (write): $${model.pricing.cacheCreationInputTokens}/token`,
- );
- }
- }
-});
-
-// Use any discovered model with plain string
-const { text } = await generateText({
- model: availableModels.models[0].id, // e.g., 'openai/gpt-4o'
- prompt: 'Hello world',
-});
-```
-
-## Credit Usage
-
-You can check your team's current credit balance and usage:
-
-```ts
-import { gateway } from 'ai';
-
-const credits = await gateway.getCredits();
-
-console.log(`Team balance: ${credits.balance} credits`);
-console.log(`Team total used: ${credits.total_used} credits`);
-```
-
-The `getCredits()` method returns your team's credit information based on the authenticated API key or OIDC token:
-
-- **balance** _number_ - Your team's current available credit balance
-- **total_used** _number_ - Total credits consumed by your team
-
-## Examples
-
-### Basic Text Generation
-
-```ts
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: 'anthropic/claude-sonnet-4',
- prompt: 'Write a haiku about programming',
-});
-
-console.log(text);
-```
-
-### Streaming
-
-```ts
-import { streamText } from 'ai';
-
-const { textStream } = await streamText({
- model: 'openai/gpt-5',
- prompt: 'Explain the benefits of serverless architecture',
-});
-
-for await (const textPart of textStream) {
- process.stdout.write(textPart);
-}
-```
-
-### Tool Usage
-
-```ts
-import { generateText, tool } from 'ai';
-import { z } from 'zod';
-
-const { text } = await generateText({
- model: 'xai/grok-4',
- prompt: 'What is the weather like in San Francisco?',
- tools: {
- getWeather: tool({
- description: 'Get the current weather for a location',
- parameters: z.object({
- location: z.string().describe('The location to get weather for'),
- }),
- execute: async ({ location }) => {
- // Your weather API call here
- return `It's sunny in ${location}`;
- },
- }),
- },
-});
-```
-
-### Provider-Executed Tools
-
-Some providers offer tools that are executed by the provider itself, such as [OpenAI's web search tool](/providers/ai-sdk-providers/openai#web-search-tool). To use these tools through AI Gateway, import the provider to access the tool definitions:
-
-```ts
-import { generateText, stepCountIs } from 'ai';
-import { openai } from '@ai-sdk/openai';
-
-const result = await generateText({
- model: 'openai/gpt-5-mini',
- prompt: 'What is the Vercel AI Gateway?',
- stopWhen: stepCountIs(10),
- tools: {
- web_search: openai.tools.webSearch({}),
- },
-});
-
-console.dir(result.text);
-```
-
-
- Some provider-executed tools require account-specific configuration (such as
- Claude Agent Skills) and may not work through AI Gateway. To use these tools,
- you must bring your own key (BYOK) directly to the provider.
-
-
-### Gateway Tools
-
-The AI Gateway provider includes built-in tools that are executed by the gateway itself. These tools can be used with any model through the gateway.
-
-#### Perplexity Search
-
-The Perplexity Search tool enables models to search the web using [Perplexity's search API](https://docs.perplexity.ai/guides/search-quickstart). This tool is executed by the AI Gateway and returns web search results that the model can use to provide up-to-date information.
-
-```ts
-import { gateway, generateText } from 'ai';
-
-const result = await generateText({
- model: 'openai/gpt-5-nano',
- prompt: 'Search for news about AI regulations in January 2025.',
- tools: {
- perplexity_search: gateway.tools.perplexitySearch(),
- },
-});
-
-console.log(result.text);
-console.log('Tool calls:', JSON.stringify(result.toolCalls, null, 2));
-console.log('Tool results:', JSON.stringify(result.toolResults, null, 2));
-```
-
-You can also configure the search with optional parameters:
-
-```ts
-import { gateway, generateText } from 'ai';
-
-const result = await generateText({
- model: 'openai/gpt-5-nano',
- prompt:
- 'Search for news about AI regulations from the first week of January 2025.',
- tools: {
- perplexity_search: gateway.tools.perplexitySearch({
- maxResults: 5,
- searchLanguageFilter: ['en'],
- country: 'US',
- searchDomainFilter: ['reuters.com', 'bbc.com', 'nytimes.com'],
- }),
- },
-});
-
-console.log(result.text);
-console.log('Tool calls:', JSON.stringify(result.toolCalls, null, 2));
-console.log('Tool results:', JSON.stringify(result.toolResults, null, 2));
-```
-
-The Perplexity Search tool supports the following optional configuration options:
-
-- **maxResults** _number_
-
- The maximum number of search results to return (1-20, default: 10).
-
-- **maxTokensPerPage** _number_
-
- The maximum number of tokens to extract per search result page (256-2048, default: 2048).
-
-- **maxTokens** _number_
-
- The maximum total tokens across all search results (default: 25000, max: 1000000).
-
-- **searchLanguageFilter** _string[]_
-
- Filter search results by language using ISO 639-1 language codes (e.g., `['en']` for English, `['en', 'es']` for English and Spanish).
-
-- **country** _string_
-
- Filter search results by country using ISO 3166-1 alpha-2 country codes (e.g., `'US'` for United States, `'GB'` for United Kingdom).
-
-- **searchDomainFilter** _string[]_
-
- Limit search results to specific domains (e.g., `['reuters.com', 'bbc.com']`). This is useful for restricting results to trusted sources.
-
-- **searchRecencyFilter** _'day' | 'week' | 'month' | 'year'_
-
- Filter search results by relative time period. Useful for always getting recent results (e.g., 'week' for results from the last week).
-
-The tool works with both `generateText` and `streamText`:
-
-```ts
-import { gateway, streamText } from 'ai';
-
-const result = streamText({
- model: 'openai/gpt-5-nano',
- prompt: 'Search for the latest news about AI regulations.',
- tools: {
- perplexity_search: gateway.tools.perplexitySearch(),
- },
-});
-
-for await (const part of result.fullStream) {
- switch (part.type) {
- case 'text-delta':
- process.stdout.write(part.text);
- break;
- case 'tool-call':
- console.log('\nTool call:', JSON.stringify(part, null, 2));
- break;
- case 'tool-result':
- console.log('\nTool result:', JSON.stringify(part, null, 2));
- break;
- }
-}
-```
-
-#### Parallel Search
-
-The Parallel Search tool enables models to search the web using [Parallel AI's Search API](https://docs.parallel.ai/api-reference/search-beta/search). This tool is optimized for LLM consumption, returning relevant excerpts from web pages that can replace multiple keyword searches with a single call.
-
-```ts
-import { gateway, generateText } from 'ai';
-
-const result = await generateText({
- model: 'openai/gpt-5-nano',
- prompt: 'Research the latest developments in quantum computing.',
- tools: {
- parallel_search: gateway.tools.parallelSearch(),
- },
-});
-
-console.log(result.text);
-console.log('Tool calls:', JSON.stringify(result.toolCalls, null, 2));
-console.log('Tool results:', JSON.stringify(result.toolResults, null, 2));
-```
-
-You can also configure the search with optional parameters:
-
-```ts
-import { gateway, generateText } from 'ai';
-
-const result = await generateText({
- model: 'openai/gpt-5-nano',
- prompt: 'Find detailed information about TypeScript 5.0 features.',
- tools: {
- parallel_search: gateway.tools.parallelSearch({
- mode: 'agentic',
- maxResults: 5,
- sourcePolicy: {
- includeDomains: ['typescriptlang.org', 'github.com'],
- },
- excerpts: {
- maxCharsPerResult: 8000,
- },
- }),
- },
-});
-
-console.log(result.text);
-console.log('Tool calls:', JSON.stringify(result.toolCalls, null, 2));
-console.log('Tool results:', JSON.stringify(result.toolResults, null, 2));
-```
-
-The Parallel Search tool supports the following optional configuration options:
-
-- **mode** _'one-shot' | 'agentic'_
-
- Mode preset for different use cases:
-
- - `'one-shot'` - Comprehensive results with longer excerpts for single-response answers (default)
- - `'agentic'` - Concise, token-efficient results optimized for multi-step agentic workflows
-
-- **maxResults** _number_
-
- Maximum number of results to return (1-20). Defaults to 10 if not specified.
-
-- **sourcePolicy** _object_
-
- Source policy for controlling which domains to include/exclude:
-
- - `includeDomains` - List of domains to include in search results
- - `excludeDomains` - List of domains to exclude from search results
- - `afterDate` - Only include results published after this date (ISO 8601 format)
-
-- **excerpts** _object_
-
- Excerpt configuration for controlling result length:
-
- - `maxCharsPerResult` - Maximum characters per result
- - `maxCharsTotal` - Maximum total characters across all results
-
-- **fetchPolicy** _object_
-
- Fetch policy for controlling content freshness:
-
- - `maxAgeSeconds` - Maximum age in seconds for cached content (set to 0 for always fresh)
-
-The tool works with both `generateText` and `streamText`:
-
-```ts
-import { gateway, streamText } from 'ai';
-
-const result = streamText({
- model: 'openai/gpt-5-nano',
- prompt: 'Research the latest AI safety guidelines.',
- tools: {
- parallel_search: gateway.tools.parallelSearch(),
- },
-});
-
-for await (const part of result.fullStream) {
- switch (part.type) {
- case 'text-delta':
- process.stdout.write(part.text);
- break;
- case 'tool-call':
- console.log('\nTool call:', JSON.stringify(part, null, 2));
- break;
- case 'tool-result':
- console.log('\nTool result:', JSON.stringify(part, null, 2));
- break;
- }
-}
-```
-
-### Usage Tracking with User and Tags
-
-Track usage per end-user and categorize requests with tags:
-
-```ts
-import type { GatewayLanguageModelOptions } from '@ai-sdk/gateway';
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: 'openai/gpt-5',
- prompt: 'Summarize this document...',
- providerOptions: {
- gateway: {
- user: 'user-abc-123', // Track usage for this specific end-user
- tags: ['document-summary', 'premium-feature'], // Categorize for reporting
- } satisfies GatewayLanguageModelOptions,
- },
-});
-```
-
-This allows you to:
-
-- View usage and costs broken down by end-user in your analytics
-- Filter and analyze spending by feature or use case using tags
-- Track which users or features are driving the most AI usage
-
-## Provider Options
-
-The AI Gateway provider accepts provider options that control routing behavior and provider-specific configurations.
-
-### Gateway Provider Options
-
-You can use the `gateway` key in `providerOptions` to control how AI Gateway routes requests:
-
-```ts
-import type { GatewayLanguageModelOptions } from '@ai-sdk/gateway';
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: 'anthropic/claude-sonnet-4',
- prompt: 'Explain quantum computing',
- providerOptions: {
- gateway: {
- order: ['vertex', 'anthropic'], // Try Vertex AI first, then Anthropic
- only: ['vertex', 'anthropic'], // Only use these providers
- } satisfies GatewayLanguageModelOptions,
- },
-});
-```
-
-The following gateway provider options are available:
-
-- **order** _string[]_
-
- Specifies the sequence of providers to attempt when routing requests. The gateway will try providers in the order specified. If a provider fails or is unavailable, it will move to the next provider in the list.
-
- Example: `order: ['bedrock', 'anthropic']` will attempt Amazon Bedrock first, then fall back to Anthropic.
-
-- **only** _string[]_
-
- Restricts routing to only the specified providers. When set, the gateway will never route to providers not in this list, even if they would otherwise be available.
-
- Example: `only: ['anthropic', 'vertex']` will only allow routing to Anthropic or Vertex AI.
-
-- **models** _string[]_
-
- Specifies fallback models to use when the primary model fails or is unavailable. The gateway will try the primary model first (specified in the `model` parameter), then try each model in this array in order until one succeeds.
-
- Example: `models: ['openai/gpt-5-nano', 'gemini-2.0-flash']` will try the fallback models in order if the primary model fails.
-
-- **user** _string_
-
- Optional identifier for the end user on whose behalf the request is being made. This is used for spend tracking and attribution purposes, allowing you to track usage per end-user in your application.
-
- Example: `user: 'user-123'` will associate this request with end-user ID "user-123" in usage reports.
-
-- **tags** _string[]_
-
- Optional array of tags for categorizing and filtering usage in reports. Useful for tracking spend by feature, prompt version, or any other dimension relevant to your application.
-
- Example: `tags: ['chat', 'v2']` will tag this request with "chat" and "v2" for filtering in usage analytics.
-
-- **byok** _Record<string, Array<Record<string, unknown>>>_
-
- Request-scoped BYOK (Bring Your Own Key) credentials to use for this request. When provided, any cached BYOK credentials configured in the gateway system are not considered. Requests may still fall back to use system credentials if the provided credentials fail.
-
- Each provider can have multiple credentials (tried in order). The structure is a record where keys are provider slugs and values are arrays of credential objects.
-
- Examples:
-
- - Single provider: `byok: { 'anthropic': [{ apiKey: 'sk-ant-...' }] }`
- - Multiple credentials: `byok: { 'vertex': [{ project: 'proj-1', googleCredentials: { privateKey: '...', clientEmail: '...' } }, { project: 'proj-2', googleCredentials: { privateKey: '...', clientEmail: '...' } }] }`
- - Multiple providers: `byok: { 'anthropic': [{ apiKey: '...' }], 'bedrock': [{ accessKeyId: '...', secretAccessKey: '...' }] }`
-
-- **zeroDataRetention** _boolean_
-
- Restricts routing requests to providers that have zero data retention policies.
-
-- **providerTimeouts** _object_
-
- Per-provider timeouts for BYOK credentials in milliseconds. Controls how long to wait for a provider to start responding before falling back to the next available provider.
-
- Example: `providerTimeouts: { byok: { openai: 5000, anthropic: 2000 } }`
-
- For full details, see [Provider Timeouts](https://vercel.com/docs/ai-gateway/models-and-providers/provider-timeouts).
-
-You can combine these options to have fine-grained control over routing and tracking:
-
-```ts
-import type { GatewayLanguageModelOptions } from '@ai-sdk/gateway';
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: 'anthropic/claude-sonnet-4',
- prompt: 'Write a haiku about programming',
- providerOptions: {
- gateway: {
- order: ['vertex'], // Prefer Vertex AI
- only: ['anthropic', 'vertex'], // Only allow these providers
- } satisfies GatewayLanguageModelOptions,
- },
-});
-```
-
-#### Model Fallbacks Example
-
-The `models` option enables automatic fallback to alternative models when the primary model fails:
-
-```ts
-import type { GatewayLanguageModelOptions } from '@ai-sdk/gateway';
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: 'openai/gpt-4o', // Primary model
- prompt: 'Write a TypeScript haiku',
- providerOptions: {
- gateway: {
- models: ['openai/gpt-5-nano', 'gemini-2.0-flash'], // Fallback models
- } satisfies GatewayLanguageModelOptions,
- },
-});
-
-// This will:
-// 1. Try openai/gpt-4o first
-// 2. If it fails, try openai/gpt-5-nano
-// 3. If that fails, try gemini-2.0-flash
-// 4. Return the result from the first model that succeeds
-```
-
-#### Zero Data Retention Example
-
-Set `zeroDataRetention` to true to ensure requests are only routed to providers
-that have zero data retention policies. When `zeroDataRetention` is `false` or not
-specified, there is no enforcement of restricting routing.
-
-```ts
-import type { GatewayLanguageModelOptions } from '@ai-sdk/gateway';
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: 'anthropic/claude-sonnet-4.5',
- prompt: 'Analyze this sensitive document...',
- providerOptions: {
- gateway: {
- zeroDataRetention: true,
- } satisfies GatewayLanguageModelOptions,
- },
-});
-```
-
-### Provider-Specific Options
-
-When using provider-specific options through AI Gateway, use the actual provider name (e.g. `anthropic`, `openai`, not `gateway`) as the key:
-
-```ts
-import type { AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
-import type { GatewayLanguageModelOptions } from '@ai-sdk/gateway';
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: 'anthropic/claude-sonnet-4',
- prompt: 'Explain quantum computing',
- providerOptions: {
- gateway: {
- order: ['vertex', 'anthropic'],
- } satisfies GatewayLanguageModelOptions,
- anthropic: {
- thinking: { type: 'enabled', budgetTokens: 12000 },
- } satisfies AnthropicLanguageModelOptions,
- },
-});
-```
-
-This works with any provider supported by AI Gateway. Each provider has its own set of options - see the individual [provider documentation pages](/providers/ai-sdk-providers) for details on provider-specific options.
-
-### Available Providers
-
-AI Gateway supports routing to 20+ providers.
-
-For a complete list of available providers and their slugs, see the [AI Gateway documentation](https://vercel.com/docs/ai-gateway/provider-options#available-providers).
-
-## Model Capabilities
-
-Model capabilities depend on the specific provider and model you're using. For detailed capability information, see:
-
-- [AI Gateway provider options](https://vercel.com/docs/ai-gateway/provider-options#available-providers) for an overview of available providers
-- Individual [AI SDK provider pages](/providers/ai-sdk-providers) for specific model capabilities and features
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/package.json b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/package.json
deleted file mode 100644
index 66da58a04..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/package.json
+++ /dev/null
@@ -1,78 +0,0 @@
-{
- "name": "@ai-sdk/gateway",
- "private": false,
- "version": "3.0.80",
- "license": "Apache-2.0",
- "sideEffects": false,
- "main": "./dist/index.js",
- "module": "./dist/index.mjs",
- "types": "./dist/index.d.ts",
- "files": [
- "dist/**/*",
- "docs/**/*",
- "src",
- "!src/**/*.test.ts",
- "!src/**/*.test-d.ts",
- "!src/**/__snapshots__",
- "!src/**/__fixtures__",
- "CHANGELOG.md",
- "README.md"
- ],
- "directories": {
- "doc": "./docs"
- },
- "exports": {
- "./package.json": "./package.json",
- ".": {
- "types": "./dist/index.d.ts",
- "import": "./dist/index.mjs",
- "require": "./dist/index.js"
- }
- },
- "dependencies": {
- "@vercel/oidc": "3.1.0",
- "@ai-sdk/provider": "3.0.8",
- "@ai-sdk/provider-utils": "4.0.21"
- },
- "devDependencies": {
- "@types/node": "18.15.11",
- "tsup": "^8",
- "tsx": "4.19.2",
- "typescript": "5.8.3",
- "zod": "3.25.76",
- "@ai-sdk/test-server": "1.0.3",
- "@vercel/ai-tsconfig": "0.0.0"
- },
- "peerDependencies": {
- "zod": "^3.25.76 || ^4.1.8"
- },
- "engines": {
- "node": ">=18"
- },
- "publishConfig": {
- "access": "public"
- },
- "homepage": "https://ai-sdk.dev/docs",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/vercel/ai.git"
- },
- "bugs": {
- "url": "https://github.com/vercel/ai/issues"
- },
- "keywords": [
- "ai"
- ],
- "scripts": {
- "build": "pnpm clean && tsup --tsconfig tsconfig.build.json",
- "build:watch": "pnpm clean && tsup --watch",
- "clean": "del-cli dist docs *.tsbuildinfo",
- "generate-model-settings": "tsx scripts/generate-model-settings.ts",
- "type-check": "tsc --build",
- "test": "pnpm test:node && pnpm test:edge",
- "test:update": "pnpm test:node -u",
- "test:watch": "vitest --config vitest.node.config.js",
- "test:edge": "vitest --config vitest.edge.config.js --run",
- "test:node": "vitest --config vitest.node.config.js --run"
- }
-}
\ No newline at end of file
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/as-gateway-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/as-gateway-error.ts
deleted file mode 100644
index 07ae080ef..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/as-gateway-error.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import { APICallError } from '@ai-sdk/provider';
-import { extractApiCallResponse, GatewayError } from '.';
-import { createGatewayErrorFromResponse } from './create-gateway-error';
-import { GatewayTimeoutError } from './gateway-timeout-error';
-
-/**
- * Checks if an error is a timeout error from undici.
- * Only checks undici-specific error codes to avoid false positives.
- */
-function isTimeoutError(error: unknown): boolean {
- if (!(error instanceof Error)) {
- return false;
- }
-
- // Check for undici-specific timeout error codes
- const errorCode = (error as any).code;
- if (typeof errorCode === 'string') {
- const undiciTimeoutCodes = [
- 'UND_ERR_HEADERS_TIMEOUT',
- 'UND_ERR_BODY_TIMEOUT',
- 'UND_ERR_CONNECT_TIMEOUT',
- ];
- return undiciTimeoutCodes.includes(errorCode);
- }
-
- return false;
-}
-
-export async function asGatewayError(
- error: unknown,
- authMethod?: 'api-key' | 'oidc',
-) {
- if (GatewayError.isInstance(error)) {
- return error;
- }
-
- // Check if this is a timeout error (or has a timeout error in the cause chain)
- if (isTimeoutError(error)) {
- return GatewayTimeoutError.createTimeoutError({
- originalMessage: error instanceof Error ? error.message : 'Unknown error',
- cause: error,
- });
- }
-
- // Check if this is an APICallError caused by a timeout
- if (APICallError.isInstance(error)) {
- // Check if the cause is a timeout error
- if (error.cause && isTimeoutError(error.cause)) {
- return GatewayTimeoutError.createTimeoutError({
- originalMessage: error.message,
- cause: error,
- });
- }
-
- return await createGatewayErrorFromResponse({
- response: extractApiCallResponse(error),
- statusCode: error.statusCode ?? 500,
- defaultMessage: 'Gateway request failed',
- cause: error,
- authMethod,
- });
- }
-
- return await createGatewayErrorFromResponse({
- response: {},
- statusCode: 500,
- defaultMessage:
- error instanceof Error
- ? `Gateway request failed: ${error.message}`
- : 'Unknown Gateway error',
- cause: error,
- authMethod,
- });
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/create-gateway-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/create-gateway-error.ts
deleted file mode 100644
index 68a827de1..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/create-gateway-error.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-import { z } from 'zod/v4';
-import type { GatewayError } from './gateway-error';
-import { GatewayAuthenticationError } from './gateway-authentication-error';
-import { GatewayInvalidRequestError } from './gateway-invalid-request-error';
-import { GatewayRateLimitError } from './gateway-rate-limit-error';
-import {
- GatewayModelNotFoundError,
- modelNotFoundParamSchema,
-} from './gateway-model-not-found-error';
-import { GatewayInternalServerError } from './gateway-internal-server-error';
-import { GatewayResponseError } from './gateway-response-error';
-import {
- InferSchema,
- lazySchema,
- safeValidateTypes,
- validateTypes,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-
-export async function createGatewayErrorFromResponse({
- response,
- statusCode,
- defaultMessage = 'Gateway request failed',
- cause,
- authMethod,
-}: {
- response: unknown;
- statusCode: number;
- defaultMessage?: string;
- cause?: unknown;
- authMethod?: 'api-key' | 'oidc';
-}): Promise {
- const parseResult = await safeValidateTypes({
- value: response,
- schema: gatewayErrorResponseSchema,
- });
-
- if (!parseResult.success) {
- // Try to extract generationId even if validation failed
- const rawGenerationId =
- typeof response === 'object' &&
- response !== null &&
- 'generationId' in response
- ? (response as { generationId?: string }).generationId
- : undefined;
-
- return new GatewayResponseError({
- message: `Invalid error response format: ${defaultMessage}`,
- statusCode,
- response,
- validationError: parseResult.error,
- cause,
- generationId: rawGenerationId,
- });
- }
-
- const validatedResponse: GatewayErrorResponse = parseResult.value;
- const errorType = validatedResponse.error.type;
- const message = validatedResponse.error.message;
- const generationId = validatedResponse.generationId ?? undefined;
-
- switch (errorType) {
- case 'authentication_error':
- return GatewayAuthenticationError.createContextualError({
- apiKeyProvided: authMethod === 'api-key',
- oidcTokenProvided: authMethod === 'oidc',
- statusCode,
- cause,
- generationId,
- });
- case 'invalid_request_error':
- return new GatewayInvalidRequestError({
- message,
- statusCode,
- cause,
- generationId,
- });
- case 'rate_limit_exceeded':
- return new GatewayRateLimitError({
- message,
- statusCode,
- cause,
- generationId,
- });
- case 'model_not_found': {
- const modelResult = await safeValidateTypes({
- value: validatedResponse.error.param,
- schema: modelNotFoundParamSchema,
- });
-
- return new GatewayModelNotFoundError({
- message,
- statusCode,
- modelId: modelResult.success ? modelResult.value.modelId : undefined,
- cause,
- generationId,
- });
- }
- case 'internal_server_error':
- return new GatewayInternalServerError({
- message,
- statusCode,
- cause,
- generationId,
- });
- default:
- return new GatewayInternalServerError({
- message,
- statusCode,
- cause,
- generationId,
- });
- }
-}
-
-const gatewayErrorResponseSchema = lazySchema(() =>
- zodSchema(
- z.object({
- error: z.object({
- message: z.string(),
- type: z.string().nullish(),
- param: z.unknown().nullish(),
- code: z.union([z.string(), z.number()]).nullish(),
- }),
- generationId: z.string().nullish(),
- }),
- ),
-);
-
-export type GatewayErrorResponse = InferSchema<
- typeof gatewayErrorResponseSchema
->;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/extract-api-call-response.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/extract-api-call-response.ts
deleted file mode 100644
index e99662aac..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/extract-api-call-response.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { APICallError } from '@ai-sdk/provider';
-
-export function extractApiCallResponse(error: APICallError): unknown {
- if (error.data !== undefined) {
- return error.data;
- }
- if (error.responseBody != null) {
- try {
- return JSON.parse(error.responseBody);
- } catch {
- return error.responseBody;
- }
- }
- return {};
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-authentication-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-authentication-error.ts
deleted file mode 100644
index f62136104..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-authentication-error.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import { GatewayError } from './gateway-error';
-
-const name = 'GatewayAuthenticationError';
-const marker = `vercel.ai.gateway.error.${name}`;
-const symbol = Symbol.for(marker);
-
-/**
- * Authentication failed - invalid API key or OIDC token
- */
-export class GatewayAuthenticationError extends GatewayError {
- private readonly [symbol] = true; // used in isInstance
-
- readonly name = name;
- readonly type = 'authentication_error';
-
- constructor({
- message = 'Authentication failed',
- statusCode = 401,
- cause,
- generationId,
- }: {
- message?: string;
- statusCode?: number;
- cause?: unknown;
- generationId?: string;
- } = {}) {
- super({ message, statusCode, cause, generationId });
- }
-
- static isInstance(error: unknown): error is GatewayAuthenticationError {
- return GatewayError.hasMarker(error) && symbol in error;
- }
-
- /**
- * Creates a contextual error message when authentication fails
- */
- static createContextualError({
- apiKeyProvided,
- oidcTokenProvided,
- message = 'Authentication failed',
- statusCode = 401,
- cause,
- generationId,
- }: {
- apiKeyProvided: boolean;
- oidcTokenProvided: boolean;
- message?: string;
- statusCode?: number;
- cause?: unknown;
- generationId?: string;
- }): GatewayAuthenticationError {
- let contextualMessage: string;
-
- if (apiKeyProvided) {
- contextualMessage = `AI Gateway authentication failed: Invalid API key.
-
-Create a new API key: https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai%2Fapi-keys
-
-Provide via 'apiKey' option or 'AI_GATEWAY_API_KEY' environment variable.`;
- } else if (oidcTokenProvided) {
- contextualMessage = `AI Gateway authentication failed: Invalid OIDC token.
-
-Run 'npx vercel link' to link your project, then 'vc env pull' to fetch the token.
-
-Alternatively, use an API key: https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai%2Fapi-keys`;
- } else {
- contextualMessage = `AI Gateway authentication failed: No authentication provided.
-
-Option 1 - API key:
-Create an API key: https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai%2Fapi-keys
-Provide via 'apiKey' option or 'AI_GATEWAY_API_KEY' environment variable.
-
-Option 2 - OIDC token:
-Run 'npx vercel link' to link your project, then 'vc env pull' to fetch the token.`;
- }
-
- return new GatewayAuthenticationError({
- message: contextualMessage,
- statusCode,
- cause,
- generationId,
- });
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-error.ts
deleted file mode 100644
index 669dcc294..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-error.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-const marker = 'vercel.ai.gateway.error';
-const symbol = Symbol.for(marker);
-
-export abstract class GatewayError extends Error {
- private readonly [symbol] = true; // used in isInstance
-
- abstract readonly name: string;
- abstract readonly type: string;
- readonly statusCode: number;
- readonly cause?: unknown;
- readonly generationId?: string;
-
- constructor({
- message,
- statusCode = 500,
- cause,
- generationId,
- }: {
- message: string;
- statusCode?: number;
- cause?: unknown;
- generationId?: string;
- }) {
- super(generationId ? `${message} [${generationId}]` : message);
- this.statusCode = statusCode;
- this.cause = cause;
- this.generationId = generationId;
- }
-
- /**
- * Checks if the given error is a Gateway Error.
- * @param {unknown} error - The error to check.
- * @returns {boolean} True if the error is a Gateway Error, false otherwise.
- */
- static isInstance(error: unknown): error is GatewayError {
- return GatewayError.hasMarker(error);
- }
-
- static hasMarker(error: unknown): error is GatewayError {
- return (
- typeof error === 'object' &&
- error !== null &&
- symbol in error &&
- (error as any)[symbol] === true
- );
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-internal-server-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-internal-server-error.ts
deleted file mode 100644
index 4b2e99909..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-internal-server-error.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { GatewayError } from './gateway-error';
-
-const name = 'GatewayInternalServerError';
-const marker = `vercel.ai.gateway.error.${name}`;
-const symbol = Symbol.for(marker);
-
-/**
- * Internal server error from the Gateway
- */
-export class GatewayInternalServerError extends GatewayError {
- private readonly [symbol] = true; // used in isInstance
-
- readonly name = name;
- readonly type = 'internal_server_error';
-
- constructor({
- message = 'Internal server error',
- statusCode = 500,
- cause,
- generationId,
- }: {
- message?: string;
- statusCode?: number;
- cause?: unknown;
- generationId?: string;
- } = {}) {
- super({ message, statusCode, cause, generationId });
- }
-
- static isInstance(error: unknown): error is GatewayInternalServerError {
- return GatewayError.hasMarker(error) && symbol in error;
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-invalid-request-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-invalid-request-error.ts
deleted file mode 100644
index c7ec507e9..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-invalid-request-error.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { GatewayError } from './gateway-error';
-
-const name = 'GatewayInvalidRequestError';
-const marker = `vercel.ai.gateway.error.${name}`;
-const symbol = Symbol.for(marker);
-
-/**
- * Invalid request - missing headers, malformed data, etc.
- */
-export class GatewayInvalidRequestError extends GatewayError {
- private readonly [symbol] = true; // used in isInstance
-
- readonly name = name;
- readonly type = 'invalid_request_error';
-
- constructor({
- message = 'Invalid request',
- statusCode = 400,
- cause,
- generationId,
- }: {
- message?: string;
- statusCode?: number;
- cause?: unknown;
- generationId?: string;
- } = {}) {
- super({ message, statusCode, cause, generationId });
- }
-
- static isInstance(error: unknown): error is GatewayInvalidRequestError {
- return GatewayError.hasMarker(error) && symbol in error;
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-model-not-found-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-model-not-found-error.ts
deleted file mode 100644
index 6f23fda81..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-model-not-found-error.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { z } from 'zod/v4';
-import { GatewayError } from './gateway-error';
-import { lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-
-const name = 'GatewayModelNotFoundError';
-const marker = `vercel.ai.gateway.error.${name}`;
-const symbol = Symbol.for(marker);
-
-export const modelNotFoundParamSchema = lazySchema(() =>
- zodSchema(
- z.object({
- modelId: z.string(),
- }),
- ),
-);
-
-/**
- * Model not found or not available
- */
-export class GatewayModelNotFoundError extends GatewayError {
- private readonly [symbol] = true; // used in isInstance
-
- readonly name = name;
- readonly type = 'model_not_found';
- readonly modelId?: string;
-
- constructor({
- message = 'Model not found',
- statusCode = 404,
- modelId,
- cause,
- generationId,
- }: {
- message?: string;
- statusCode?: number;
- modelId?: string;
- cause?: unknown;
- generationId?: string;
- } = {}) {
- super({ message, statusCode, cause, generationId });
- this.modelId = modelId;
- }
-
- static isInstance(error: unknown): error is GatewayModelNotFoundError {
- return GatewayError.hasMarker(error) && symbol in error;
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-rate-limit-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-rate-limit-error.ts
deleted file mode 100644
index 09867eead..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-rate-limit-error.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { GatewayError } from './gateway-error';
-
-const name = 'GatewayRateLimitError';
-const marker = `vercel.ai.gateway.error.${name}`;
-const symbol = Symbol.for(marker);
-
-/**
- * Rate limit exceeded.
- */
-export class GatewayRateLimitError extends GatewayError {
- private readonly [symbol] = true; // used in isInstance
-
- readonly name = name;
- readonly type = 'rate_limit_exceeded';
-
- constructor({
- message = 'Rate limit exceeded',
- statusCode = 429,
- cause,
- generationId,
- }: {
- message?: string;
- statusCode?: number;
- cause?: unknown;
- generationId?: string;
- } = {}) {
- super({ message, statusCode, cause, generationId });
- }
-
- static isInstance(error: unknown): error is GatewayRateLimitError {
- return GatewayError.hasMarker(error) && symbol in error;
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-response-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-response-error.ts
deleted file mode 100644
index 7bc05d7c7..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-response-error.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { TypeValidationError } from '@ai-sdk/provider';
-import { GatewayError } from './gateway-error';
-
-const name = 'GatewayResponseError';
-const marker = `vercel.ai.gateway.error.${name}`;
-const symbol = Symbol.for(marker);
-
-/**
- * Gateway response parsing error
- */
-export class GatewayResponseError extends GatewayError {
- private readonly [symbol] = true; // used in isInstance
-
- readonly name = name;
- readonly type = 'response_error';
- readonly response?: unknown;
- readonly validationError?: TypeValidationError;
-
- constructor({
- message = 'Invalid response from Gateway',
- statusCode = 502,
- response,
- validationError,
- cause,
- generationId,
- }: {
- message?: string;
- statusCode?: number;
- response?: unknown;
- validationError?: TypeValidationError;
- cause?: unknown;
- generationId?: string;
- } = {}) {
- super({ message, statusCode, cause, generationId });
- this.response = response;
- this.validationError = validationError;
- }
-
- static isInstance(error: unknown): error is GatewayResponseError {
- return GatewayError.hasMarker(error) && symbol in error;
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-timeout-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-timeout-error.ts
deleted file mode 100644
index d99df6293..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/gateway-timeout-error.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { GatewayError } from './gateway-error';
-
-const name = 'GatewayTimeoutError';
-const marker = `vercel.ai.gateway.error.${name}`;
-const symbol = Symbol.for(marker);
-
-/**
- * Client request timed out before receiving a response.
- */
-export class GatewayTimeoutError extends GatewayError {
- private readonly [symbol] = true; // used in isInstance
-
- readonly name = name;
- readonly type = 'timeout_error';
-
- constructor({
- message = 'Request timed out',
- statusCode = 408,
- cause,
- generationId,
- }: {
- message?: string;
- statusCode?: number;
- cause?: unknown;
- generationId?: string;
- } = {}) {
- super({ message, statusCode, cause, generationId });
- }
-
- static isInstance(error: unknown): error is GatewayTimeoutError {
- return GatewayError.hasMarker(error) && symbol in error;
- }
-
- /**
- * Creates a helpful timeout error message with troubleshooting guidance
- */
- static createTimeoutError({
- originalMessage,
- statusCode = 408,
- cause,
- generationId,
- }: {
- originalMessage: string;
- statusCode?: number;
- cause?: unknown;
- generationId?: string;
- }): GatewayTimeoutError {
- const message = `Gateway request timed out: ${originalMessage}
-
- This is a client-side timeout. To resolve this, increase your timeout configuration: https://vercel.com/docs/ai-gateway/capabilities/video-generation#extending-timeouts-for-node.js`;
-
- return new GatewayTimeoutError({
- message,
- statusCode,
- cause,
- generationId,
- });
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/index.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/index.ts
deleted file mode 100644
index e5d8f7f7e..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/index.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-export { asGatewayError } from './as-gateway-error';
-export {
- createGatewayErrorFromResponse,
- type GatewayErrorResponse,
-} from './create-gateway-error';
-export { extractApiCallResponse } from './extract-api-call-response';
-export { GatewayError } from './gateway-error';
-export { GatewayAuthenticationError } from './gateway-authentication-error';
-export { GatewayInternalServerError } from './gateway-internal-server-error';
-export { GatewayInvalidRequestError } from './gateway-invalid-request-error';
-export {
- GatewayModelNotFoundError,
- modelNotFoundParamSchema,
-} from './gateway-model-not-found-error';
-export { GatewayRateLimitError } from './gateway-rate-limit-error';
-export { GatewayResponseError } from './gateway-response-error';
-export { GatewayTimeoutError } from './gateway-timeout-error';
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/parse-auth-method.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/parse-auth-method.ts
deleted file mode 100644
index 3efe41a6f..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/errors/parse-auth-method.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { z } from 'zod/v4';
-import {
- lazySchema,
- safeValidateTypes,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-
-export const GATEWAY_AUTH_METHOD_HEADER = 'ai-gateway-auth-method' as const;
-
-export async function parseAuthMethod(
- headers: Record,
-) {
- const result = await safeValidateTypes({
- value: headers[GATEWAY_AUTH_METHOD_HEADER],
- schema: gatewayAuthMethodSchema,
- });
-
- return result.success ? result.value : undefined;
-}
-
-const gatewayAuthMethodSchema = lazySchema(() =>
- zodSchema(z.union([z.literal('api-key'), z.literal('oidc')])),
-);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-config.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-config.ts
deleted file mode 100644
index 3edf37da6..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-config.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import type { FetchFunction, Resolvable } from '@ai-sdk/provider-utils';
-
-export type GatewayConfig = {
- baseURL: string;
- headers: () => Resolvable>;
- fetch?: FetchFunction;
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-embedding-model-settings.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-embedding-model-settings.ts
deleted file mode 100644
index 70d8384e8..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-embedding-model-settings.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-export type GatewayEmbeddingModelId =
- | 'alibaba/qwen3-embedding-0.6b'
- | 'alibaba/qwen3-embedding-4b'
- | 'alibaba/qwen3-embedding-8b'
- | 'amazon/titan-embed-text-v2'
- | 'cohere/embed-v4.0'
- | 'google/gemini-embedding-001'
- | 'google/gemini-embedding-2'
- | 'google/text-embedding-005'
- | 'google/text-multilingual-embedding-002'
- | 'mistral/codestral-embed'
- | 'mistral/mistral-embed'
- | 'openai/text-embedding-3-large'
- | 'openai/text-embedding-3-small'
- | 'openai/text-embedding-ada-002'
- | 'voyage/voyage-3-large'
- | 'voyage/voyage-3.5'
- | 'voyage/voyage-3.5-lite'
- | 'voyage/voyage-4'
- | 'voyage/voyage-4-large'
- | 'voyage/voyage-4-lite'
- | 'voyage/voyage-code-2'
- | 'voyage/voyage-code-3'
- | 'voyage/voyage-finance-2'
- | 'voyage/voyage-law-2'
- | (string & {});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-embedding-model.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-embedding-model.ts
deleted file mode 100644
index 80c9ee1d4..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-embedding-model.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import type {
- EmbeddingModelV3,
- SharedV3ProviderMetadata,
-} from '@ai-sdk/provider';
-import {
- combineHeaders,
- createJsonErrorResponseHandler,
- createJsonResponseHandler,
- lazySchema,
- postJsonToApi,
- resolve,
- zodSchema,
- type Resolvable,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-import { asGatewayError } from './errors';
-import { parseAuthMethod } from './errors/parse-auth-method';
-import type { GatewayConfig } from './gateway-config';
-
-export class GatewayEmbeddingModel implements EmbeddingModelV3 {
- readonly specificationVersion = 'v3';
- readonly maxEmbeddingsPerCall = 2048;
- readonly supportsParallelCalls = true;
-
- constructor(
- readonly modelId: string,
- private readonly config: GatewayConfig & {
- provider: string;
- o11yHeaders: Resolvable>;
- },
- ) {}
-
- get provider(): string {
- return this.config.provider;
- }
-
- async doEmbed({
- values,
- headers,
- abortSignal,
- providerOptions,
- }: Parameters[0]): Promise<
- Awaited>
- > {
- const resolvedHeaders = await resolve(this.config.headers());
- try {
- const {
- responseHeaders,
- value: responseBody,
- rawValue,
- } = await postJsonToApi({
- url: this.getUrl(),
- headers: combineHeaders(
- resolvedHeaders,
- headers ?? {},
- this.getModelConfigHeaders(),
- await resolve(this.config.o11yHeaders),
- ),
- body: {
- values,
- ...(providerOptions ? { providerOptions } : {}),
- },
- successfulResponseHandler: createJsonResponseHandler(
- gatewayEmbeddingResponseSchema,
- ),
- failedResponseHandler: createJsonErrorResponseHandler({
- errorSchema: z.any(),
- errorToMessage: data => data,
- }),
- ...(abortSignal && { abortSignal }),
- fetch: this.config.fetch,
- });
-
- return {
- embeddings: responseBody.embeddings,
- usage: responseBody.usage ?? undefined,
- providerMetadata:
- responseBody.providerMetadata as unknown as SharedV3ProviderMetadata,
- response: { headers: responseHeaders, body: rawValue },
- warnings: [],
- };
- } catch (error) {
- throw await asGatewayError(error, await parseAuthMethod(resolvedHeaders));
- }
- }
-
- private getUrl() {
- return `${this.config.baseURL}/embedding-model`;
- }
-
- private getModelConfigHeaders() {
- return {
- 'ai-embedding-model-specification-version': '3',
- 'ai-model-id': this.modelId,
- };
- }
-}
-
-const gatewayEmbeddingResponseSchema = lazySchema(() =>
- zodSchema(
- z.object({
- embeddings: z.array(z.array(z.number())),
- usage: z.object({ tokens: z.number() }).nullish(),
- providerMetadata: z
- .record(z.string(), z.record(z.string(), z.unknown()))
- .optional(),
- }),
- ),
-);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-fetch-metadata.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-fetch-metadata.ts
deleted file mode 100644
index 44f8c3c3d..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-fetch-metadata.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-import {
- createJsonErrorResponseHandler,
- createJsonResponseHandler,
- getFromApi,
- lazySchema,
- resolve,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-import { asGatewayError } from './errors';
-import type { GatewayConfig } from './gateway-config';
-import type { GatewayLanguageModelEntry } from './gateway-model-entry';
-
-type GatewayFetchMetadataConfig = GatewayConfig;
-
-export interface GatewayFetchMetadataResponse {
- models: GatewayLanguageModelEntry[];
-}
-
-export interface GatewayCreditsResponse {
- /** The remaining gateway credit balance available for API usage */
- balance: string;
- /** The total amount of gateway credits that have been consumed */
- totalUsed: string;
-}
-
-export class GatewayFetchMetadata {
- constructor(private readonly config: GatewayFetchMetadataConfig) {}
-
- async getAvailableModels(): Promise {
- try {
- const { value } = await getFromApi({
- url: `${this.config.baseURL}/config`,
- headers: await resolve(this.config.headers()),
- successfulResponseHandler: createJsonResponseHandler(
- gatewayAvailableModelsResponseSchema,
- ),
- failedResponseHandler: createJsonErrorResponseHandler({
- errorSchema: z.any(),
- errorToMessage: data => data,
- }),
- fetch: this.config.fetch,
- });
-
- return value;
- } catch (error) {
- throw await asGatewayError(error);
- }
- }
-
- async getCredits(): Promise {
- try {
- const baseUrl = new URL(this.config.baseURL);
-
- const { value } = await getFromApi({
- url: `${baseUrl.origin}/v1/credits`,
- headers: await resolve(this.config.headers()),
- successfulResponseHandler: createJsonResponseHandler(
- gatewayCreditsResponseSchema,
- ),
- failedResponseHandler: createJsonErrorResponseHandler({
- errorSchema: z.any(),
- errorToMessage: data => data,
- }),
- fetch: this.config.fetch,
- });
-
- return value;
- } catch (error) {
- throw await asGatewayError(error);
- }
- }
-}
-
-const gatewayAvailableModelsResponseSchema = lazySchema(() =>
- zodSchema(
- z.object({
- models: z.array(
- z.object({
- id: z.string(),
- name: z.string(),
- description: z.string().nullish(),
- pricing: z
- .object({
- input: z.string(),
- output: z.string(),
- input_cache_read: z.string().nullish(),
- input_cache_write: z.string().nullish(),
- })
- .transform(
- ({ input, output, input_cache_read, input_cache_write }) => ({
- input,
- output,
- ...(input_cache_read
- ? { cachedInputTokens: input_cache_read }
- : {}),
- ...(input_cache_write
- ? { cacheCreationInputTokens: input_cache_write }
- : {}),
- }),
- )
- .nullish(),
- specification: z.object({
- specificationVersion: z.literal('v3'),
- provider: z.string(),
- modelId: z.string(),
- }),
- modelType: z
- .enum(['embedding', 'image', 'language', 'video'])
- .nullish(),
- }),
- ),
- }),
- ),
-);
-
-const gatewayCreditsResponseSchema = lazySchema(() =>
- zodSchema(
- z
- .object({
- balance: z.string(),
- total_used: z.string(),
- })
- .transform(({ balance, total_used }) => ({
- balance,
- totalUsed: total_used,
- })),
- ),
-);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-image-model-settings.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-image-model-settings.ts
deleted file mode 100644
index f48bff9d8..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-image-model-settings.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-export type GatewayImageModelId =
- | 'bfl/flux-2-flex'
- | 'bfl/flux-2-klein-4b'
- | 'bfl/flux-2-klein-9b'
- | 'bfl/flux-2-max'
- | 'bfl/flux-2-pro'
- | 'bfl/flux-kontext-max'
- | 'bfl/flux-kontext-pro'
- | 'bfl/flux-pro-1.0-fill'
- | 'bfl/flux-pro-1.1'
- | 'bfl/flux-pro-1.1-ultra'
- | 'google/imagen-4.0-fast-generate-001'
- | 'google/imagen-4.0-generate-001'
- | 'google/imagen-4.0-ultra-generate-001'
- | 'openai/gpt-image-1'
- | 'openai/gpt-image-1-mini'
- | 'openai/gpt-image-1.5'
- | 'prodia/flux-fast-schnell'
- | 'recraft/recraft-v2'
- | 'recraft/recraft-v3'
- | 'recraft/recraft-v4'
- | 'recraft/recraft-v4-pro'
- | 'xai/grok-imagine-image'
- | 'xai/grok-imagine-image-pro'
- | (string & {});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-image-model.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-image-model.ts
deleted file mode 100644
index 44b698875..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-image-model.ts
+++ /dev/null
@@ -1,169 +0,0 @@
-import type {
- ImageModelV3,
- ImageModelV3File,
- ImageModelV3ProviderMetadata,
-} from '@ai-sdk/provider';
-import {
- combineHeaders,
- convertUint8ArrayToBase64,
- createJsonResponseHandler,
- createJsonErrorResponseHandler,
- postJsonToApi,
- resolve,
- type Resolvable,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-import type { GatewayConfig } from './gateway-config';
-import { asGatewayError } from './errors';
-import { parseAuthMethod } from './errors/parse-auth-method';
-
-export class GatewayImageModel implements ImageModelV3 {
- readonly specificationVersion = 'v3' as const;
- // Set a very large number to prevent client-side splitting of requests
- readonly maxImagesPerCall = Number.MAX_SAFE_INTEGER;
-
- constructor(
- readonly modelId: string,
- private readonly config: GatewayConfig & {
- provider: string;
- o11yHeaders: Resolvable>;
- },
- ) {}
-
- get provider(): string {
- return this.config.provider;
- }
-
- async doGenerate({
- prompt,
- n,
- size,
- aspectRatio,
- seed,
- files,
- mask,
- providerOptions,
- headers,
- abortSignal,
- }: Parameters[0]): Promise<
- Awaited>
- > {
- const resolvedHeaders = await resolve(this.config.headers());
- try {
- const {
- responseHeaders,
- value: responseBody,
- rawValue,
- } = await postJsonToApi({
- url: this.getUrl(),
- headers: combineHeaders(
- resolvedHeaders,
- headers ?? {},
- this.getModelConfigHeaders(),
- await resolve(this.config.o11yHeaders),
- ),
- body: {
- prompt,
- n,
- ...(size && { size }),
- ...(aspectRatio && { aspectRatio }),
- ...(seed && { seed }),
- ...(providerOptions && { providerOptions }),
- ...(files && {
- files: files.map(file => maybeEncodeImageFile(file)),
- }),
- ...(mask && { mask: maybeEncodeImageFile(mask) }),
- },
- successfulResponseHandler: createJsonResponseHandler(
- gatewayImageResponseSchema,
- ),
- failedResponseHandler: createJsonErrorResponseHandler({
- errorSchema: z.any(),
- errorToMessage: data => data,
- }),
- ...(abortSignal && { abortSignal }),
- fetch: this.config.fetch,
- });
-
- return {
- images: responseBody.images, // Always base64 strings from server
- warnings: responseBody.warnings ?? [],
- providerMetadata:
- responseBody.providerMetadata as ImageModelV3ProviderMetadata,
- response: {
- timestamp: new Date(),
- modelId: this.modelId,
- headers: responseHeaders,
- },
- ...(responseBody.usage != null && {
- usage: {
- inputTokens: responseBody.usage.inputTokens ?? undefined,
- outputTokens: responseBody.usage.outputTokens ?? undefined,
- totalTokens: responseBody.usage.totalTokens ?? undefined,
- },
- }),
- };
- } catch (error) {
- throw await asGatewayError(error, await parseAuthMethod(resolvedHeaders));
- }
- }
-
- private getUrl() {
- return `${this.config.baseURL}/image-model`;
- }
-
- private getModelConfigHeaders() {
- return {
- 'ai-image-model-specification-version': '3',
- 'ai-model-id': this.modelId,
- };
- }
-}
-
-function maybeEncodeImageFile(file: ImageModelV3File) {
- if (file.type === 'file' && file.data instanceof Uint8Array) {
- return {
- ...file,
- data: convertUint8ArrayToBase64(file.data),
- };
- }
- return file;
-}
-
-const providerMetadataEntrySchema = z
- .object({
- images: z.array(z.unknown()).optional(),
- })
- .catchall(z.unknown());
-
-const gatewayImageWarningSchema = z.discriminatedUnion('type', [
- z.object({
- type: z.literal('unsupported'),
- feature: z.string(),
- details: z.string().optional(),
- }),
- z.object({
- type: z.literal('compatibility'),
- feature: z.string(),
- details: z.string().optional(),
- }),
- z.object({
- type: z.literal('other'),
- message: z.string(),
- }),
-]);
-
-const gatewayImageUsageSchema = z.object({
- inputTokens: z.number().nullish(),
- outputTokens: z.number().nullish(),
- totalTokens: z.number().nullish(),
-});
-
-const gatewayImageResponseSchema = z.object({
- images: z.array(z.string()), // Always base64 strings over the wire
- warnings: z.array(gatewayImageWarningSchema).optional(),
- providerMetadata: z
- .record(z.string(), providerMetadataEntrySchema)
- .optional(),
- usage: gatewayImageUsageSchema.optional(),
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-language-model-settings.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-language-model-settings.ts
deleted file mode 100644
index 06bf147c4..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-language-model-settings.ts
+++ /dev/null
@@ -1,183 +0,0 @@
-export type GatewayModelId =
- | 'alibaba/qwen-3-14b'
- | 'alibaba/qwen-3-235b'
- | 'alibaba/qwen-3-30b'
- | 'alibaba/qwen-3-32b'
- | 'alibaba/qwen3-235b-a22b-thinking'
- | 'alibaba/qwen3-coder'
- | 'alibaba/qwen3-coder-30b-a3b'
- | 'alibaba/qwen3-coder-next'
- | 'alibaba/qwen3-coder-plus'
- | 'alibaba/qwen3-max'
- | 'alibaba/qwen3-max-preview'
- | 'alibaba/qwen3-max-thinking'
- | 'alibaba/qwen3-next-80b-a3b-instruct'
- | 'alibaba/qwen3-next-80b-a3b-thinking'
- | 'alibaba/qwen3-vl-instruct'
- | 'alibaba/qwen3-vl-thinking'
- | 'alibaba/qwen3.5-flash'
- | 'alibaba/qwen3.5-plus'
- | 'amazon/nova-2-lite'
- | 'amazon/nova-lite'
- | 'amazon/nova-micro'
- | 'amazon/nova-pro'
- | 'anthropic/claude-3-haiku'
- | 'anthropic/claude-3-opus'
- | 'anthropic/claude-3.5-haiku'
- | 'anthropic/claude-3.5-sonnet'
- | 'anthropic/claude-3.5-sonnet-20240620'
- | 'anthropic/claude-3.7-sonnet'
- | 'anthropic/claude-haiku-4.5'
- | 'anthropic/claude-opus-4'
- | 'anthropic/claude-opus-4.1'
- | 'anthropic/claude-opus-4.5'
- | 'anthropic/claude-opus-4.6'
- | 'anthropic/claude-sonnet-4'
- | 'anthropic/claude-sonnet-4.5'
- | 'anthropic/claude-sonnet-4.6'
- | 'arcee-ai/trinity-large-preview'
- | 'arcee-ai/trinity-mini'
- | 'bytedance/seed-1.6'
- | 'bytedance/seed-1.8'
- | 'cohere/command-a'
- | 'deepseek/deepseek-r1'
- | 'deepseek/deepseek-v3'
- | 'deepseek/deepseek-v3.1'
- | 'deepseek/deepseek-v3.1-terminus'
- | 'deepseek/deepseek-v3.2'
- | 'deepseek/deepseek-v3.2-thinking'
- | 'google/gemini-2.0-flash'
- | 'google/gemini-2.0-flash-lite'
- | 'google/gemini-2.5-flash'
- | 'google/gemini-2.5-flash-image'
- | 'google/gemini-2.5-flash-lite'
- | 'google/gemini-2.5-pro'
- | 'google/gemini-3-flash'
- | 'google/gemini-3-pro-image'
- | 'google/gemini-3-pro-preview'
- | 'google/gemini-3.1-flash-image-preview'
- | 'google/gemini-3.1-flash-lite-preview'
- | 'google/gemini-3.1-pro-preview'
- | 'inception/mercury-2'
- | 'inception/mercury-coder-small'
- | 'kwaipilot/kat-coder-pro-v1'
- | 'meituan/longcat-flash-chat'
- | 'meituan/longcat-flash-thinking'
- | 'meituan/longcat-flash-thinking-2601'
- | 'meta/llama-3.1-70b'
- | 'meta/llama-3.1-8b'
- | 'meta/llama-3.2-11b'
- | 'meta/llama-3.2-1b'
- | 'meta/llama-3.2-3b'
- | 'meta/llama-3.2-90b'
- | 'meta/llama-3.3-70b'
- | 'meta/llama-4-maverick'
- | 'meta/llama-4-scout'
- | 'minimax/minimax-m2'
- | 'minimax/minimax-m2.1'
- | 'minimax/minimax-m2.1-lightning'
- | 'minimax/minimax-m2.5'
- | 'minimax/minimax-m2.5-highspeed'
- | 'minimax/minimax-m2.7'
- | 'minimax/minimax-m2.7-highspeed'
- | 'mistral/codestral'
- | 'mistral/devstral-2'
- | 'mistral/devstral-small'
- | 'mistral/devstral-small-2'
- | 'mistral/magistral-medium'
- | 'mistral/magistral-small'
- | 'mistral/ministral-14b'
- | 'mistral/ministral-3b'
- | 'mistral/ministral-8b'
- | 'mistral/mistral-large-3'
- | 'mistral/mistral-medium'
- | 'mistral/mistral-nemo'
- | 'mistral/mistral-small'
- | 'mistral/mixtral-8x22b-instruct'
- | 'mistral/pixtral-12b'
- | 'mistral/pixtral-large'
- | 'moonshotai/kimi-k2'
- | 'moonshotai/kimi-k2-0905'
- | 'moonshotai/kimi-k2-thinking'
- | 'moonshotai/kimi-k2-thinking-turbo'
- | 'moonshotai/kimi-k2-turbo'
- | 'moonshotai/kimi-k2.5'
- | 'morph/morph-v3-fast'
- | 'morph/morph-v3-large'
- | 'nvidia/nemotron-3-nano-30b-a3b'
- | 'nvidia/nemotron-nano-12b-v2-vl'
- | 'nvidia/nemotron-nano-9b-v2'
- | 'openai/gpt-3.5-turbo'
- | 'openai/gpt-3.5-turbo-instruct'
- | 'openai/gpt-4-turbo'
- | 'openai/gpt-4.1'
- | 'openai/gpt-4.1-mini'
- | 'openai/gpt-4.1-nano'
- | 'openai/gpt-4o'
- | 'openai/gpt-4o-mini'
- | 'openai/gpt-4o-mini-search-preview'
- | 'openai/gpt-5'
- | 'openai/gpt-5-chat'
- | 'openai/gpt-5-codex'
- | 'openai/gpt-5-mini'
- | 'openai/gpt-5-nano'
- | 'openai/gpt-5-pro'
- | 'openai/gpt-5.1-codex'
- | 'openai/gpt-5.1-codex-max'
- | 'openai/gpt-5.1-codex-mini'
- | 'openai/gpt-5.1-instant'
- | 'openai/gpt-5.1-thinking'
- | 'openai/gpt-5.2'
- | 'openai/gpt-5.2-chat'
- | 'openai/gpt-5.2-codex'
- | 'openai/gpt-5.2-pro'
- | 'openai/gpt-5.3-chat'
- | 'openai/gpt-5.3-codex'
- | 'openai/gpt-5.4'
- | 'openai/gpt-5.4-mini'
- | 'openai/gpt-5.4-nano'
- | 'openai/gpt-5.4-pro'
- | 'openai/gpt-oss-120b'
- | 'openai/gpt-oss-20b'
- | 'openai/gpt-oss-safeguard-20b'
- | 'openai/o1'
- | 'openai/o3'
- | 'openai/o3-deep-research'
- | 'openai/o3-mini'
- | 'openai/o3-pro'
- | 'openai/o4-mini'
- | 'perplexity/sonar'
- | 'perplexity/sonar-pro'
- | 'perplexity/sonar-reasoning-pro'
- | 'prime-intellect/intellect-3'
- | 'xai/grok-2-vision'
- | 'xai/grok-3'
- | 'xai/grok-3-fast'
- | 'xai/grok-3-mini'
- | 'xai/grok-3-mini-fast'
- | 'xai/grok-4'
- | 'xai/grok-4-fast-non-reasoning'
- | 'xai/grok-4-fast-reasoning'
- | 'xai/grok-4.1-fast-non-reasoning'
- | 'xai/grok-4.1-fast-reasoning'
- | 'xai/grok-4.20-multi-agent'
- | 'xai/grok-4.20-multi-agent-beta'
- | 'xai/grok-4.20-non-reasoning'
- | 'xai/grok-4.20-non-reasoning-beta'
- | 'xai/grok-4.20-reasoning'
- | 'xai/grok-4.20-reasoning-beta'
- | 'xai/grok-code-fast-1'
- | 'xiaomi/mimo-v2-flash'
- | 'xiaomi/mimo-v2-pro'
- | 'zai/glm-4.5'
- | 'zai/glm-4.5-air'
- | 'zai/glm-4.5v'
- | 'zai/glm-4.6'
- | 'zai/glm-4.6v'
- | 'zai/glm-4.6v-flash'
- | 'zai/glm-4.7'
- | 'zai/glm-4.7-flash'
- | 'zai/glm-4.7-flashx'
- | 'zai/glm-5'
- | 'zai/glm-5-turbo'
- | (string & {});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-language-model.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-language-model.ts
deleted file mode 100644
index 8bce6153f..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-language-model.ts
+++ /dev/null
@@ -1,212 +0,0 @@
-import type {
- LanguageModelV3,
- LanguageModelV3CallOptions,
- SharedV3Warning,
- LanguageModelV3FilePart,
- LanguageModelV3StreamPart,
- LanguageModelV3GenerateResult,
- LanguageModelV3StreamResult,
-} from '@ai-sdk/provider';
-import {
- combineHeaders,
- createEventSourceResponseHandler,
- createJsonErrorResponseHandler,
- createJsonResponseHandler,
- postJsonToApi,
- resolve,
- type ParseResult,
- type Resolvable,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-import type { GatewayConfig } from './gateway-config';
-import type { GatewayModelId } from './gateway-language-model-settings';
-import { asGatewayError } from './errors';
-import { parseAuthMethod } from './errors/parse-auth-method';
-
-type GatewayChatConfig = GatewayConfig & {
- provider: string;
- o11yHeaders: Resolvable>;
-};
-
-export class GatewayLanguageModel implements LanguageModelV3 {
- readonly specificationVersion = 'v3';
- readonly supportedUrls = { '*/*': [/.*/] };
-
- constructor(
- readonly modelId: GatewayModelId,
- private readonly config: GatewayChatConfig,
- ) {}
-
- get provider(): string {
- return this.config.provider;
- }
-
- private async getArgs(options: LanguageModelV3CallOptions) {
- const { abortSignal: _abortSignal, ...optionsWithoutSignal } = options;
-
- return {
- args: this.maybeEncodeFileParts(optionsWithoutSignal),
- warnings: [],
- };
- }
-
- async doGenerate(
- options: LanguageModelV3CallOptions,
- ): Promise {
- const { args, warnings } = await this.getArgs(options);
- const { abortSignal } = options;
-
- const resolvedHeaders = await resolve(this.config.headers());
-
- try {
- const {
- responseHeaders,
- value: responseBody,
- rawValue: rawResponse,
- } = await postJsonToApi({
- url: this.getUrl(),
- headers: combineHeaders(
- resolvedHeaders,
- options.headers,
- this.getModelConfigHeaders(this.modelId, false),
- await resolve(this.config.o11yHeaders),
- ),
- body: args,
- successfulResponseHandler: createJsonResponseHandler(z.any()),
- failedResponseHandler: createJsonErrorResponseHandler({
- errorSchema: z.any(),
- errorToMessage: data => data,
- }),
- ...(abortSignal && { abortSignal }),
- fetch: this.config.fetch,
- });
-
- return {
- ...responseBody,
- request: { body: args },
- response: { headers: responseHeaders, body: rawResponse },
- warnings,
- };
- } catch (error) {
- throw await asGatewayError(error, await parseAuthMethod(resolvedHeaders));
- }
- }
-
- async doStream(
- options: LanguageModelV3CallOptions,
- ): Promise {
- const { args, warnings } = await this.getArgs(options);
- const { abortSignal } = options;
-
- const resolvedHeaders = await resolve(this.config.headers());
-
- try {
- const { value: response, responseHeaders } = await postJsonToApi({
- url: this.getUrl(),
- headers: combineHeaders(
- resolvedHeaders,
- options.headers,
- this.getModelConfigHeaders(this.modelId, true),
- await resolve(this.config.o11yHeaders),
- ),
- body: args,
- successfulResponseHandler: createEventSourceResponseHandler(z.any()),
- failedResponseHandler: createJsonErrorResponseHandler({
- errorSchema: z.any(),
- errorToMessage: data => data,
- }),
- ...(abortSignal && { abortSignal }),
- fetch: this.config.fetch,
- });
-
- return {
- stream: response.pipeThrough(
- new TransformStream<
- ParseResult,
- LanguageModelV3StreamPart
- >({
- start(controller) {
- if (warnings.length > 0) {
- controller.enqueue({ type: 'stream-start', warnings });
- }
- },
- transform(chunk, controller) {
- if (chunk.success) {
- const streamPart = chunk.value;
-
- // Handle raw chunks: if this is a raw chunk from the gateway API,
- // only emit it if includeRawChunks is true
- if (streamPart.type === 'raw' && !options.includeRawChunks) {
- return; // Skip raw chunks if not requested
- }
-
- if (
- streamPart.type === 'response-metadata' &&
- streamPart.timestamp &&
- typeof streamPart.timestamp === 'string'
- ) {
- streamPart.timestamp = new Date(streamPart.timestamp);
- }
-
- controller.enqueue(streamPart);
- } else {
- controller.error(
- (chunk as { success: false; error: unknown }).error,
- );
- }
- },
- }),
- ),
- request: { body: args },
- response: { headers: responseHeaders },
- };
- } catch (error) {
- throw await asGatewayError(error, await parseAuthMethod(resolvedHeaders));
- }
- }
-
- private isFilePart(part: unknown) {
- return (
- part && typeof part === 'object' && 'type' in part && part.type === 'file'
- );
- }
-
- /**
- * Encodes file parts in the prompt to base64. Mutates the passed options
- * instance directly to avoid copying the file data.
- * @param options - The options to encode.
- * @returns The options with the file parts encoded.
- */
- private maybeEncodeFileParts(options: LanguageModelV3CallOptions) {
- for (const message of options.prompt) {
- for (const part of message.content) {
- if (this.isFilePart(part)) {
- const filePart = part as LanguageModelV3FilePart;
- // If the file part is a URL it will get cleanly converted to a string.
- // If it's a binary file attachment we convert it to a data url.
- // In either case, server-side we should only ever see URLs as strings.
- if (filePart.data instanceof Uint8Array) {
- const buffer = Uint8Array.from(filePart.data);
- const base64Data = Buffer.from(buffer).toString('base64');
- filePart.data = new URL(
- `data:${filePart.mediaType || 'application/octet-stream'};base64,${base64Data}`,
- );
- }
- }
- }
- }
- return options;
- }
-
- private getUrl() {
- return `${this.config.baseURL}/language-model`;
- }
-
- private getModelConfigHeaders(modelId: string, streaming: boolean) {
- return {
- 'ai-language-model-specification-version': '3',
- 'ai-language-model-id': modelId,
- 'ai-language-model-streaming': String(streaming),
- };
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-model-entry.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-model-entry.ts
deleted file mode 100644
index bd69757cc..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-model-entry.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import type { LanguageModelV3 } from '@ai-sdk/provider';
-
-export interface GatewayLanguageModelEntry {
- /**
- * The model id used by the remote provider in model settings and for specifying the
- * intended model for text generation.
- */
- id: string;
-
- /**
- * The display name of the model for presentation in user-facing contexts.
- */
- name: string;
-
- /**
- * Optional description of the model.
- */
- description?: string | null;
-
- /**
- * Optional pricing information for the model.
- */
- pricing?: {
- /**
- * Cost per input token in USD.
- */
- input: string;
- /**
- * Cost per output token in USD.
- */
- output: string;
- /**
- * Cost per cached input token in USD.
- * Only present for providers/models that support prompt caching.
- */
- cachedInputTokens?: string;
- /**
- * Cost per input token to create/write cache entries in USD.
- * Only present for providers/models that support prompt caching.
- */
- cacheCreationInputTokens?: string;
- } | null;
-
- /**
- * Additional AI SDK language model specifications for the model.
- */
- specification: GatewayLanguageModelSpecification;
-
- /**
- * Optional field to differentiate between model types.
- */
- modelType?: 'language' | 'embedding' | 'image' | 'video' | null;
-}
-
-export type GatewayLanguageModelSpecification = Pick<
- LanguageModelV3,
- 'specificationVersion' | 'provider' | 'modelId'
->;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-provider-options.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-provider-options.ts
deleted file mode 100644
index 54d653f03..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-provider-options.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-// https://vercel.com/docs/ai-gateway/provider-options
-const gatewayLanguageModelOptions = lazySchema(() =>
- zodSchema(
- z.object({
- /**
- * Array of provider slugs that are the only ones allowed to be used.
- *
- * Example: `['azure', 'openai']` will only allow Azure and OpenAI to be used.
- */
- only: z.array(z.string()).optional(),
- /**
- * Array of provider slugs that specifies the sequence in which providers should be attempted.
- *
- * Example: `['bedrock', 'anthropic']` will try Amazon Bedrock first, then Anthropic as fallback.
- */
- order: z.array(z.string()).optional(),
- /**
- * The unique identifier for the end user on behalf of whom the request was made.
- *
- * Used for spend tracking and attribution purposes.
- */
- user: z.string().optional(),
- /**
- * User-specified tags for use in reporting and filtering usage.
- *
- * For example, spend tracking reporting by feature or prompt version.
- *
- * Example: `['chat', 'v2']`
- */
- tags: z.array(z.string()).optional(),
- /**
- * Array of model slugs specifying fallback models to use in order.
- *
- * Example: `['openai/gpt-5-nano', 'zai/glm-4.6']` will try `openai/gpt-5-nano` first, then `zai/glm-4.6` as fallback.
- */
- models: z.array(z.string()).optional(),
- /**
- * Request-scoped BYOK credentials to use instead of cached credentials.
- *
- * When provided, cached BYOK credentials are ignored entirely.
- *
- * Each provider can have multiple credentials (tried in order).
- *
- * Examples:
- * - Simple: `{ 'anthropic': [{ apiKey: 'sk-ant-...' }] }`
- * - Multiple: `{ 'vertex': [{ projectId: 'proj-1', privateKey: '...' }, { projectId: 'proj-2', privateKey: '...' }] }`
- * - Multi-provider: `{ 'anthropic': [{ apiKey: '...' }], 'bedrock': [{ accessKeyId: '...', secretAccessKey: '...' }] }`
- */
- byok: z
- .record(z.string(), z.array(z.record(z.string(), z.unknown())))
- .optional(),
- /**
- * Whether to filter by only providers that state they have zero data
- * retention with Vercel AI Gateway. When enabled, only providers that
- * have agreements with Vercel AI Gateway for zero data retention will be
- * used.
- */
- zeroDataRetention: z.boolean().optional(),
- /**
- * Per-provider timeouts for BYOK credentials in milliseconds.
- * Controls how long to wait for a provider to start responding
- * before falling back to the next available provider.
- *
- * Example: `{ byok: { openai: 5000, anthropic: 2000 } }`
- */
- providerTimeouts: z
- .object({
- byok: z.record(z.string(), z.number().int().min(1000)).optional(),
- })
- .optional(),
- }),
- ),
-);
-
-export type GatewayLanguageModelOptions = InferSchema<
- typeof gatewayLanguageModelOptions
->;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-provider.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-provider.ts
deleted file mode 100644
index 9b2a5f246..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-provider.ts
+++ /dev/null
@@ -1,329 +0,0 @@
-import {
- loadOptionalSetting,
- withoutTrailingSlash,
- type FetchFunction,
-} from '@ai-sdk/provider-utils';
-import { asGatewayError, GatewayAuthenticationError } from './errors';
-import {
- GATEWAY_AUTH_METHOD_HEADER,
- parseAuthMethod,
-} from './errors/parse-auth-method';
-import {
- GatewayFetchMetadata,
- type GatewayFetchMetadataResponse,
- type GatewayCreditsResponse,
-} from './gateway-fetch-metadata';
-import { GatewayLanguageModel } from './gateway-language-model';
-import { GatewayEmbeddingModel } from './gateway-embedding-model';
-import { GatewayImageModel } from './gateway-image-model';
-import { GatewayVideoModel } from './gateway-video-model';
-import type { GatewayEmbeddingModelId } from './gateway-embedding-model-settings';
-import type { GatewayImageModelId } from './gateway-image-model-settings';
-import type { GatewayVideoModelId } from './gateway-video-model-settings';
-import { gatewayTools } from './gateway-tools';
-import { getVercelOidcToken, getVercelRequestId } from './vercel-environment';
-import type { GatewayModelId } from './gateway-language-model-settings';
-import type {
- LanguageModelV3,
- EmbeddingModelV3,
- ImageModelV3,
- Experimental_VideoModelV3,
- ProviderV3,
-} from '@ai-sdk/provider';
-import { withUserAgentSuffix } from '@ai-sdk/provider-utils';
-import { VERSION } from './version';
-
-export interface GatewayProvider extends ProviderV3 {
- (modelId: GatewayModelId): LanguageModelV3;
-
- /**
- * Creates a model for text generation.
- */
- chat(modelId: GatewayModelId): LanguageModelV3;
-
- /**
- * Creates a model for text generation.
- */
- languageModel(modelId: GatewayModelId): LanguageModelV3;
-
- /**
- * Returns available providers and models for use with the remote provider.
- */
- getAvailableModels(): Promise;
-
- /**
- * Returns credit information for the authenticated user.
- */
- getCredits(): Promise;
-
- /**
- * Creates a model for generating text embeddings.
- */
- embedding(modelId: GatewayEmbeddingModelId): EmbeddingModelV3;
-
- /**
- * Creates a model for generating text embeddings.
- */
- embeddingModel(modelId: GatewayEmbeddingModelId): EmbeddingModelV3;
-
- /**
- * @deprecated Use `embeddingModel` instead.
- */
- textEmbeddingModel(modelId: GatewayEmbeddingModelId): EmbeddingModelV3;
-
- /**
- * Creates a model for generating images.
- */
- image(modelId: GatewayImageModelId): ImageModelV3;
-
- /**
- * Creates a model for generating images.
- */
- imageModel(modelId: GatewayImageModelId): ImageModelV3;
-
- /**
- * Creates a model for generating videos.
- */
- video(modelId: GatewayVideoModelId): Experimental_VideoModelV3;
-
- /**
- * Creates a model for generating videos.
- */
- videoModel(modelId: GatewayVideoModelId): Experimental_VideoModelV3;
-
- /**
- * Gateway-specific tools executed server-side.
- */
- tools: typeof gatewayTools;
-}
-
-export interface GatewayProviderSettings {
- /**
- * The base URL prefix for API calls. Defaults to `https://ai-gateway.vercel.sh/v1/ai`.
- */
- baseURL?: string;
-
- /**
- * API key that is being sent using the `Authorization` header.
- */
- apiKey?: string;
-
- /**
- * Custom headers to include in the requests.
- */
- headers?: Record;
-
- /**
- * Custom fetch implementation. You can use it as a middleware to intercept requests,
- * or to provide a custom fetch implementation for e.g. testing.
- */
- fetch?: FetchFunction;
-
- /**
- * How frequently to refresh the metadata cache in milliseconds.
- */
- metadataCacheRefreshMillis?: number;
-
- /**
- * @internal For testing purposes only
- */
- _internal?: {
- currentDate?: () => Date;
- };
-}
-
-const AI_GATEWAY_PROTOCOL_VERSION = '0.0.1';
-
-/**
- * Create a remote provider instance.
- */
-export function createGatewayProvider(
- options: GatewayProviderSettings = {},
-): GatewayProvider {
- let pendingMetadata: Promise | null = null;
- let metadataCache: GatewayFetchMetadataResponse | null = null;
- const cacheRefreshMillis =
- options.metadataCacheRefreshMillis ?? 1000 * 60 * 5;
- let lastFetchTime = 0;
-
- const baseURL =
- withoutTrailingSlash(options.baseURL) ??
- 'https://ai-gateway.vercel.sh/v3/ai';
-
- const getHeaders = async () => {
- try {
- const auth = await getGatewayAuthToken(options);
- return withUserAgentSuffix(
- {
- Authorization: `Bearer ${auth.token}`,
- 'ai-gateway-protocol-version': AI_GATEWAY_PROTOCOL_VERSION,
- [GATEWAY_AUTH_METHOD_HEADER]: auth.authMethod,
- ...options.headers,
- },
- `ai-sdk/gateway/${VERSION}`,
- );
- } catch (error) {
- throw GatewayAuthenticationError.createContextualError({
- apiKeyProvided: false,
- oidcTokenProvided: false,
- statusCode: 401,
- cause: error,
- });
- }
- };
-
- const createO11yHeaders = () => {
- const deploymentId = loadOptionalSetting({
- settingValue: undefined,
- environmentVariableName: 'VERCEL_DEPLOYMENT_ID',
- });
- const environment = loadOptionalSetting({
- settingValue: undefined,
- environmentVariableName: 'VERCEL_ENV',
- });
- const region = loadOptionalSetting({
- settingValue: undefined,
- environmentVariableName: 'VERCEL_REGION',
- });
- const projectId = loadOptionalSetting({
- settingValue: undefined,
- environmentVariableName: 'VERCEL_PROJECT_ID',
- });
-
- return async () => {
- const requestId = await getVercelRequestId();
- return {
- ...(deploymentId && { 'ai-o11y-deployment-id': deploymentId }),
- ...(environment && { 'ai-o11y-environment': environment }),
- ...(region && { 'ai-o11y-region': region }),
- ...(requestId && { 'ai-o11y-request-id': requestId }),
- ...(projectId && { 'ai-o11y-project-id': projectId }),
- };
- };
- };
-
- const createLanguageModel = (modelId: GatewayModelId) => {
- return new GatewayLanguageModel(modelId, {
- provider: 'gateway',
- baseURL,
- headers: getHeaders,
- fetch: options.fetch,
- o11yHeaders: createO11yHeaders(),
- });
- };
-
- const getAvailableModels = async () => {
- const now = options._internal?.currentDate?.().getTime() ?? Date.now();
- if (!pendingMetadata || now - lastFetchTime > cacheRefreshMillis) {
- lastFetchTime = now;
-
- pendingMetadata = new GatewayFetchMetadata({
- baseURL,
- headers: getHeaders,
- fetch: options.fetch,
- })
- .getAvailableModels()
- .then(metadata => {
- metadataCache = metadata;
- return metadata;
- })
- .catch(async (error: unknown) => {
- throw await asGatewayError(
- error,
- await parseAuthMethod(await getHeaders()),
- );
- });
- }
-
- return metadataCache ? Promise.resolve(metadataCache) : pendingMetadata;
- };
-
- const getCredits = async () => {
- return new GatewayFetchMetadata({
- baseURL,
- headers: getHeaders,
- fetch: options.fetch,
- })
- .getCredits()
- .catch(async (error: unknown) => {
- throw await asGatewayError(
- error,
- await parseAuthMethod(await getHeaders()),
- );
- });
- };
-
- const provider = function (modelId: GatewayModelId) {
- if (new.target) {
- throw new Error(
- 'The Gateway Provider model function cannot be called with the new keyword.',
- );
- }
-
- return createLanguageModel(modelId);
- };
-
- provider.specificationVersion = 'v3' as const;
- provider.getAvailableModels = getAvailableModels;
- provider.getCredits = getCredits;
- provider.imageModel = (modelId: GatewayImageModelId) => {
- return new GatewayImageModel(modelId, {
- provider: 'gateway',
- baseURL,
- headers: getHeaders,
- fetch: options.fetch,
- o11yHeaders: createO11yHeaders(),
- });
- };
- provider.languageModel = createLanguageModel;
- const createEmbeddingModel = (modelId: GatewayEmbeddingModelId) => {
- return new GatewayEmbeddingModel(modelId, {
- provider: 'gateway',
- baseURL,
- headers: getHeaders,
- fetch: options.fetch,
- o11yHeaders: createO11yHeaders(),
- });
- };
- provider.embeddingModel = createEmbeddingModel;
- provider.textEmbeddingModel = createEmbeddingModel;
- provider.videoModel = (modelId: GatewayVideoModelId) => {
- return new GatewayVideoModel(modelId, {
- provider: 'gateway',
- baseURL,
- headers: getHeaders,
- fetch: options.fetch,
- o11yHeaders: createO11yHeaders(),
- });
- };
- provider.chat = provider.languageModel;
- provider.embedding = provider.embeddingModel;
- provider.image = provider.imageModel;
- provider.video = provider.videoModel;
- provider.tools = gatewayTools;
- return provider;
-}
-
-export const gateway = createGatewayProvider();
-
-export async function getGatewayAuthToken(
- options: GatewayProviderSettings,
-): Promise<{ token: string; authMethod: 'api-key' | 'oidc' }> {
- const apiKey = loadOptionalSetting({
- settingValue: options.apiKey,
- environmentVariableName: 'AI_GATEWAY_API_KEY',
- });
-
- if (apiKey) {
- return {
- token: apiKey,
- authMethod: 'api-key',
- };
- }
-
- const oidcToken = await getVercelOidcToken();
- return {
- token: oidcToken,
- authMethod: 'oidc',
- };
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-tools.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-tools.ts
deleted file mode 100644
index 8d57b71f4..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-tools.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { parallelSearch } from './tool/parallel-search';
-import { perplexitySearch } from './tool/perplexity-search';
-
-/**
- * Gateway-specific provider-defined tools.
- */
-export const gatewayTools = {
- /**
- * Search the web using Parallel AI's Search API for LLM-optimized excerpts.
- *
- * Takes a natural language objective and returns relevant excerpts,
- * replacing multiple keyword searches with a single call for broad
- * or complex queries. Supports different search types for depth vs
- * breadth tradeoffs.
- */
- parallelSearch,
-
- /**
- * Search the web using Perplexity's Search API for real-time information,
- * news, research papers, and articles.
- *
- * Provides ranked search results with advanced filtering options including
- * domain, language, date range, and recency filters.
- */
- perplexitySearch,
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-video-model-settings.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-video-model-settings.ts
deleted file mode 100644
index c14fdd1d5..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-video-model-settings.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-export type GatewayVideoModelId =
- | 'alibaba/wan-v2.5-t2v-preview'
- | 'alibaba/wan-v2.6-i2v'
- | 'alibaba/wan-v2.6-i2v-flash'
- | 'alibaba/wan-v2.6-r2v'
- | 'alibaba/wan-v2.6-r2v-flash'
- | 'alibaba/wan-v2.6-t2v'
- | 'bytedance/seedance-v1.0-lite-i2v'
- | 'bytedance/seedance-v1.0-lite-t2v'
- | 'bytedance/seedance-v1.0-pro'
- | 'bytedance/seedance-v1.0-pro-fast'
- | 'bytedance/seedance-v1.5-pro'
- | 'google/veo-3.0-fast-generate-001'
- | 'google/veo-3.0-generate-001'
- | 'google/veo-3.1-fast-generate-001'
- | 'google/veo-3.1-generate-001'
- | 'klingai/kling-v2.5-turbo-i2v'
- | 'klingai/kling-v2.5-turbo-t2v'
- | 'klingai/kling-v2.6-i2v'
- | 'klingai/kling-v2.6-motion-control'
- | 'klingai/kling-v2.6-t2v'
- | 'klingai/kling-v3.0-i2v'
- | 'klingai/kling-v3.0-t2v'
- | 'xai/grok-imagine-video'
- | (string & {});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-video-model.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-video-model.ts
deleted file mode 100644
index e97162009..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/gateway-video-model.ts
+++ /dev/null
@@ -1,259 +0,0 @@
-import type {
- Experimental_VideoModelV3,
- Experimental_VideoModelV3CallOptions,
- Experimental_VideoModelV3File,
- Experimental_VideoModelV3VideoData,
- SharedV3ProviderMetadata,
- SharedV3Warning,
-} from '@ai-sdk/provider';
-import { APICallError } from '@ai-sdk/provider';
-import {
- combineHeaders,
- convertUint8ArrayToBase64,
- createJsonErrorResponseHandler,
- parseJsonEventStream,
- postJsonToApi,
- resolve,
- type Resolvable,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-import type { GatewayConfig } from './gateway-config';
-import { asGatewayError } from './errors';
-import { parseAuthMethod } from './errors/parse-auth-method';
-
-export class GatewayVideoModel implements Experimental_VideoModelV3 {
- readonly specificationVersion = 'v3' as const;
- // Set a very large number to prevent client-side splitting of requests
- readonly maxVideosPerCall = Number.MAX_SAFE_INTEGER;
-
- constructor(
- readonly modelId: string,
- private readonly config: GatewayConfig & {
- provider: string;
- o11yHeaders: Resolvable>;
- },
- ) {}
-
- get provider(): string {
- return this.config.provider;
- }
-
- async doGenerate({
- prompt,
- n,
- aspectRatio,
- resolution,
- duration,
- fps,
- seed,
- image,
- providerOptions,
- headers,
- abortSignal,
- }: Experimental_VideoModelV3CallOptions): Promise<{
- videos: Array;
- warnings: Array;
- providerMetadata?: SharedV3ProviderMetadata;
- response: {
- timestamp: Date;
- modelId: string;
- headers: Record | undefined;
- };
- }> {
- const resolvedHeaders = await resolve(this.config.headers());
- try {
- const { responseHeaders, value: responseBody } = await postJsonToApi({
- url: this.getUrl(),
- headers: combineHeaders(
- resolvedHeaders,
- headers ?? {},
- this.getModelConfigHeaders(),
- await resolve(this.config.o11yHeaders),
- { accept: 'text/event-stream' },
- ),
- body: {
- prompt,
- n,
- ...(aspectRatio && { aspectRatio }),
- ...(resolution && { resolution }),
- ...(duration && { duration }),
- ...(fps && { fps }),
- ...(seed && { seed }),
- ...(providerOptions && { providerOptions }),
- ...(image && { image: maybeEncodeVideoFile(image) }),
- },
- successfulResponseHandler: async ({
- response,
- url,
- requestBodyValues,
- }: {
- url: string;
- requestBodyValues: unknown;
- response: Response;
- }) => {
- if (response.body == null) {
- throw new APICallError({
- message: 'SSE response body is empty',
- url,
- requestBodyValues,
- statusCode: response.status,
- });
- }
-
- const eventStream = parseJsonEventStream({
- stream: response.body,
- schema: gatewayVideoEventSchema,
- });
-
- const reader = eventStream.getReader();
- const { done, value: parseResult } = await reader.read();
- reader.releaseLock();
-
- if (done || !parseResult) {
- throw new APICallError({
- message: 'SSE stream ended without a data event',
- url,
- requestBodyValues,
- statusCode: response.status,
- });
- }
-
- if (!parseResult.success) {
- throw new APICallError({
- message: 'Failed to parse video SSE event',
- cause: parseResult.error,
- url,
- requestBodyValues,
- statusCode: response.status,
- });
- }
-
- const event = parseResult.value;
-
- if (event.type === 'error') {
- throw new APICallError({
- message: event.message,
- statusCode: event.statusCode,
- url,
- requestBodyValues,
- responseHeaders: Object.fromEntries([...response.headers]),
- responseBody: JSON.stringify(event),
- data: {
- error: {
- message: event.message,
- type: event.errorType,
- param: event.param,
- },
- },
- });
- }
-
- // event.type === 'result'
- return {
- value: {
- videos: event.videos,
- warnings: event.warnings,
- providerMetadata: event.providerMetadata,
- },
- responseHeaders: Object.fromEntries([...response.headers]),
- };
- },
- failedResponseHandler: createJsonErrorResponseHandler({
- errorSchema: z.any(),
- errorToMessage: data => data,
- }),
- ...(abortSignal && { abortSignal }),
- fetch: this.config.fetch,
- });
-
- return {
- videos: responseBody.videos,
- warnings: responseBody.warnings ?? [],
- providerMetadata:
- responseBody.providerMetadata as SharedV3ProviderMetadata,
- response: {
- timestamp: new Date(),
- modelId: this.modelId,
- headers: responseHeaders,
- },
- };
- } catch (error) {
- throw await asGatewayError(error, await parseAuthMethod(resolvedHeaders));
- }
- }
-
- private getUrl() {
- return `${this.config.baseURL}/video-model`;
- }
-
- private getModelConfigHeaders() {
- return {
- 'ai-video-model-specification-version': '3',
- 'ai-model-id': this.modelId,
- };
- }
-}
-
-function maybeEncodeVideoFile(file: Experimental_VideoModelV3File) {
- if (file.type === 'file' && file.data instanceof Uint8Array) {
- return {
- ...file,
- data: convertUint8ArrayToBase64(file.data),
- };
- }
- return file;
-}
-
-const providerMetadataEntrySchema = z
- .object({
- videos: z.array(z.unknown()).optional(),
- })
- .catchall(z.unknown());
-
-const gatewayVideoDataSchema = z.union([
- z.object({
- type: z.literal('url'),
- url: z.string(),
- mediaType: z.string(),
- }),
- z.object({
- type: z.literal('base64'),
- data: z.string(),
- mediaType: z.string(),
- }),
-]);
-
-const gatewayVideoWarningSchema = z.discriminatedUnion('type', [
- z.object({
- type: z.literal('unsupported'),
- feature: z.string(),
- details: z.string().optional(),
- }),
- z.object({
- type: z.literal('compatibility'),
- feature: z.string(),
- details: z.string().optional(),
- }),
- z.object({
- type: z.literal('other'),
- message: z.string(),
- }),
-]);
-
-const gatewayVideoEventSchema = z.discriminatedUnion('type', [
- z.object({
- type: z.literal('result'),
- videos: z.array(gatewayVideoDataSchema),
- warnings: z.array(gatewayVideoWarningSchema).optional(),
- providerMetadata: z
- .record(z.string(), providerMetadataEntrySchema)
- .optional(),
- }),
- z.object({
- type: z.literal('error'),
- message: z.string(),
- errorType: z.string(),
- statusCode: z.number(),
- param: z.unknown().nullable(),
- }),
-]);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/index.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/index.ts
deleted file mode 100644
index 61acc34ac..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/index.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-export type { GatewayModelId } from './gateway-language-model-settings';
-export type { GatewayVideoModelId } from './gateway-video-model-settings';
-export type {
- GatewayLanguageModelEntry,
- GatewayLanguageModelSpecification,
-} from './gateway-model-entry';
-export type { GatewayCreditsResponse } from './gateway-fetch-metadata';
-export type { GatewayLanguageModelEntry as GatewayModelEntry } from './gateway-model-entry';
-export {
- createGatewayProvider,
- createGatewayProvider as createGateway,
- gateway,
-} from './gateway-provider';
-export type {
- GatewayProvider,
- GatewayProviderSettings,
-} from './gateway-provider';
-export type {
- GatewayLanguageModelOptions,
- /** @deprecated Use `GatewayLanguageModelOptions` instead. */
- GatewayLanguageModelOptions as GatewayProviderOptions,
-} from './gateway-provider-options';
-export {
- GatewayError,
- GatewayAuthenticationError,
- GatewayInvalidRequestError,
- GatewayRateLimitError,
- GatewayModelNotFoundError,
- GatewayInternalServerError,
- GatewayResponseError,
-} from './errors';
-export type { GatewayErrorResponse } from './errors';
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/tool/parallel-search.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/tool/parallel-search.ts
deleted file mode 100644
index e8f81a772..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/tool/parallel-search.ts
+++ /dev/null
@@ -1,295 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod';
-
-export interface ParallelSearchSourcePolicy {
- /**
- * List of domains to include in search results.
- * Example: ['wikipedia.org', 'nature.com']
- */
- includeDomains?: string[];
-
- /**
- * List of domains to exclude from search results.
- * Example: ['reddit.com', 'twitter.com']
- */
- excludeDomains?: string[];
-
- /**
- * Only include results published after this date (ISO 8601 format).
- * Example: '2024-01-01'
- */
- afterDate?: string;
-}
-
-export interface ParallelSearchExcerpts {
- /**
- * Maximum characters per result.
- */
- maxCharsPerResult?: number;
-
- /**
- * Maximum total characters across all results.
- */
- maxCharsTotal?: number;
-}
-
-export interface ParallelSearchFetchPolicy {
- /**
- * Maximum age in seconds for cached content.
- * Set to 0 to always fetch fresh content.
- */
- maxAgeSeconds?: number;
-}
-
-export interface ParallelSearchConfig {
- /**
- * Mode preset for different use cases:
- * - "one-shot": Comprehensive results with longer excerpts for single-response answers (default)
- * - "agentic": Concise, token-efficient results for multi-step agentic workflows
- */
- mode?: 'one-shot' | 'agentic';
-
- /**
- * Default maximum number of results to return (1-20).
- * Defaults to 10 if not specified.
- */
- maxResults?: number;
-
- /**
- * Default source policy for controlling which domains to include/exclude.
- */
- sourcePolicy?: ParallelSearchSourcePolicy;
-
- /**
- * Default excerpt configuration for controlling result length.
- */
- excerpts?: ParallelSearchExcerpts;
-
- /**
- * Default fetch policy for controlling content freshness.
- */
- fetchPolicy?: ParallelSearchFetchPolicy;
-}
-
-export interface ParallelSearchResult {
- /** URL of the search result */
- url: string;
- /** Title of the search result */
- title: string;
- /** Extracted text excerpt/content from the page */
- excerpt: string;
- /** Publication date of the content (may be null) */
- publishDate?: string | null;
- /** Relevance score for the result */
- relevanceScore?: number;
-}
-
-export interface ParallelSearchResponse {
- /** Unique identifier for this search request */
- searchId: string;
- /** Array of search results */
- results: ParallelSearchResult[];
-}
-
-export interface ParallelSearchError {
- /** Error type */
- error:
- | 'api_error'
- | 'rate_limit'
- | 'timeout'
- | 'invalid_input'
- | 'configuration_error'
- | 'unknown';
- /** HTTP status code if applicable */
- statusCode?: number;
- /** Human-readable error message */
- message: string;
-}
-
-export interface ParallelSearchInput {
- /**
- * Natural-language description of the web research goal.
- * Include source or freshness guidance and broader context from the task.
- * Maximum 5000 characters.
- */
- objective: string;
-
- /**
- * Optional search queries to supplement the objective.
- * Maximum 200 characters per query.
- */
- search_queries?: string[];
-
- /**
- * Mode preset for different use cases:
- * - "one-shot": Comprehensive results with longer excerpts
- * - "agentic": Concise, token-efficient results for multi-step workflows
- */
- mode?: 'one-shot' | 'agentic';
-
- /**
- * Maximum number of results to return (1-20).
- * Defaults to 10 if not specified.
- */
- max_results?: number;
-
- /**
- * Source policy for controlling which domains to include/exclude.
- */
- source_policy?: {
- include_domains?: string[];
- exclude_domains?: string[];
- after_date?: string;
- };
-
- /**
- * Excerpt configuration for controlling result length.
- */
- excerpts?: {
- max_chars_per_result?: number;
- max_chars_total?: number;
- };
-
- /**
- * Fetch policy for controlling content freshness.
- */
- fetch_policy?: {
- max_age_seconds?: number;
- };
-}
-
-export type ParallelSearchOutput = ParallelSearchResponse | ParallelSearchError;
-
-const parallelSearchInputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- objective: z
- .string()
- .describe(
- 'Natural-language description of the web research goal, including source or freshness guidance and broader context from the task. Maximum 5000 characters.',
- ),
-
- search_queries: z
- .array(z.string())
- .optional()
- .describe(
- 'Optional search queries to supplement the objective. Maximum 200 characters per query.',
- ),
-
- mode: z
- .enum(['one-shot', 'agentic'])
- .optional()
- .describe(
- 'Mode preset: "one-shot" for comprehensive results with longer excerpts (default), "agentic" for concise, token-efficient results for multi-step workflows.',
- ),
-
- max_results: z
- .number()
- .optional()
- .describe(
- 'Maximum number of results to return (1-20). Defaults to 10 if not specified.',
- ),
-
- source_policy: z
- .object({
- include_domains: z
- .array(z.string())
- .optional()
- .describe('List of domains to include in search results.'),
- exclude_domains: z
- .array(z.string())
- .optional()
- .describe('List of domains to exclude from search results.'),
- after_date: z
- .string()
- .optional()
- .describe(
- 'Only include results published after this date (ISO 8601 format).',
- ),
- })
- .optional()
- .describe(
- 'Source policy for controlling which domains to include/exclude and freshness.',
- ),
-
- excerpts: z
- .object({
- max_chars_per_result: z
- .number()
- .optional()
- .describe('Maximum characters per result.'),
- max_chars_total: z
- .number()
- .optional()
- .describe('Maximum total characters across all results.'),
- })
- .optional()
- .describe('Excerpt configuration for controlling result length.'),
-
- fetch_policy: z
- .object({
- max_age_seconds: z
- .number()
- .optional()
- .describe(
- 'Maximum age in seconds for cached content. Set to 0 to always fetch fresh content.',
- ),
- })
- .optional()
- .describe('Fetch policy for controlling content freshness.'),
- }),
- ),
-);
-
-const parallelSearchOutputSchema = lazySchema(() =>
- zodSchema(
- z.union([
- // Success response
- z.object({
- searchId: z.string(),
- results: z.array(
- z.object({
- url: z.string(),
- title: z.string(),
- excerpt: z.string(),
- publishDate: z.string().nullable().optional(),
- relevanceScore: z.number().optional(),
- }),
- ),
- }),
- // Error response
- z.object({
- error: z.enum([
- 'api_error',
- 'rate_limit',
- 'timeout',
- 'invalid_input',
- 'configuration_error',
- 'unknown',
- ]),
- statusCode: z.number().optional(),
- message: z.string(),
- }),
- ]),
- ),
-);
-
-export const parallelSearchToolFactory =
- createProviderToolFactoryWithOutputSchema<
- ParallelSearchInput,
- ParallelSearchOutput,
- ParallelSearchConfig
- >({
- id: 'gateway.parallel_search',
- inputSchema: parallelSearchInputSchema,
- outputSchema: parallelSearchOutputSchema,
- });
-
-export const parallelSearch = (
- config: ParallelSearchConfig = {},
-): ReturnType =>
- parallelSearchToolFactory(config);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/tool/perplexity-search.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/tool/perplexity-search.ts
deleted file mode 100644
index e315e4255..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/tool/perplexity-search.ts
+++ /dev/null
@@ -1,294 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod';
-
-export interface PerplexitySearchConfig {
- /**
- * Default maximum number of search results to return (1-20, default: 10).
- */
- maxResults?: number;
-
- /**
- * Default maximum tokens to extract per search result page (256-2048, default: 2048).
- */
- maxTokensPerPage?: number;
-
- /**
- * Default maximum total tokens across all search results (default: 25000, max: 1000000).
- */
- maxTokens?: number;
-
- /**
- * Default two-letter ISO 3166-1 alpha-2 country code for regional search results.
- * Examples: 'US', 'GB', 'FR'
- */
- country?: string;
-
- /**
- * Default list of domains to include or exclude from search results (max 20).
- * To include: ['nature.com', 'science.org']
- * To exclude: ['-example.com', '-spam.net']
- */
- searchDomainFilter?: string[];
-
- /**
- * Default list of ISO 639-1 language codes to filter results (max 10, lowercase).
- * Examples: ['en', 'fr', 'de']
- */
- searchLanguageFilter?: string[];
-
- /**
- * Default recency filter for results.
- * Cannot be combined with searchAfterDate/searchBeforeDate at runtime.
- */
- searchRecencyFilter?: 'day' | 'week' | 'month' | 'year';
-}
-
-export interface PerplexitySearchResult {
- /** Title of the search result */
- title: string;
- /** URL of the search result */
- url: string;
- /** Text snippet/preview of the content */
- snippet: string;
- /** Publication date of the content */
- date?: string;
- /** Last updated date of the content */
- lastUpdated?: string;
-}
-
-export interface PerplexitySearchResponse {
- /** Array of search results */
- results: PerplexitySearchResult[];
- /** Unique identifier for this search request */
- id: string;
-}
-
-export interface PerplexitySearchError {
- /** Error type */
- error: 'api_error' | 'rate_limit' | 'timeout' | 'invalid_input' | 'unknown';
- /** HTTP status code if applicable */
- statusCode?: number;
- /** Human-readable error message */
- message: string;
-}
-
-export interface PerplexitySearchInput {
- /**
- * Search query (string) or multiple queries (array of up to 5 strings).
- * Multi-query searches return combined results from all queries.
- */
- query: string | string[];
-
- /**
- * Maximum number of search results to return (1-20, default: 10).
- */
- max_results?: number;
-
- /**
- * Maximum number of tokens to extract per search result page (256-2048, default: 2048).
- */
- max_tokens_per_page?: number;
-
- /**
- * Maximum total tokens across all search results (default: 25000, max: 1000000).
- */
- max_tokens?: number;
-
- /**
- * Two-letter ISO 3166-1 alpha-2 country code for regional search results.
- * Examples: 'US', 'GB', 'FR'
- */
- country?: string;
-
- /**
- * List of domains to include or exclude from search results (max 20).
- * To include: ['nature.com', 'science.org']
- * To exclude: ['-example.com', '-spam.net']
- */
- search_domain_filter?: string[];
-
- /**
- * List of ISO 639-1 language codes to filter results (max 10, lowercase).
- * Examples: ['en', 'fr', 'de']
- */
- search_language_filter?: string[];
-
- /**
- * Include only results published after this date.
- * Format: 'MM/DD/YYYY' (e.g., '3/1/2025')
- * Cannot be used with search_recency_filter.
- */
- search_after_date?: string;
-
- /**
- * Include only results published before this date.
- * Format: 'MM/DD/YYYY' (e.g., '3/15/2025')
- * Cannot be used with search_recency_filter.
- */
- search_before_date?: string;
-
- /**
- * Include only results last updated after this date.
- * Format: 'MM/DD/YYYY' (e.g., '3/1/2025')
- * Cannot be used with search_recency_filter.
- */
- last_updated_after_filter?: string;
-
- /**
- * Include only results last updated before this date.
- * Format: 'MM/DD/YYYY' (e.g., '3/15/2025')
- * Cannot be used with search_recency_filter.
- */
- last_updated_before_filter?: string;
-
- /**
- * Filter results by relative time period.
- * Cannot be used with search_after_date or search_before_date.
- */
- search_recency_filter?: 'day' | 'week' | 'month' | 'year';
-}
-
-export type PerplexitySearchOutput =
- | PerplexitySearchResponse
- | PerplexitySearchError;
-
-const perplexitySearchInputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- query: z
- .union([z.string(), z.array(z.string())])
- .describe(
- 'Search query (string) or multiple queries (array of up to 5 strings). Multi-query searches return combined results from all queries.',
- ),
-
- max_results: z
- .number()
- .optional()
- .describe(
- 'Maximum number of search results to return (1-20, default: 10)',
- ),
-
- max_tokens_per_page: z
- .number()
- .optional()
- .describe(
- 'Maximum number of tokens to extract per search result page (256-2048, default: 2048)',
- ),
-
- max_tokens: z
- .number()
- .optional()
- .describe(
- 'Maximum total tokens across all search results (default: 25000, max: 1000000)',
- ),
-
- country: z
- .string()
- .optional()
- .describe(
- "Two-letter ISO 3166-1 alpha-2 country code for regional search results (e.g., 'US', 'GB', 'FR')",
- ),
-
- search_domain_filter: z
- .array(z.string())
- .optional()
- .describe(
- "List of domains to include or exclude from search results (max 20). To include: ['nature.com', 'science.org']. To exclude: ['-example.com', '-spam.net']",
- ),
-
- search_language_filter: z
- .array(z.string())
- .optional()
- .describe(
- "List of ISO 639-1 language codes to filter results (max 10, lowercase). Examples: ['en', 'fr', 'de']",
- ),
-
- search_after_date: z
- .string()
- .optional()
- .describe(
- "Include only results published after this date. Format: 'MM/DD/YYYY' (e.g., '3/1/2025'). Cannot be used with search_recency_filter.",
- ),
-
- search_before_date: z
- .string()
- .optional()
- .describe(
- "Include only results published before this date. Format: 'MM/DD/YYYY' (e.g., '3/15/2025'). Cannot be used with search_recency_filter.",
- ),
-
- last_updated_after_filter: z
- .string()
- .optional()
- .describe(
- "Include only results last updated after this date. Format: 'MM/DD/YYYY' (e.g., '3/1/2025'). Cannot be used with search_recency_filter.",
- ),
-
- last_updated_before_filter: z
- .string()
- .optional()
- .describe(
- "Include only results last updated before this date. Format: 'MM/DD/YYYY' (e.g., '3/15/2025'). Cannot be used with search_recency_filter.",
- ),
-
- search_recency_filter: z
- .enum(['day', 'week', 'month', 'year'])
- .optional()
- .describe(
- 'Filter results by relative time period. Cannot be used with search_after_date or search_before_date.',
- ),
- }),
- ),
-);
-
-const perplexitySearchOutputSchema = lazySchema(() =>
- zodSchema(
- z.union([
- // Success response
- z.object({
- results: z.array(
- z.object({
- title: z.string(),
- url: z.string(),
- snippet: z.string(),
- date: z.string().optional(),
- lastUpdated: z.string().optional(),
- }),
- ),
- id: z.string(),
- }),
- // Error response
- z.object({
- error: z.enum([
- 'api_error',
- 'rate_limit',
- 'timeout',
- 'invalid_input',
- 'unknown',
- ]),
- statusCode: z.number().optional(),
- message: z.string(),
- }),
- ]),
- ),
-);
-
-export const perplexitySearchToolFactory =
- createProviderToolFactoryWithOutputSchema<
- PerplexitySearchInput,
- PerplexitySearchOutput,
- PerplexitySearchConfig
- >({
- id: 'gateway.perplexity_search',
- inputSchema: perplexitySearchInputSchema,
- outputSchema: perplexitySearchOutputSchema,
- });
-
-export const perplexitySearch = (
- config: PerplexitySearchConfig = {},
-): ReturnType =>
- perplexitySearchToolFactory(config);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/vercel-environment.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/vercel-environment.ts
deleted file mode 100644
index 3ed597eb9..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/vercel-environment.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { getContext } from '@vercel/oidc';
-export { getVercelOidcToken } from '@vercel/oidc';
-
-export async function getVercelRequestId(): Promise {
- return getContext().headers?.['x-vercel-id'];
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/version.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/version.ts
deleted file mode 100644
index 7a35d46f5..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/gateway/src/version.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-// Version string of this package injected at build time.
-declare const __PACKAGE_VERSION__: string | undefined;
-export const VERSION: string =
- typeof __PACKAGE_VERSION__ !== 'undefined'
- ? __PACKAGE_VERSION__
- : '0.0.0-test';
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/CHANGELOG.md b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/CHANGELOG.md
deleted file mode 100644
index f76b3a5bd..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/CHANGELOG.md
+++ /dev/null
@@ -1,3149 +0,0 @@
-# @ai-sdk/openai
-
-## 3.0.48
-
-### Patch Changes
-
-- 9c548de: Add `gpt-5.4-mini`, `gpt-5.4-mini-2026-03-17`, `gpt-5.4-nano`, and `gpt-5.4-nano-2026-03-17` models.
-- bcb04df: fix(openai): preserve raw finish reason for failed responses stream events
-
- Handle `response.failed` chunks in Responses API streaming so `finishReason.raw` is preserved from `incomplete_details.reason` (e.g. `max_output_tokens`), and map failed-without-reason cases to unified `error` instead of `other`.
-
-## 3.0.47
-
-### Patch Changes
-
-- 055cd68: fix: publish v6 to latest npm dist tag
-- Updated dependencies [055cd68]
- - @ai-sdk/provider-utils@4.0.21
-
-## 3.0.46
-
-### Patch Changes
-
-- 75fc0e7: feat(openai): add new tool search tool
-
-## 3.0.45
-
-### Patch Changes
-
-- 023088c: feat(provider/openai): add `gpt-5.3-chat-latest`
-
-## 3.0.44
-
-### Patch Changes
-
-- f4a734a: fix(provider/openai): drop reasoning parts without encrypted content when store: false
-
-## 3.0.43
-
-### Patch Changes
-
-- Updated dependencies [64ac0fd]
- - @ai-sdk/provider-utils@4.0.20
-
-## 3.0.42
-
-### Patch Changes
-
-- 2589004: feat(provider/openai): add GPT-5.4 model support
-
-## 3.0.41
-
-### Patch Changes
-
-- Updated dependencies [ad4cfc2]
- - @ai-sdk/provider-utils@4.0.19
-
-## 3.0.40
-
-### Patch Changes
-
-- Updated dependencies [824b295]
- - @ai-sdk/provider-utils@4.0.18
-
-## 3.0.39
-
-### Patch Changes
-
-- Updated dependencies [08336f1]
- - @ai-sdk/provider-utils@4.0.17
-
-## 3.0.38
-
-### Patch Changes
-
-- 64a8fae: chore: remove obsolete model IDs for Anthropic, Google, OpenAI, xAI
-
-## 3.0.37
-
-### Patch Changes
-
-- 58bc42d: feat(provider/openai): support custom tools with alias mapping
-- Updated dependencies [58bc42d]
- - @ai-sdk/provider-utils@4.0.16
-
-## 3.0.36
-
-### Patch Changes
-
-- 53bdfa5: fix(openai): allow null/undefined type in streaming tool call deltas
-
- Azure AI Foundry and Mistral deployed on Azure omit the `type` field in
- streaming tool_calls deltas. The chat stream parser now accepts a missing
- `type` field (treating it as `"function"`) instead of throwing
- `InvalidResponseDataError: Expected 'function' type.`
-
- Fixes #12770
-
-## 3.0.35
-
-### Patch Changes
-
-- 5e18272: fix(openai): include reasoning parts without itemId when encrypted_content is present
-
- When `providerOptions.openai.itemId` is absent on a reasoning content part,
- the converter now uses `encrypted_content` as a fallback instead of silently
- skipping the part with a warning. The OpenAI Responses API accepts reasoning
- items without an `id` when `encrypted_content` is supplied, enabling
- multi-turn reasoning even when item IDs are stripped from provider options.
-
- Also makes the `id` field optional on the `OpenAIResponsesReasoning` type to
- reflect that the API does not require it.
-
- Fixes #12853
-
-## 3.0.34
-
-### Patch Changes
-
-- 66a374c: Support `phase` parameter on Responses API message items. The `phase` field (`'commentary'` or `'final_answer'`) is returned by models like `gpt-5.3-codex` on assistant message output items and must be preserved when sending follow-up requests. The phase value is available in `providerMetadata.openai.phase` on text parts and is automatically included on assistant messages sent back to the API.
-
-## 3.0.33
-
-### Patch Changes
-
-- 624e651: Added missing model IDs to OpenAIChatModelId, OpenAIResponsesModelId, OpenAIImageModelId, OpenAISpeechModelId, OpenAITranscriptionModelId, and OpenAICompletionModelId types for better autocomplete support.
-
-## 3.0.32
-
-### Patch Changes
-
-- 0c9395b: feat(provider/openai): add `gpt-5.3-codex`
-
-## 3.0.31
-
-### Patch Changes
-
-- d5f7312: fix(openai): change web search tool action to be optional
-
-## 3.0.30
-
-### Patch Changes
-
-- ff12133: feat(provider/openai): support native skills and hosted shell
-
-## 3.0.29
-
-### Patch Changes
-
-- e2ee705: feat: differentiate text vs image input tokens
-
-## 3.0.28
-
-### Patch Changes
-
-- Updated dependencies [4024a3a]
- - @ai-sdk/provider-utils@4.0.15
-
-## 3.0.27
-
-### Patch Changes
-
-- 99fbed8: feat: normalize provider specific model options type names and ensure they are exported
-
-## 3.0.26
-
-### Patch Changes
-
-- Updated dependencies [7168375]
- - @ai-sdk/provider@3.0.8
- - @ai-sdk/provider-utils@4.0.14
-
-## 3.0.25
-
-### Patch Changes
-
-- Updated dependencies [53f6731]
- - @ai-sdk/provider@3.0.7
- - @ai-sdk/provider-utils@4.0.13
-
-## 3.0.24
-
-### Patch Changes
-
-- Updated dependencies [96936e5]
- - @ai-sdk/provider-utils@4.0.12
-
-## 3.0.23
-
-### Patch Changes
-
-- Updated dependencies [2810850]
- - @ai-sdk/provider-utils@4.0.11
- - @ai-sdk/provider@3.0.6
-
-## 3.0.22
-
-### Patch Changes
-
-- 1524271: chore: add skill information to README files
-
-## 3.0.21
-
-### Patch Changes
-
-- 2c70b90: chore: update provider docs
-
-## 3.0.20
-
-### Patch Changes
-
-- Updated dependencies [462ad00]
- - @ai-sdk/provider-utils@4.0.10
-
-## 3.0.19
-
-### Patch Changes
-
-- 04c89b1: Provide Responses API providerMetadata types at the message / reasoning level.
-
- - Export the following types for use in client code:
- - `OpenaiResponsesProviderMetadata`
- - `OpenaiResponsesReasoningProviderMetadata`
- - `AzureResponsesProviderMetadata`
- - `AzureResponsesReasoningProviderMetadata`
-
-## 3.0.18
-
-### Patch Changes
-
-- 4de5a1d: chore: excluded tests from src folder in npm package
-- Updated dependencies [4de5a1d]
- - @ai-sdk/provider@3.0.5
- - @ai-sdk/provider-utils@4.0.9
-
-## 3.0.17
-
-### Patch Changes
-
-- 4218f86: fix(openai): preserve tool id for apply patch tool
-
-## 3.0.16
-
-### Patch Changes
-
-- 2b8369d: chore: add docs to package dist
-
-## 3.0.15
-
-### Patch Changes
-
-- 8dc54db: chore: add src folders to package bundle
-
-## 3.0.14
-
-### Patch Changes
-
-- d21d016: feat(openai): add o4-mini model to OpenAIChatModelId type
-
-## 3.0.13
-
-### Patch Changes
-
-- 000fa96: fix(openai): filter duplicate items when passing conversationID
-
-## 3.0.12
-
-### Patch Changes
-
-- Updated dependencies [5c090e7]
- - @ai-sdk/provider@3.0.4
- - @ai-sdk/provider-utils@4.0.8
-
-## 3.0.11
-
-### Patch Changes
-
-- Updated dependencies [46f46e4]
- - @ai-sdk/provider-utils@4.0.7
-
-## 3.0.10
-
-### Patch Changes
-
-- Updated dependencies [1b11dcb]
- - @ai-sdk/provider-utils@4.0.6
- - @ai-sdk/provider@3.0.3
-
-## 3.0.9
-
-### Patch Changes
-
-- Updated dependencies [34d1c8a]
- - @ai-sdk/provider-utils@4.0.5
-
-## 3.0.8
-
-### Patch Changes
-
-- 330bd92: Fix Responses `code_interpreter` annotations and add typed providerMetadata
-
- - Align Responses API `code_interpreter` annotation types with the official spec.
- - Add tests to ensure the overlapping parts of the Zod schemas used by `doGenerate` and `doStream` stay in sync.
- - Export the following types for use in client code:
- - `OpenaiResponsesTextProviderMetadata`
- - `OpenaiResponsesSourceDocumentProviderMetadata`
- - `AzureResponsesTextProviderMetadata`
- - `AzureResponsesSourceDocumentProviderMetadata`
-
-## 3.0.7
-
-### Patch Changes
-
-- 89202fb: fix(openai/azure): passing response_format correctly
-
-## 3.0.6
-
-### Patch Changes
-
-- dc87517: Fix handling of `image-url` tool result content type in OpenAI Responses API conversion
-
-## 3.0.5
-
-### Patch Changes
-
-- Updated dependencies [d937c8f]
- - @ai-sdk/provider@3.0.2
- - @ai-sdk/provider-utils@4.0.4
-
-## 3.0.4
-
-### Patch Changes
-
-- Updated dependencies [0b429d4]
- - @ai-sdk/provider-utils@4.0.3
-
-## 3.0.3
-
-### Patch Changes
-
-- 55cd1a4: fix(azure): allow 'azure' as a key for providerOptions
-
-## 3.0.2
-
-### Patch Changes
-
-- 863d34f: fix: trigger release to update `@latest`
-- Updated dependencies [863d34f]
- - @ai-sdk/provider@3.0.1
- - @ai-sdk/provider-utils@4.0.2
-
-## 3.0.1
-
-### Patch Changes
-
-- 29264a3: feat: add MCP tool approval
-- Updated dependencies [29264a3]
- - @ai-sdk/provider-utils@4.0.1
-
-## 3.0.0
-
-### Major Changes
-
-- dee8b05: ai SDK 6 beta
-
-### Minor Changes
-
-- 78928cb: release: start 5.1 beta
-
-### Patch Changes
-
-- 0c3b58b: fix(provider): add specificationVersion to ProviderV3
-- 4920119: fix the "incomplete_details" key from nullable to nullish for openai compatibility
-- 0adc679: feat(provider): shared spec v3
-- 92c6241: feat(openai): additional settings for file search tool
-- 88fc415: feat(openai): add the new provider 'apply_patch' tool
-- 817e601: fix(openai); fix url_citation schema in chat api
-- dae2185: fix(openai): extract meta data from first chunk that contains any
-- 046aa3b: feat(provider): speech model v3 spec
-- f1277fe: feat(provider/openai): send assistant text and tool call parts as reference ids when store: true
-- 8d9e8ad: chore(provider): remove generics from EmbeddingModelV3
-
- Before
-
- ```ts
- model.textEmbeddingModel("my-model-id");
- ```
-
- After
-
- ```ts
- model.embeddingModel("my-model-id");
- ```
-
-- 60f4775: fix: remove code for unsuported o1-mini and o1-preview models
-- 9a51b92: support OPENAI_BASE_URL env
-- d64ece9: enables image_generation capabilities in the Azure provider through the Responses API.
-- 2625a04: feat(openai); update spec for mcp approval
-- 2e86082: feat(provider/openai): `OpenAIChatLanguageModelOptions` type
-
- ```ts
- import { openai, type OpenAIChatLanguageModelOptions } from "@ai-sdk/openai";
- import { generateText } from "ai";
-
- await generateText({
- model: openai.chat("gpt-4o"),
- prompt: "Invent a new holiday and describe its traditions.",
- providerOptions: {
- openai: {
- user: "user-123",
- } satisfies OpenAIChatLanguageModelOptions,
- },
- });
- ```
-
-- 0877683: feat(provider/openai): support conversations api
-- d0f1baf: feat(openai): Add support for 'promptCacheRetention: 24h' for gpt5.1 series
-- 831b6cc: feat(openai): adding provider mcp tool for openai
-- 95f65c2: chore: use import \* from zod/v4
-- edc5548: feat(provider/openai): automatically add reasoning.encrypted_content include when store = false
-- 954c356: feat(openai): allow custom names for provider-defined tools
-- 544d4e8: chore(specification): rename v3 provider defined tool to provider tool
-- 77f2b20: enables code_interpreter and file_search capabilities in the Azure provider through the Responses API
-- 0c4822d: feat: `EmbeddingModelV3`
-- 73d9883: chore(openai): enable strict json by default
-- d2039d7: feat(provider/openai): add GPT 5.1 Codex Max to OpenAI Responses model IDs list
-- 88edc28: feat (provider/openai): include more image generation response metadata
-- e8109d3: feat: tool execution approval
-- ed329cb: feat: `Provider-V3`
-- 3bd2689: feat: extended token usage
-- 1cad0ab: feat: add provider version to user-agent header
-- e85fa2f: feat(openai): add sources in web-search actions
-- 423ba08: Set the annotations from the Responses API to doStream
-- 401f561: fix(provider/openai): fix web search tool input types
-- 4122d2a: feat(provider/openai): add gpt-5-codex model id
-- 0153bfa: fix(openai): fix parameter exclusion logic
-- 8dac895: feat: `LanguageModelV3`
-- 304222e: Add streaming support for apply_patch partial diffs.
-- 23f132b: fix: error schema for Responses API
-- 1d0de66: refactoring(provider/openai): simplify code
-- 000e87b: fix(provider/openai): add providerExecuted flag to tool start chunks
-- 2c0a758: chore(openai): add JSDoc to responses options
-- 1b982e6: feat(openai): preserve file_id when converting file citations
-- b82987c: feat(openai): support openai code-interpreter annotations
-- 457318b: chore(provider,ai): switch to SharedV3Warning and unified warnings
-- b681d7d: feat: expose usage tokens for 'generateImage' function
-- 79b4e46: feat(openai): add 'gpt-5.1' modelID
-- 3997a42: feat(provider/openai): local shell tool
-- 348fd10: fix(openai): treat unknown models as reasoning
-- 9061dc0: feat: image editing
-- fe49278: feat(provider/openai): only send item references for reasoning when store: true
-- cb4d238: The built in Code Interpreter tool input code is streamed in `tool-input-` chunks.
-- 357cfd7: feat(provider/openai): add new model IDs `gpt-image-1-mini`, `gpt-5-pro`, `gpt-5-pro-2025-10-06`
-- 38a4035: added support for external_web_access parameter on web_search tool
-- 40d5419: feat(openai): add `o3-deep-research` and `o4-mini-deep-research` models
-- 366f50b: chore(provider): add deprecated textEmbeddingModel and textEmbedding aliases
-- 2b0caef: feat(provider/openai): preview image generation results
-- b60d2e2: fix(openai): allow open_page action type url to be nullish
-- fd47df5: fix(openai): revised_prompt sometimes returns null, causing errors
-- 4616b86: chore: update zod peer depenedency version
-- 7756857: fix(provider/openai): add truncation parameter support for Responses API
-- cad6445: feat(openai); adding OpenAI's new shell tool
-- 64aa48f: Azure OpenAI enabled web-search-preview
-- 0b9fdd5: fix(provider/openai): end reasoning parts earlier
-- 61c52dc: feat (provider/openai): add gpt-image-1.5 model support
-- ef739fa: fix(openai): refactor apply-patch tool
-- 3220329: fix openai responses input: process all provider tool outputs (shell/apply_patch) so parallel tool results aren’t dropped and apply_patch outputs are forwarded.
-- d270a5d: chore(openai): update tests for apply-patch tool to use snapshots
-- f18ef7f: feat(openai): add gpt-5.2 models
-- 21e20c0: feat(provider): transcription model v3 spec
-- 522f6b8: feat: `ImageModelV3`
-- 484aa93: Add 'default' as service tier
-- 88574c1: Change `isReasoningModel` detection from blocklist to allowlist and add override option
-- 68c6187: feat(provider/openai): support file and image tool results
-- 3794514: feat: flexible tool output content support
-- cbf52cd: feat: expose raw finish reason
-- 10c1322: fix: moved dependency `@ai-sdk/test-server` to devDependencies
-- 5648ec0: Add GPT-5.2 support for non-reasoning parameters (temperature, topP, logProbs) when reasoningEffort is none.
-- 78f813e: fix(openai): allow temperature etc setting when reasoning effort is none for gpt-5.1
-- 40dc7fa: fix(openai): change find action type to find_in_page action type
-- 0273b74: fix(openai): add support for sources type 'api'
-- 5bf101a: feat(provider/openai): add support for OpenAI xhigh reasoning effort
-- 1bd7d32: feat: tool-specific strict mode
-- d86b52f: distinguish between OpenAI and Azure in Responses API providerMetadata
-- 95f65c2: chore: load zod schemas lazily
-- 59561f8: fix(openai); fix url_citation schema in chat api
-- Updated dependencies
- - @ai-sdk/provider@3.0.0
- - @ai-sdk/provider-utils@4.0.0
-
-## 3.0.0-beta.112
-
-### Patch Changes
-
-- Updated dependencies [475189e]
- - @ai-sdk/provider@3.0.0-beta.32
- - @ai-sdk/provider-utils@4.0.0-beta.59
-
-## 3.0.0-beta.111
-
-### Patch Changes
-
-- 304222e: Add streaming support for apply_patch partial diffs.
-
-## 3.0.0-beta.110
-
-### Patch Changes
-
-- 2625a04: feat(openai); update spec for mcp approval
-- Updated dependencies [2625a04]
- - @ai-sdk/provider@3.0.0-beta.31
- - @ai-sdk/provider-utils@4.0.0-beta.58
-
-## 3.0.0-beta.109
-
-### Patch Changes
-
-- cbf52cd: feat: expose raw finish reason
-- Updated dependencies [cbf52cd]
- - @ai-sdk/provider@3.0.0-beta.30
- - @ai-sdk/provider-utils@4.0.0-beta.57
-
-## 3.0.0-beta.108
-
-### Patch Changes
-
-- Updated dependencies [9549c9e]
- - @ai-sdk/provider@3.0.0-beta.29
- - @ai-sdk/provider-utils@4.0.0-beta.56
-
-## 3.0.0-beta.107
-
-### Patch Changes
-
-- Updated dependencies [50b70d6]
- - @ai-sdk/provider-utils@4.0.0-beta.55
-
-## 3.0.0-beta.106
-
-### Patch Changes
-
-- 9061dc0: feat: image editing
-- Updated dependencies [9061dc0]
- - @ai-sdk/provider-utils@4.0.0-beta.54
- - @ai-sdk/provider@3.0.0-beta.28
-
-## 3.0.0-beta.105
-
-### Patch Changes
-
-- 88574c1: Change `isReasoningModel` detection from blocklist to allowlist and add override option
-
-## 3.0.0-beta.104
-
-### Patch Changes
-
-- 61c52dc: feat (provider/openai): add gpt-image-1.5 model support
-
-## 3.0.0-beta.103
-
-### Patch Changes
-
-- 366f50b: chore(provider): add deprecated textEmbeddingModel and textEmbedding aliases
-- Updated dependencies [366f50b]
- - @ai-sdk/provider@3.0.0-beta.27
- - @ai-sdk/provider-utils@4.0.0-beta.53
-
-## 3.0.0-beta.102
-
-### Patch Changes
-
-- Updated dependencies [763d04a]
- - @ai-sdk/provider-utils@4.0.0-beta.52
-
-## 3.0.0-beta.101
-
-### Patch Changes
-
-- 3220329: fix openai responses input: process all provider tool outputs (shell/apply_patch) so parallel tool results aren’t dropped and apply_patch outputs are forwarded.
-- 5648ec0: Add GPT-5.2 support for non-reasoning parameters (temperature, topP, logProbs) when reasoningEffort is none.
-
-## 3.0.0-beta.100
-
-### Patch Changes
-
-- Updated dependencies [c1efac4]
- - @ai-sdk/provider-utils@4.0.0-beta.51
-
-## 3.0.0-beta.99
-
-### Patch Changes
-
-- Updated dependencies [32223c8]
- - @ai-sdk/provider-utils@4.0.0-beta.50
-
-## 3.0.0-beta.98
-
-### Patch Changes
-
-- Updated dependencies [83e5744]
- - @ai-sdk/provider-utils@4.0.0-beta.49
-
-## 3.0.0-beta.97
-
-### Patch Changes
-
-- Updated dependencies [960ec8f]
- - @ai-sdk/provider-utils@4.0.0-beta.48
-
-## 3.0.0-beta.96
-
-### Patch Changes
-
-- 817e601: fix(openai); fix url_citation schema in chat api
-- 59561f8: fix(openai); fix url_citation schema in chat api
-
-## 3.0.0-beta.95
-
-### Patch Changes
-
-- 40dc7fa: fix(openai): change find action type to find_in_page action type
-
-## 3.0.0-beta.94
-
-### Patch Changes
-
-- f18ef7f: feat(openai): add gpt-5.2 models
-
-## 3.0.0-beta.93
-
-### Patch Changes
-
-- d2039d7: feat(provider/openai): add GPT 5.1 Codex Max to OpenAI Responses model IDs list
-
-## 3.0.0-beta.92
-
-### Patch Changes
-
-- 5bf101a: feat(provider/openai): add support for OpenAI xhigh reasoning effort
-
-## 3.0.0-beta.91
-
-### Patch Changes
-
-- Updated dependencies [e9e157f]
- - @ai-sdk/provider-utils@4.0.0-beta.47
-
-## 3.0.0-beta.90
-
-### Patch Changes
-
-- Updated dependencies [81e29ab]
- - @ai-sdk/provider-utils@4.0.0-beta.46
-
-## 3.0.0-beta.89
-
-### Patch Changes
-
-- 3bd2689: feat: extended token usage
-- Updated dependencies [3bd2689]
- - @ai-sdk/provider@3.0.0-beta.26
- - @ai-sdk/provider-utils@4.0.0-beta.45
-
-## 3.0.0-beta.88
-
-### Patch Changes
-
-- 92c6241: feat(openai): additional settings for file search tool
-
-## 3.0.0-beta.87
-
-### Patch Changes
-
-- Updated dependencies [53f3368]
- - @ai-sdk/provider@3.0.0-beta.25
- - @ai-sdk/provider-utils@4.0.0-beta.44
-
-## 3.0.0-beta.86
-
-### Patch Changes
-
-- 0153bfa: fix(openai): fix parameter exclusion logic
-
-## 3.0.0-beta.85
-
-### Patch Changes
-
-- 78f813e: fix(openai): allow temperature etc setting when reasoning effort is none for gpt-5.1
-
-## 3.0.0-beta.84
-
-### Patch Changes
-
-- Updated dependencies [dce03c4]
- - @ai-sdk/provider-utils@4.0.0-beta.43
- - @ai-sdk/provider@3.0.0-beta.24
-
-## 3.0.0-beta.83
-
-### Patch Changes
-
-- ef739fa: fix(openai): refactor apply-patch tool
-
-## 3.0.0-beta.82
-
-### Patch Changes
-
-- Updated dependencies [3ed5519]
- - @ai-sdk/provider-utils@4.0.0-beta.42
-
-## 3.0.0-beta.81
-
-### Patch Changes
-
-- cad6445: feat(openai); adding OpenAI's new shell tool
-
-## 3.0.0-beta.80
-
-### Patch Changes
-
-- b60d2e2: fix(openai): allow open_page action type url to be nullish
-
-## 3.0.0-beta.79
-
-### Patch Changes
-
-- 1bd7d32: feat: tool-specific strict mode
-- Updated dependencies [1bd7d32]
- - @ai-sdk/provider-utils@4.0.0-beta.41
- - @ai-sdk/provider@3.0.0-beta.23
-
-## 3.0.0-beta.78
-
-### Patch Changes
-
-- 2c0a758: chore(openai): add JSDoc to responses options
-
-## 3.0.0-beta.77
-
-### Patch Changes
-
-- d270a5d: chore(openai): update tests for apply-patch tool to use snapshots
-
-## 3.0.0-beta.76
-
-### Patch Changes
-
-- 88edc28: feat (provider/openai): include more image generation response metadata
-
-## 3.0.0-beta.75
-
-### Patch Changes
-
-- 73d9883: chore(openai): enable strict json by default
-
-## 3.0.0-beta.74
-
-### Patch Changes
-
-- 88fc415: feat(openai): add the new provider 'apply_patch' tool
-
-## 3.0.0-beta.73
-
-### Patch Changes
-
-- 544d4e8: chore(specification): rename v3 provider defined tool to provider tool
-- Updated dependencies [544d4e8]
- - @ai-sdk/provider-utils@4.0.0-beta.40
- - @ai-sdk/provider@3.0.0-beta.22
-
-## 3.0.0-beta.72
-
-### Patch Changes
-
-- 954c356: feat(openai): allow custom names for provider-defined tools
-- Updated dependencies [954c356]
- - @ai-sdk/provider-utils@4.0.0-beta.39
- - @ai-sdk/provider@3.0.0-beta.21
-
-## 3.0.0-beta.71
-
-### Patch Changes
-
-- Updated dependencies [03849b0]
- - @ai-sdk/provider-utils@4.0.0-beta.38
-
-## 3.0.0-beta.70
-
-### Patch Changes
-
-- 457318b: chore(provider,ai): switch to SharedV3Warning and unified warnings
-- Updated dependencies [457318b]
- - @ai-sdk/provider@3.0.0-beta.20
- - @ai-sdk/provider-utils@4.0.0-beta.37
-
-## 3.0.0-beta.69
-
-### Patch Changes
-
-- 1d0de66: refactoring(provider/openai): simplify code
-
-## 3.0.0-beta.68
-
-### Patch Changes
-
-- 8d9e8ad: chore(provider): remove generics from EmbeddingModelV3
-
- Before
-
- ```ts
- model.textEmbeddingModel("my-model-id");
- ```
-
- After
-
- ```ts
- model.embeddingModel("my-model-id");
- ```
-
-- Updated dependencies [8d9e8ad]
- - @ai-sdk/provider@3.0.0-beta.19
- - @ai-sdk/provider-utils@4.0.0-beta.36
-
-## 3.0.0-beta.67
-
-### Patch Changes
-
-- Updated dependencies [10d819b]
- - @ai-sdk/provider@3.0.0-beta.18
- - @ai-sdk/provider-utils@4.0.0-beta.35
-
-## 3.0.0-beta.66
-
-### Patch Changes
-
-- d86b52f: distinguish between OpenAI and Azure in Responses API providerMetadata
-
-## 3.0.0-beta.65
-
-### Patch Changes
-
-- 38a4035: added support for external_web_access parameter on web_search tool
-
-## 3.0.0-beta.64
-
-### Patch Changes
-
-- Updated dependencies [db913bd]
- - @ai-sdk/provider@3.0.0-beta.17
- - @ai-sdk/provider-utils@4.0.0-beta.34
-
-## 3.0.0-beta.63
-
-### Patch Changes
-
-- 423ba08: Set the annotations from the Responses API to doStream
-
-## 3.0.0-beta.62
-
-### Patch Changes
-
-- 64aa48f: Azure OpenAI enabled web-search-preview
-
-## 3.0.0-beta.61
-
-### Patch Changes
-
-- 23f132b: fix: error schema for Responses API
-
-## 3.0.0-beta.60
-
-### Patch Changes
-
-- 0877683: feat(provider/openai): support conversations api
-
-## 3.0.0-beta.59
-
-### Patch Changes
-
-- d0f1baf: feat(openai): Add support for 'promptCacheRetention: 24h' for gpt5.1 series
-
-## 3.0.0-beta.58
-
-### Patch Changes
-
-- 79b4e46: feat(openai): add 'gpt-5.1' modelID
-
-## 3.0.0-beta.57
-
-### Patch Changes
-
-- b681d7d: feat: expose usage tokens for 'generateImage' function
-- Updated dependencies [b681d7d]
- - @ai-sdk/provider@3.0.0-beta.16
- - @ai-sdk/provider-utils@4.0.0-beta.33
-
-## 3.0.0-beta.56
-
-### Patch Changes
-
-- Updated dependencies [32d8dbb]
- - @ai-sdk/provider-utils@4.0.0-beta.32
-
-## 3.0.0-beta.55
-
-### Patch Changes
-
-- 831b6cc: feat(openai): adding provider mcp tool for openai
-
-## 3.0.0-beta.54
-
-### Patch Changes
-
-- 40d5419: feat(openai): add `o3-deep-research` and `o4-mini-deep-research` models
-
-## 3.0.0-beta.53
-
-### Patch Changes
-
-- dae2185: fix(openai): extract meta data from first chunk that contains any
-
-## 3.0.0-beta.52
-
-### Patch Changes
-
-- 348fd10: fix(openai): treat unknown models as reasoning
-
-## 3.0.0-beta.51
-
-### Patch Changes
-
-- b82987c: feat(openai): support openai code-interpreter annotations
-
-## 3.0.0-beta.50
-
-### Patch Changes
-
-- Updated dependencies [bb36798]
- - @ai-sdk/provider@3.0.0-beta.15
- - @ai-sdk/provider-utils@4.0.0-beta.31
-
-## 3.0.0-beta.49
-
-### Patch Changes
-
-- 0273b74: fix(openai): add support for sources type 'api'
-
-## 3.0.0-beta.48
-
-### Patch Changes
-
-- 60f4775: fix: remove code for unsuported o1-mini and o1-preview models
-
-## 3.0.0-beta.47
-
-### Patch Changes
-
-- Updated dependencies [4f16c37]
- - @ai-sdk/provider-utils@4.0.0-beta.30
-
-## 3.0.0-beta.46
-
-### Patch Changes
-
-- Updated dependencies [af3780b]
- - @ai-sdk/provider@3.0.0-beta.14
- - @ai-sdk/provider-utils@4.0.0-beta.29
-
-## 3.0.0-beta.45
-
-### Patch Changes
-
-- fd47df5: fix(openai): revised_prompt sometimes returns null, causing errors
-
-## 3.0.0-beta.44
-
-### Patch Changes
-
-- Updated dependencies [016b111]
- - @ai-sdk/provider-utils@4.0.0-beta.28
-
-## 3.0.0-beta.43
-
-### Patch Changes
-
-- Updated dependencies [37c58a0]
- - @ai-sdk/provider@3.0.0-beta.13
- - @ai-sdk/provider-utils@4.0.0-beta.27
-
-## 3.0.0-beta.42
-
-### Patch Changes
-
-- Updated dependencies [d1bdadb]
- - @ai-sdk/provider@3.0.0-beta.12
- - @ai-sdk/provider-utils@4.0.0-beta.26
-
-## 3.0.0-beta.41
-
-### Patch Changes
-
-- Updated dependencies [4c44a5b]
- - @ai-sdk/provider@3.0.0-beta.11
- - @ai-sdk/provider-utils@4.0.0-beta.25
-
-## 3.0.0-beta.40
-
-### Patch Changes
-
-- 1b982e6: feat(openai): preserve file_id when converting file citations
-
-## 3.0.0-beta.39
-
-### Patch Changes
-
-- 0c3b58b: fix(provider): add specificationVersion to ProviderV3
-- Updated dependencies [0c3b58b]
- - @ai-sdk/provider@3.0.0-beta.10
- - @ai-sdk/provider-utils@4.0.0-beta.24
-
-## 3.0.0-beta.38
-
-### Patch Changes
-
-- Updated dependencies [a755db5]
- - @ai-sdk/provider@3.0.0-beta.9
- - @ai-sdk/provider-utils@4.0.0-beta.23
-
-## 3.0.0-beta.37
-
-### Patch Changes
-
-- e85fa2f: feat(openai): add sources in web-search actions
-
-## 3.0.0-beta.36
-
-### Patch Changes
-
-- Updated dependencies [58920e0]
- - @ai-sdk/provider-utils@4.0.0-beta.22
-
-## 3.0.0-beta.35
-
-### Patch Changes
-
-- Updated dependencies [293a6b7]
- - @ai-sdk/provider-utils@4.0.0-beta.21
-
-## 3.0.0-beta.34
-
-### Patch Changes
-
-- Updated dependencies [fca786b]
- - @ai-sdk/provider-utils@4.0.0-beta.20
-
-## 3.0.0-beta.33
-
-### Patch Changes
-
-- 7756857: fix(provider/openai): add truncation parameter support for Responses API
-
-## 3.0.0-beta.32
-
-### Patch Changes
-
-- 3794514: feat: flexible tool output content support
-- Updated dependencies [3794514]
- - @ai-sdk/provider-utils@4.0.0-beta.19
- - @ai-sdk/provider@3.0.0-beta.8
-
-## 3.0.0-beta.31
-
-### Patch Changes
-
-- Updated dependencies [81d4308]
- - @ai-sdk/provider@3.0.0-beta.7
- - @ai-sdk/provider-utils@4.0.0-beta.18
-
-## 3.0.0-beta.30
-
-### Patch Changes
-
-- Updated dependencies [703459a]
- - @ai-sdk/provider-utils@4.0.0-beta.17
-
-## 3.0.0-beta.29
-
-### Patch Changes
-
-- 0b9fdd5: fix(provider/openai): end reasoning parts earlier
-
-## 3.0.0-beta.28
-
-### Patch Changes
-
-- 401f561: fix(provider/openai): fix web search tool input types
-
-## 3.0.0-beta.27
-
-### Patch Changes
-
-- f1277fe: feat(provider/openai): send assistant text and tool call parts as reference ids when store: true
-
-## 3.0.0-beta.26
-
-### Patch Changes
-
-- edc5548: feat(provider/openai): automatically add reasoning.encrypted_content include when store = false
-
-## 3.0.0-beta.25
-
-### Patch Changes
-
-- Updated dependencies [6306603]
- - @ai-sdk/provider-utils@4.0.0-beta.16
-
-## 3.0.0-beta.24
-
-### Patch Changes
-
-- Updated dependencies [f0b2157]
- - @ai-sdk/provider-utils@4.0.0-beta.15
-
-## 3.0.0-beta.23
-
-### Patch Changes
-
-- Updated dependencies [3b1d015]
- - @ai-sdk/provider-utils@4.0.0-beta.14
-
-## 3.0.0-beta.22
-
-### Patch Changes
-
-- Updated dependencies [d116b4b]
- - @ai-sdk/provider-utils@4.0.0-beta.13
-
-## 3.0.0-beta.21
-
-### Patch Changes
-
-- Updated dependencies [7e32fea]
- - @ai-sdk/provider-utils@4.0.0-beta.12
-
-## 3.0.0-beta.20
-
-### Patch Changes
-
-- 68c6187: feat(provider/openai): support file and image tool results
-
-## 3.0.0-beta.19
-
-### Patch Changes
-
-- 484aa93: Add 'default' as service tier
-
-## 3.0.0-beta.18
-
-### Patch Changes
-
-- 95f65c2: chore: use import \* from zod/v4
-- 95f65c2: chore: load zod schemas lazily
-- Updated dependencies
- - @ai-sdk/provider-utils@4.0.0-beta.11
-
-## 3.0.0-beta.17
-
-### Major Changes
-
-- dee8b05: ai SDK 6 beta
-
-### Patch Changes
-
-- Updated dependencies [dee8b05]
- - @ai-sdk/provider@3.0.0-beta.6
- - @ai-sdk/provider-utils@4.0.0-beta.10
-
-## 2.1.0-beta.16
-
-### Patch Changes
-
-- Updated dependencies [521c537]
- - @ai-sdk/provider-utils@3.1.0-beta.9
-
-## 2.1.0-beta.15
-
-### Patch Changes
-
-- Updated dependencies [e06565c]
- - @ai-sdk/provider-utils@3.1.0-beta.8
-
-## 2.1.0-beta.14
-
-### Patch Changes
-
-- 000e87b: fix(provider/openai): add providerExecuted flag to tool start chunks
-
-## 2.1.0-beta.13
-
-### Patch Changes
-
-- 357cfd7: feat(provider/openai): add new model IDs `gpt-image-1-mini`, `gpt-5-pro`, `gpt-5-pro-2025-10-06`
-
-## 2.1.0-beta.12
-
-### Patch Changes
-
-- 046aa3b: feat(provider): speech model v3 spec
-- e8109d3: feat: tool execution approval
-- 21e20c0: feat(provider): transcription model v3 spec
-- Updated dependencies
- - @ai-sdk/provider@2.1.0-beta.5
- - @ai-sdk/provider-utils@3.1.0-beta.7
-
-## 2.1.0-beta.11
-
-### Patch Changes
-
-- 0adc679: feat(provider): shared spec v3
-- 2b0caef: feat(provider/openai): preview image generation results
-- Updated dependencies
- - @ai-sdk/provider-utils@3.1.0-beta.6
- - @ai-sdk/provider@2.1.0-beta.4
-
-## 2.1.0-beta.10
-
-### Patch Changes
-
-- d64ece9: enables image_generation capabilities in the Azure provider through the Responses API.
-
-## 2.1.0-beta.9
-
-### Patch Changes
-
-- 9a51b92: support OPENAI_BASE_URL env
-
-## 2.1.0-beta.8
-
-### Patch Changes
-
-- 4122d2a: feat(provider/openai): add gpt-5-codex model id
-- 3997a42: feat(provider/openai): local shell tool
-- cb4d238: The built in Code Interpreter tool input code is streamed in `tool-input-` chunks.
-
-## 2.1.0-beta.7
-
-### Patch Changes
-
-- 77f2b20: enables code_interpreter and file_search capabilities in the Azure provider through the Responses API
-- 8dac895: feat: `LanguageModelV3`
-- 10c1322: fix: moved dependency `@ai-sdk/test-server` to devDependencies
-- Updated dependencies [8dac895]
- - @ai-sdk/provider-utils@3.1.0-beta.5
- - @ai-sdk/provider@2.1.0-beta.3
-
-## 2.1.0-beta.6
-
-### Patch Changes
-
-- fe49278: feat(provider/openai): only send item references for reasoning when store: true
-
-## 2.1.0-beta.5
-
-### Patch Changes
-
-- 4616b86: chore: update zod peer depenedency version
-- Updated dependencies [4616b86]
- - @ai-sdk/provider-utils@3.1.0-beta.4
-
-## 2.1.0-beta.4
-
-### Patch Changes
-
-- ed329cb: feat: `Provider-V3`
-- 522f6b8: feat: `ImageModelV3`
-- Updated dependencies
- - @ai-sdk/provider@2.1.0-beta.2
- - @ai-sdk/provider-utils@3.1.0-beta.3
-
-## 2.1.0-beta.3
-
-### Patch Changes
-
-- 2e86082: feat(provider/openai): `OpenAIChatLanguageModelOptions` type
-
- ```ts
- import { openai, type OpenAIChatLanguageModelOptions } from "@ai-sdk/openai";
- import { generateText } from "ai";
-
- await generateText({
- model: openai.chat("gpt-4o"),
- prompt: "Invent a new holiday and describe its traditions.",
- providerOptions: {
- openai: {
- user: "user-123",
- } satisfies OpenAIChatLanguageModelOptions,
- },
- });
- ```
-
-## 2.1.0-beta.2
-
-### Patch Changes
-
-- 4920119: fix the "incomplete_details" key from nullable to nullish for openai compatibility
-- 0c4822d: feat: `EmbeddingModelV3`
-- 1cad0ab: feat: add provider version to user-agent header
-- Updated dependencies [0c4822d]
- - @ai-sdk/provider@2.1.0-beta.1
- - @ai-sdk/provider-utils@3.1.0-beta.2
-
-## 2.1.0-beta.1
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/test-server@1.0.0-beta.0
- - @ai-sdk/provider-utils@3.1.0-beta.1
-
-## 2.1.0-beta.0
-
-### Minor Changes
-
-- 78928cb: release: start 5.1 beta
-
-### Patch Changes
-
-- Updated dependencies [78928cb]
- - @ai-sdk/provider@2.1.0-beta.0
- - @ai-sdk/provider-utils@3.1.0-beta.0
-
-## 2.0.32
-
-### Patch Changes
-
-- 1cf857d: fix(provider/openai): remove provider-executed tools from chat completions model
-- 01de47f: feat(provider/openai): rework file search tool
-
-## 2.0.31
-
-### Patch Changes
-
-- bb94467: feat(provider/openai): add maxToolCalls provider option
-- 4a2b70e: feat(provider/openai): send item references for provider-executed tool results
-- 643711d: feat (provider/openai): provider defined image generation tool support
-
-## 2.0.30
-
-### Patch Changes
-
-- Updated dependencies [0294b58]
- - @ai-sdk/provider-utils@3.0.9
-
-## 2.0.29
-
-### Patch Changes
-
-- 4235eb3: feat(provider/openai): code interpreter tool calls and results
-
-## 2.0.28
-
-### Patch Changes
-
-- 4c2bb77: fix (provider/openai): send sources action as include
-- 561e8b0: fix (provider/openai): fix code interpreter tool in doGenerate
-
-## 2.0.27
-
-### Patch Changes
-
-- 2338c79: feat (provider/openai): add jsdoc for openai tools
-
-## 2.0.26
-
-### Patch Changes
-
-- 5819aec: fix (provider/openai): only send tool calls finish reason for tools that are not provider-executed
-- af8c6bb: feat (provider/openai): add web_search tool
-
-## 2.0.25
-
-### Patch Changes
-
-- fb45ade: fix timestamp granularities support for openai transcription
-
-## 2.0.24
-
-### Patch Changes
-
-- ad57512: fix(provider/openai): safe practice to include filename and fileExtension to avoid `experimental_transcribe` fails with valid Buffer
-- Updated dependencies [99964ed]
- - @ai-sdk/provider-utils@3.0.8
-
-## 2.0.23
-
-### Patch Changes
-
-- a9a61b7: Add serviceTier to provider metadata for OpenAI responses
-
-## 2.0.22
-
-### Patch Changes
-
-- 0e272ae: fix(provider/openai): make file_citation annotation fields optional for responses api compatibility
-- Updated dependencies [886e7cd]
- - @ai-sdk/provider-utils@3.0.7
-
-## 2.0.21
-
-### Patch Changes
-
-- d18856a: fix(provider/openai): support websearch tool results without query property
-- 15271d6: fix(provider/openai): do not set `response_format` to `verbose_json` if model is `gpt-4o-transcribe` or `gpt-4o-mini-transcribe`
-
- These two models do not support it:
- https://platform.openai.com/docs/api-reference/audio/createTranscription#audio_createtranscription-response_format
-
-- Updated dependencies [1b5a3d3]
- - @ai-sdk/provider-utils@3.0.6
-
-## 2.0.20
-
-### Patch Changes
-
-- 974de40: fix(provider/ai): do not set `.providerMetadata.openai.logprobs` to an array of empty arrays when using `streamText()`
-
-## 2.0.19
-
-### Patch Changes
-
-- Updated dependencies [0857788]
- - @ai-sdk/provider-utils@3.0.5
-
-## 2.0.18
-
-### Patch Changes
-
-- 5e47d00: Support Responses API input_file file_url passthrough for PDFs.
-
- This adds:
-
- - file_url variant to OpenAIResponses user content
- - PDF URL mapping to input_file with file_url in Responses converter
- - PDF URL support in supportedUrls to avoid auto-download
-
-## 2.0.17
-
-### Patch Changes
-
-- 70bb696: fix(provider/openai): correct web search tool input
-
-## 2.0.16
-
-### Patch Changes
-
-- Updated dependencies [68751f9]
- - @ai-sdk/provider-utils@3.0.4
-
-## 2.0.15
-
-### Patch Changes
-
-- a4bef93: feat(provider/openai): expose web search queries in responses api
-- 6ed34cb: refactor(openai): consolidate model config into `getResponsesModelConfig()`
-
- https://github.com/vercel/ai/pull/8038
-
-## 2.0.14
-
-### Patch Changes
-
-- 7f47105: fix(provider/openai): support file_citation annotations in responses api
-
-## 2.0.13
-
-### Patch Changes
-
-- ddc9d99: Implements `logprobs` for OpenAI `providerOptions` and `providerMetaData` in `OpenAIResponsesLanguageModel`
-
- You can now set `providerOptions.openai.logprobs` when using `generateText()` and retrieve logprobs from the response via `result.providerMetadata?.openai`
-
-## 2.0.12
-
-### Patch Changes
-
-- ec336a1: feat(provider/openai): add response_format to be supported by default
-- 2935ec7: fix(provider/openai): exclude gpt-5-chat from reasoning model
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.3
-
-## 2.0.11
-
-### Patch Changes
-
-- 097b452: feat(openai, azure): add configurable file ID prefixes for Responses API
-
- - Added `fileIdPrefixes` option to OpenAI Responses API configuration
- - Azure OpenAI now supports `assistant-` prefixed file IDs (replacing previous `file-` prefix support)
- - OpenAI maintains backward compatibility with default `file-` prefix
- - File ID detection is disabled when `fileIdPrefixes` is undefined, gracefully falling back to base64 processing
-
-- 87cf954: feat(provider/openai): add support for prompt_cache_key
-- a3d98a9: feat(provider/openai): add support for safety_identifier
-- 110d167: fix(openai): add missing file_search_call handlers in responses streaming
-- 8d3c747: chore(openai): remove deprecated GPT-4.5-preview models and improve autocomplete control
-- Updated dependencies [38ac190]
- - @ai-sdk/provider-utils@3.0.2
-
-## 2.0.10
-
-### Patch Changes
-
-- a274b01: refactor(provider/openai): restructure files
-- b48e0ff: feat(provider/openai): add code interpreter tool (responses api)
-
-## 2.0.9
-
-### Patch Changes
-
-- 8f8a521: fix(providers): use convertToBase64 for Uint8Array image parts to produce valid data URLs; keep mediaType normalization and URL passthrough
-
-## 2.0.8
-
-### Patch Changes
-
-- 57fb959: feat(openai): add verbosity parameter support for chat api
-- 2a3fbe6: allow `minimal` in `reasoningEffort` for openai chat
-
-## 2.0.7
-
-### Patch Changes
-
-- 4738f18: feat(openai): add flex processing support for gpt-5 models
-- 013d747: feat(openai): add verbosity parameter support for responses api
-- 35feee8: feat(openai): add priority processing support for gpt-5 models
-
-## 2.0.6
-
-### Patch Changes
-
-- ad2255f: chore(docs): added gpt 5 models + removed deprecated models
-- 64bcb66: feat(provider/openai): models ids on chat
-- 1d42ff2: feat(provider/openai): models ids
-
-## 2.0.5
-
-### Patch Changes
-
-- 6753a2e: feat(examples): add gpt-5 model examples and e2e tests
-- 6cba06a: feat (provider/openai): add reasoning model config
-
-## 2.0.4
-
-### Patch Changes
-
-- c9e0f52: Files from the OpenAI Files API are now supported, mirroring functionality of OpenAI Chat and Responses API, respectively. Also, the AI SDK supports URLs for PDFs in the responses API the same way it did for completions.
-
-## 2.0.3
-
-### Patch Changes
-
-- Updated dependencies [90d212f]
- - @ai-sdk/provider-utils@3.0.1
-
-## 2.0.2
-
-### Patch Changes
-
-- 63e2016: fix(openai): missing url citations from web search tools
-
-## 2.0.1
-
-### Patch Changes
-
-- bc45e29: feat(openai): add file_search_call support to responses api
-
-## 2.0.0
-
-### Major Changes
-
-- d5f588f: AI SDK 5
-- cc62234: chore (provider/openai): switch default to openai responses api
-- 516be5b: ### Move Image Model Settings into generate options
-
- Image Models no longer have settings. Instead, `maxImagesPerCall` can be passed directly to `generateImage()`. All other image settings can be passed to `providerOptions[provider]`.
-
- Before
-
- ```js
- await generateImage({
- model: luma.image("photon-flash-1", {
- maxImagesPerCall: 5,
- pollIntervalMillis: 500,
- }),
- prompt,
- n: 10,
- });
- ```
-
- After
-
- ```js
- await generateImage({
- model: luma.image("photon-flash-1"),
- prompt,
- n: 10,
- maxImagesPerCall: 5,
- providerOptions: {
- luma: { pollIntervalMillis: 5 },
- },
- });
- ```
-
- Pull Request: https://github.com/vercel/ai/pull/6180
-
-- efc3a62: fix (provider/openai): default strict mode to false
-
-### Patch Changes
-
-- 948b755: chore(providers/openai): convert to providerOptions
-- d63bcbc: feat (provider/openai): o4 updates for responses api
-- 3bd3c0b: chore(providers/openai): update embedding model to use providerOptions
-- 5d959e7: refactor: updated openai + anthropic tool use server side
-- 0eee6a8: Fix streaming and reconstruction of reasoning summary parts
-- 177526b: chore(providers/openai-transcription): switch to providerOptions
-- 2f542fa: Add reasoning-part-finish parts for reasoning models in the responses API
-- c15dfbf: feat (providers/openai): add gpt-image-1 model id to image settings
-- 3b1ea10: adding support for gpt-4o-search-preview and handling unsupported parameters
-- e2aceaf: feat: add raw chunk support
-- d2af019: feat (providers/openai): add gpt-4.1 models
-- eb173f1: chore (providers): remove model shorthand deprecation warnings
-- 209256d: Add missing file_search tool support to OpenAI Responses API
-- faea29f: fix (provider/openai): multi-step reasoning with text
-- 7032dc5: feat(openai): add priority processing service tier support
-- 870c5c0: feat (providers/openai): add o3 and o4-mini models
-- db72adc: chore(providers/openai): update completion model to use providerOptions
-- a166433: feat: add transcription with experimental_transcribe
-- 26735b5: chore(embedding-model): add v2 interface
-- 443d8ec: feat(embedding-model-v2): add response body field
-- 8d12da5: feat(provider/openai): add serviceTier option for flex processing
-- 9bf7291: chore(providers/openai): enable structuredOutputs by default & switch to provider option
-- d521cda: feat(openai): add file_search filters and update field names
-- 66962ed: fix(packages): export node10 compatible types
-- 442be08: fix: propagate openai transcription fixes
-- 0059ee2: fix(openai): update file_search fields to match API changes
-- 8493141: feat (providers/openai): add support for reasoning summaries
-- 9301f86: refactor (image-model): rename `ImageModelV1` to `ImageModelV2`
-- 0a87932: core (ai): change transcription model mimeType to mediaType
-- 8aa9e20: feat: add speech with experimental_generateSpeech
-- 4617fab: chore(embedding-models): remove remaining settings
-- b5a0e32: fix (provider/openai): correct default for chat model strict mode
-- 136819b: chore(providers/openai): re-introduce logprobs as providerMetadata
-- 52ce942: chore(providers/openai): remove & enable strict compatibility by default
-- db64cbe: fix (provider/openai): multi-step reasoning with tool calls
-- b3c3450: feat (provider/openai): add support for encrypted_reasoning to responses api
-- 48249c4: Do not warn if empty text is the first part of a reasoning sequence
-- c7d3b2e: fix (provider/openai): push first reasoning chunk in output item added event
-- ad2a3d5: feat(provider/openai): add missing reasoning models to responses API
-- 9943464: feat(openai): add file_search_call.results support to include parameter
-- 0fa7414: chore (provider/openai): standardize on itemId in provider metadata
-- 9bd5ab5: feat (provider): add providerMetadata to ImageModelV2 interface (#5977)
-
- The `experimental_generateImage` method from the `ai` package now returnes revised prompts for OpenAI's image models.
-
- ```js
- const prompt = "Santa Claus driving a Cadillac";
-
- const { providerMetadata } = await experimental_generateImage({
- model: openai.image("dall-e-3"),
- prompt,
- });
-
- const revisedPrompt = providerMetadata.openai.images[0]?.revisedPrompt;
-
- console.log({
- prompt,
- revisedPrompt,
- });
- ```
-
-- fa758ea: feat(provider/openai): add o3 & o4-mini with developer systemMessageMode
-- d1a034f: feature: using Zod 4 for internal stuff
-- fd65bc6: chore(embedding-model-v2): rename rawResponse to response
-- e497698: fix (provider/openai): handle responses api errors
-- 928fadf: fix(providers/openai): logprobs for stream alongside completion model
-- 0a87932: fix (provider/openai): increase transcription model resilience
-- 5147e6e: chore(openai): remove simulateStreaming
-- 06bac05: fix (openai): structure output for responses model
-- 205077b: fix: improve Zod compatibility
-- c2b92cc: chore(openai): remove legacy function calling
-- 284353f: fix(providers/openai): zod parse error with function
-- 6f231db: fix(providers): always use optional instead of mix of nullish for providerOptions
-- f10304b: feat(tool-calling): don't require the user to have to pass parameters
-- 4af5233: Fix PDF file parts when passed as a string url or Uint8Array
-- 7df7a25: feat (providers/openai): support gpt-image-1 image generation
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0
- - @ai-sdk/provider@2.0.0
-
-## 2.0.0-beta.16
-
-### Patch Changes
-
-- Updated dependencies [88a8ee5]
- - @ai-sdk/provider-utils@3.0.0-beta.10
-
-## 2.0.0-beta.15
-
-### Patch Changes
-
-- 9943464: feat(openai): add file_search_call.results support to include parameter
-- Updated dependencies [27deb4d]
- - @ai-sdk/provider@2.0.0-beta.2
- - @ai-sdk/provider-utils@3.0.0-beta.9
-
-## 2.0.0-beta.14
-
-### Patch Changes
-
-- eb173f1: chore (providers): remove model shorthand deprecation warnings
-- 7032dc5: feat(openai): add priority processing service tier support
-- Updated dependencies [dd5fd43]
- - @ai-sdk/provider-utils@3.0.0-beta.8
-
-## 2.0.0-beta.13
-
-### Patch Changes
-
-- Updated dependencies [e7fcc86]
- - @ai-sdk/provider-utils@3.0.0-beta.7
-
-## 2.0.0-beta.12
-
-### Patch Changes
-
-- d521cda: feat(openai): add file_search filters and update field names
-- 0059ee2: fix(openai): update file_search fields to match API changes
-- Updated dependencies [ac34802]
- - @ai-sdk/provider-utils@3.0.0-beta.6
-
-## 2.0.0-beta.11
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-beta.5
-
-## 2.0.0-beta.10
-
-### Patch Changes
-
-- 0fa7414: chore (provider/openai): standardize on itemId in provider metadata
-- 205077b: fix: improve Zod compatibility
-- Updated dependencies [205077b]
- - @ai-sdk/provider-utils@3.0.0-beta.4
-
-## 2.0.0-beta.9
-
-### Patch Changes
-
-- faea29f: fix (provider/openai): multi-step reasoning with text
-
-## 2.0.0-beta.8
-
-### Patch Changes
-
-- db64cbe: fix (provider/openai): multi-step reasoning with tool calls
-- Updated dependencies [05d2819]
- - @ai-sdk/provider-utils@3.0.0-beta.3
-
-## 2.0.0-beta.7
-
-### Patch Changes
-
-- 209256d: Add missing file_search tool support to OpenAI Responses API
-
-## 2.0.0-beta.6
-
-### Patch Changes
-
-- 0eee6a8: Fix streaming and reconstruction of reasoning summary parts
-- b5a0e32: fix (provider/openai): correct default for chat model strict mode
-- c7d3b2e: fix (provider/openai): push first reasoning chunk in output item added event
-
-## 2.0.0-beta.5
-
-### Patch Changes
-
-- 48249c4: Do not warn if empty text is the first part of a reasoning sequence
-- e497698: fix (provider/openai): handle responses api errors
-
-## 2.0.0-beta.4
-
-### Patch Changes
-
-- b3c3450: feat (provider/openai): add support for encrypted_reasoning to responses api
-- ad2a3d5: feat(provider/openai): add missing reasoning models to responses API
-
-## 2.0.0-beta.3
-
-### Major Changes
-
-- efc3a62: fix (provider/openai): default strict mode to false
-
-## 2.0.0-beta.2
-
-### Patch Changes
-
-- d1a034f: feature: using Zod 4 for internal stuff
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-beta.2
-
-## 2.0.0-beta.1
-
-### Major Changes
-
-- cc62234: chore (provider/openai): switch default to openai responses api
-
-### Patch Changes
-
-- 5d959e7: refactor: updated openai + anthropic tool use server side
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-beta.1
- - @ai-sdk/provider-utils@3.0.0-beta.1
-
-## 2.0.0-alpha.15
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-alpha.15
- - @ai-sdk/provider-utils@3.0.0-alpha.15
-
-## 2.0.0-alpha.14
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-alpha.14
- - @ai-sdk/provider-utils@3.0.0-alpha.14
-
-## 2.0.0-alpha.13
-
-### Patch Changes
-
-- Updated dependencies [68ecf2f]
- - @ai-sdk/provider@2.0.0-alpha.13
- - @ai-sdk/provider-utils@3.0.0-alpha.13
-
-## 2.0.0-alpha.12
-
-### Patch Changes
-
-- 2f542fa: Add reasoning-part-finish parts for reasoning models in the responses API
-- e2aceaf: feat: add raw chunk support
-- Updated dependencies [e2aceaf]
- - @ai-sdk/provider@2.0.0-alpha.12
- - @ai-sdk/provider-utils@3.0.0-alpha.12
-
-## 2.0.0-alpha.11
-
-### Patch Changes
-
-- 8d12da5: feat(provider/openai): add serviceTier option for flex processing
-- Updated dependencies [c1e6647]
- - @ai-sdk/provider@2.0.0-alpha.11
- - @ai-sdk/provider-utils@3.0.0-alpha.11
-
-## 2.0.0-alpha.10
-
-### Patch Changes
-
-- Updated dependencies [c4df419]
- - @ai-sdk/provider@2.0.0-alpha.10
- - @ai-sdk/provider-utils@3.0.0-alpha.10
-
-## 2.0.0-alpha.9
-
-### Patch Changes
-
-- Updated dependencies [811dff3]
- - @ai-sdk/provider@2.0.0-alpha.9
- - @ai-sdk/provider-utils@3.0.0-alpha.9
-
-## 2.0.0-alpha.8
-
-### Patch Changes
-
-- 4af5233: Fix PDF file parts when passed as a string url or Uint8Array
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-alpha.8
- - @ai-sdk/provider@2.0.0-alpha.8
-
-## 2.0.0-alpha.7
-
-### Patch Changes
-
-- Updated dependencies [5c56081]
- - @ai-sdk/provider@2.0.0-alpha.7
- - @ai-sdk/provider-utils@3.0.0-alpha.7
-
-## 2.0.0-alpha.6
-
-### Patch Changes
-
-- Updated dependencies [0d2c085]
- - @ai-sdk/provider@2.0.0-alpha.6
- - @ai-sdk/provider-utils@3.0.0-alpha.6
-
-## 2.0.0-alpha.4
-
-### Patch Changes
-
-- Updated dependencies [dc714f3]
- - @ai-sdk/provider@2.0.0-alpha.4
- - @ai-sdk/provider-utils@3.0.0-alpha.4
-
-## 2.0.0-alpha.3
-
-### Patch Changes
-
-- Updated dependencies [6b98118]
- - @ai-sdk/provider@2.0.0-alpha.3
- - @ai-sdk/provider-utils@3.0.0-alpha.3
-
-## 2.0.0-alpha.2
-
-### Patch Changes
-
-- Updated dependencies [26535e0]
- - @ai-sdk/provider@2.0.0-alpha.2
- - @ai-sdk/provider-utils@3.0.0-alpha.2
-
-## 2.0.0-alpha.1
-
-### Patch Changes
-
-- Updated dependencies [3f2f00c]
- - @ai-sdk/provider@2.0.0-alpha.1
- - @ai-sdk/provider-utils@3.0.0-alpha.1
-
-## 2.0.0-canary.20
-
-### Patch Changes
-
-- Updated dependencies [faf8446]
- - @ai-sdk/provider-utils@3.0.0-canary.19
-
-## 2.0.0-canary.19
-
-### Patch Changes
-
-- Updated dependencies [40acf9b]
- - @ai-sdk/provider-utils@3.0.0-canary.18
-
-## 2.0.0-canary.18
-
-### Major Changes
-
-- 516be5b: ### Move Image Model Settings into generate options
-
- Image Models no longer have settings. Instead, `maxImagesPerCall` can be passed directly to `generateImage()`. All other image settings can be passed to `providerOptions[provider]`.
-
- Before
-
- ```js
- await generateImage({
- model: luma.image("photon-flash-1", {
- maxImagesPerCall: 5,
- pollIntervalMillis: 500,
- }),
- prompt,
- n: 10,
- });
- ```
-
- After
-
- ```js
- await generateImage({
- model: luma.image("photon-flash-1"),
- prompt,
- n: 10,
- maxImagesPerCall: 5,
- providerOptions: {
- luma: { pollIntervalMillis: 5 },
- },
- });
- ```
-
- Pull Request: https://github.com/vercel/ai/pull/6180
-
-### Patch Changes
-
-- Updated dependencies [ea7a7c9]
- - @ai-sdk/provider-utils@3.0.0-canary.17
-
-## 2.0.0-canary.17
-
-### Patch Changes
-
-- 52ce942: chore(providers/openai): remove & enable strict compatibility by default
-- Updated dependencies [87b828f]
- - @ai-sdk/provider-utils@3.0.0-canary.16
-
-## 2.0.0-canary.16
-
-### Patch Changes
-
-- 928fadf: fix(providers/openai): logprobs for stream alongside completion model
-- 6f231db: fix(providers): always use optional instead of mix of nullish for providerOptions
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-canary.15
- - @ai-sdk/provider@2.0.0-canary.14
-
-## 2.0.0-canary.15
-
-### Patch Changes
-
-- 136819b: chore(providers/openai): re-introduce logprobs as providerMetadata
-- 9bd5ab5: feat (provider): add providerMetadata to ImageModelV2 interface (#5977)
-
- The `experimental_generateImage` method from the `ai` package now returnes revised prompts for OpenAI's image models.
-
- ```js
- const prompt = "Santa Claus driving a Cadillac";
-
- const { providerMetadata } = await experimental_generateImage({
- model: openai.image("dall-e-3"),
- prompt,
- });
-
- const revisedPrompt = providerMetadata.openai.images[0]?.revisedPrompt;
-
- console.log({
- prompt,
- revisedPrompt,
- });
- ```
-
-- 284353f: fix(providers/openai): zod parse error with function
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-canary.14
- - @ai-sdk/provider@2.0.0-canary.13
-
-## 2.0.0-canary.14
-
-### Patch Changes
-
-- fa758ea: feat(provider/openai): add o3 & o4-mini with developer systemMessageMode
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.12
- - @ai-sdk/provider-utils@3.0.0-canary.13
-
-## 2.0.0-canary.13
-
-### Patch Changes
-
-- 177526b: chore(providers/openai-transcription): switch to providerOptions
-- c15dfbf: feat (providers/openai): add gpt-image-1 model id to image settings
-- 9bf7291: chore(providers/openai): enable structuredOutputs by default & switch to provider option
-- 4617fab: chore(embedding-models): remove remaining settings
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.11
- - @ai-sdk/provider-utils@3.0.0-canary.12
-
-## 2.0.0-canary.12
-
-### Patch Changes
-
-- db72adc: chore(providers/openai): update completion model to use providerOptions
-- 66962ed: fix(packages): export node10 compatible types
-- 9301f86: refactor (image-model): rename `ImageModelV1` to `ImageModelV2`
-- 7df7a25: feat (providers/openai): support gpt-image-1 image generation
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-canary.11
- - @ai-sdk/provider@2.0.0-canary.10
-
-## 2.0.0-canary.11
-
-### Patch Changes
-
-- 8493141: feat (providers/openai): add support for reasoning summaries
-- Updated dependencies [e86be6f]
- - @ai-sdk/provider@2.0.0-canary.9
- - @ai-sdk/provider-utils@3.0.0-canary.10
-
-## 2.0.0-canary.10
-
-### Patch Changes
-
-- 3bd3c0b: chore(providers/openai): update embedding model to use providerOptions
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.8
- - @ai-sdk/provider-utils@3.0.0-canary.9
-
-## 2.0.0-canary.9
-
-### Patch Changes
-
-- d63bcbc: feat (provider/openai): o4 updates for responses api
-- d2af019: feat (providers/openai): add gpt-4.1 models
-- 870c5c0: feat (providers/openai): add o3 and o4-mini models
-- 06bac05: fix (openai): structure output for responses model
-
-## 2.0.0-canary.8
-
-### Patch Changes
-
-- 8aa9e20: feat: add speech with experimental_generateSpeech
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-canary.8
- - @ai-sdk/provider@2.0.0-canary.7
-
-## 2.0.0-canary.7
-
-### Patch Changes
-
-- 26735b5: chore(embedding-model): add v2 interface
-- 443d8ec: feat(embedding-model-v2): add response body field
-- fd65bc6: chore(embedding-model-v2): rename rawResponse to response
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.6
- - @ai-sdk/provider-utils@3.0.0-canary.7
-
-## 2.0.0-canary.6
-
-### Patch Changes
-
-- 948b755: chore(providers/openai): convert to providerOptions
-- 3b1ea10: adding support for gpt-4o-search-preview and handling unsupported parameters
-- 442be08: fix: propagate openai transcription fixes
-- 5147e6e: chore(openai): remove simulateStreaming
-- c2b92cc: chore(openai): remove legacy function calling
-- f10304b: feat(tool-calling): don't require the user to have to pass parameters
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.5
- - @ai-sdk/provider-utils@3.0.0-canary.6
-
-## 2.0.0-canary.5
-
-### Patch Changes
-
-- Updated dependencies [6f6bb89]
- - @ai-sdk/provider@2.0.0-canary.4
- - @ai-sdk/provider-utils@3.0.0-canary.5
-
-## 2.0.0-canary.4
-
-### Patch Changes
-
-- Updated dependencies [d1a1aa1]
- - @ai-sdk/provider@2.0.0-canary.3
- - @ai-sdk/provider-utils@3.0.0-canary.4
-
-## 2.0.0-canary.3
-
-### Patch Changes
-
-- a166433: feat: add transcription with experimental_transcribe
-- 0a87932: core (ai): change transcription model mimeType to mediaType
-- 0a87932: fix (provider/openai): increase transcription model resilience
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-canary.3
- - @ai-sdk/provider@2.0.0-canary.2
-
-## 2.0.0-canary.2
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.1
- - @ai-sdk/provider-utils@3.0.0-canary.2
-
-## 2.0.0-canary.1
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@3.0.0-canary.1
-
-## 2.0.0-canary.0
-
-### Major Changes
-
-- d5f588f: AI SDK 5
-
-### Patch Changes
-
-- Updated dependencies [d5f588f]
- - @ai-sdk/provider-utils@3.0.0-canary.0
- - @ai-sdk/provider@2.0.0-canary.0
-
-## 1.3.6
-
-### Patch Changes
-
-- Updated dependencies [28be004]
- - @ai-sdk/provider-utils@2.2.3
-
-## 1.3.5
-
-### Patch Changes
-
-- 52ed95f: fix (provider/openai): force web search tool
-- Updated dependencies [b01120e]
- - @ai-sdk/provider-utils@2.2.2
-
-## 1.3.4
-
-### Patch Changes
-
-- b520dba: feat (provider/openai): add chatgpt-4o-latest model
-
-## 1.3.3
-
-### Patch Changes
-
-- 24befd8: feat (provider/openai): add instructions to providerOptions
-
-## 1.3.2
-
-### Patch Changes
-
-- db15028: feat (provider/openai): expose type for validating OpenAI responses provider options
-
-## 1.3.1
-
-### Patch Changes
-
-- Updated dependencies [f10f0fa]
- - @ai-sdk/provider-utils@2.2.1
-
-## 1.3.0
-
-### Minor Changes
-
-- 5bc638d: AI SDK 4.2
-
-### Patch Changes
-
-- Updated dependencies [5bc638d]
- - @ai-sdk/provider@1.1.0
- - @ai-sdk/provider-utils@2.2.0
-
-## 1.2.8
-
-### Patch Changes
-
-- 9f4f1bc: feat (provider/openai): pdf support for chat language models
-
-## 1.2.7
-
-### Patch Changes
-
-- Updated dependencies [d0c4659]
- - @ai-sdk/provider-utils@2.1.15
-
-## 1.2.6
-
-### Patch Changes
-
-- Updated dependencies [0bd5bc6]
- - @ai-sdk/provider@1.0.12
- - @ai-sdk/provider-utils@2.1.14
-
-## 1.2.5
-
-### Patch Changes
-
-- 2e1101a: feat (provider/openai): pdf input support
-- Updated dependencies [2e1101a]
- - @ai-sdk/provider@1.0.11
- - @ai-sdk/provider-utils@2.1.13
-
-## 1.2.4
-
-### Patch Changes
-
-- 523f128: feat (provider/openai): add strictSchemas option to responses model
-
-## 1.2.3
-
-### Patch Changes
-
-- Updated dependencies [1531959]
- - @ai-sdk/provider-utils@2.1.12
-
-## 1.2.2
-
-### Patch Changes
-
-- e3a389e: feat (provider/openai): support responses api
-
-## 1.2.1
-
-### Patch Changes
-
-- e1d3d42: feat (ai): expose raw response body in generateText and generateObject
-- Updated dependencies [e1d3d42]
- - @ai-sdk/provider@1.0.10
- - @ai-sdk/provider-utils@2.1.11
-
-## 1.2.0
-
-### Minor Changes
-
-- ede6d1b: feat (provider/azure): Add Azure image model support
-
-## 1.1.15
-
-### Patch Changes
-
-- d8216f8: feat (provider/openai): add gpt-4.5-preview to model id set
-
-## 1.1.14
-
-### Patch Changes
-
-- Updated dependencies [ddf9740]
- - @ai-sdk/provider@1.0.9
- - @ai-sdk/provider-utils@2.1.10
-
-## 1.1.13
-
-### Patch Changes
-
-- Updated dependencies [2761f06]
- - @ai-sdk/provider@1.0.8
- - @ai-sdk/provider-utils@2.1.9
-
-## 1.1.12
-
-### Patch Changes
-
-- ea159cb: chore (provider/openai): remove default streaming simulation for o1
-
-## 1.1.11
-
-### Patch Changes
-
-- Updated dependencies [2e898b4]
- - @ai-sdk/provider-utils@2.1.8
-
-## 1.1.10
-
-### Patch Changes
-
-- Updated dependencies [3ff4ef8]
- - @ai-sdk/provider-utils@2.1.7
-
-## 1.1.9
-
-### Patch Changes
-
-- c55b81a: fix (provider/openai): fix o3-mini streaming
-
-## 1.1.8
-
-### Patch Changes
-
-- 161be90: fix (provider/openai): fix model id typo
-
-## 1.1.7
-
-### Patch Changes
-
-- 0a2f026: feat (provider/openai): add o3-mini
-
-## 1.1.6
-
-### Patch Changes
-
-- d89c3b9: feat (provider): add image model support to provider specification
-- Updated dependencies [d89c3b9]
- - @ai-sdk/provider@1.0.7
- - @ai-sdk/provider-utils@2.1.6
-
-## 1.1.5
-
-### Patch Changes
-
-- Updated dependencies [3a602ca]
- - @ai-sdk/provider-utils@2.1.5
-
-## 1.1.4
-
-### Patch Changes
-
-- Updated dependencies [066206e]
- - @ai-sdk/provider-utils@2.1.4
-
-## 1.1.3
-
-### Patch Changes
-
-- Updated dependencies [39e5c1f]
- - @ai-sdk/provider-utils@2.1.3
-
-## 1.1.2
-
-### Patch Changes
-
-- 3a58a2e: feat (ai/core): throw NoImageGeneratedError from generateImage when no predictions are returned.
-- Updated dependencies
- - @ai-sdk/provider-utils@2.1.2
- - @ai-sdk/provider@1.0.6
-
-## 1.1.1
-
-### Patch Changes
-
-- e7a9ec9: feat (provider-utils): include raw value in json parse results
-- Updated dependencies
- - @ai-sdk/provider-utils@2.1.1
- - @ai-sdk/provider@1.0.5
-
-## 1.1.0
-
-### Minor Changes
-
-- 62ba5ad: release: AI SDK 4.1
-
-### Patch Changes
-
-- Updated dependencies [62ba5ad]
- - @ai-sdk/provider-utils@2.1.0
-
-## 1.0.20
-
-### Patch Changes
-
-- Updated dependencies [00114c5]
- - @ai-sdk/provider-utils@2.0.8
-
-## 1.0.19
-
-### Patch Changes
-
-- 218d001: feat (provider): Add maxImagesPerCall setting to all image providers.
-
-## 1.0.18
-
-### Patch Changes
-
-- fe816e4: fix (provider/openai): streamObject with o1
-
-## 1.0.17
-
-### Patch Changes
-
-- ba62cf2: feat (provider/openai): automatically map maxTokens to max_completion_tokens for reasoning models
-- 3c3fae8: fix (provider/openai): add o1-mini-2024-09-12 and o1-preview-2024-09-12 configurations
-
-## 1.0.16
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@2.0.7
-
-## 1.0.15
-
-### Patch Changes
-
-- f8c6acb: feat (provider/openai): automatically simulate streaming for reasoning models
-- d0041f7: feat (provider/openai): improved system message support for reasoning models
-- 4d2f97b: feat (provider/openai): improve automatic setting removal for reasoning models
-
-## 1.0.14
-
-### Patch Changes
-
-- 19a2ce7: feat (ai/core): add aspectRatio and seed options to generateImage
-- 6337688: feat: change image generation errors to warnings
-- Updated dependencies
- - @ai-sdk/provider@1.0.4
- - @ai-sdk/provider-utils@2.0.6
-
-## 1.0.13
-
-### Patch Changes
-
-- b19aa82: feat (provider/openai): add predicted outputs token usage
-
-## 1.0.12
-
-### Patch Changes
-
-- a4241ff: feat (provider/openai): add o3 reasoning model support
-
-## 1.0.11
-
-### Patch Changes
-
-- 5ed5e45: chore (config): Use ts-library.json tsconfig for no-UI libs.
-- Updated dependencies [5ed5e45]
- - @ai-sdk/provider-utils@2.0.5
- - @ai-sdk/provider@1.0.3
-
-## 1.0.10
-
-### Patch Changes
-
-- d4fad4e: fix (provider/openai): fix reasoning model detection
-
-## 1.0.9
-
-### Patch Changes
-
-- 3fab0fb: feat (provider/openai): support reasoning_effort setting
-- e956eed: feat (provider/openai): update model list and add o1
-- 6faab13: feat (provider/openai): simulated streaming setting
-
-## 1.0.8
-
-### Patch Changes
-
-- 09a9cab: feat (ai/core): add experimental generateImage function
-- Updated dependencies [09a9cab]
- - @ai-sdk/provider@1.0.2
- - @ai-sdk/provider-utils@2.0.4
-
-## 1.0.7
-
-### Patch Changes
-
-- Updated dependencies [0984f0b]
- - @ai-sdk/provider-utils@2.0.3
-
-## 1.0.6
-
-### Patch Changes
-
-- a9a19cb: fix (provider/openai,groq): prevent sending duplicate tool calls
-
-## 1.0.5
-
-### Patch Changes
-
-- fc18132: feat (ai/core): experimental output for generateText
-
-## 1.0.4
-
-### Patch Changes
-
-- Updated dependencies [b446ae5]
- - @ai-sdk/provider@1.0.1
- - @ai-sdk/provider-utils@2.0.2
-
-## 1.0.3
-
-### Patch Changes
-
-- b748dfb: feat (providers): update model lists
-
-## 1.0.2
-
-### Patch Changes
-
-- Updated dependencies [c3ab5de]
- - @ai-sdk/provider-utils@2.0.1
-
-## 1.0.1
-
-### Patch Changes
-
-- 5e6419a: feat (provider/openai): support streaming for reasoning models
-
-## 1.0.0
-
-### Major Changes
-
-- 66060f7: chore (release): bump major version to 4.0
-- 79644e9: chore (provider/openai): remove OpenAI facade
-- 0d3d3f5: chore (providers): remove baseUrl option
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@2.0.0
- - @ai-sdk/provider@1.0.0
-
-## 1.0.0-canary.3
-
-### Patch Changes
-
-- Updated dependencies [8426f55]
- - @ai-sdk/provider-utils@2.0.0-canary.3
-
-## 1.0.0-canary.2
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@2.0.0-canary.2
-
-## 1.0.0-canary.1
-
-### Major Changes
-
-- 79644e9: chore (provider/openai): remove OpenAI facade
-- 0d3d3f5: chore (providers): remove baseUrl option
-
-### Patch Changes
-
-- Updated dependencies [b1da952]
- - @ai-sdk/provider-utils@2.0.0-canary.1
-
-## 1.0.0-canary.0
-
-### Major Changes
-
-- 66060f7: chore (release): bump major version to 4.0
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@2.0.0-canary.0
- - @ai-sdk/provider@1.0.0-canary.0
-
-## 0.0.72
-
-### Patch Changes
-
-- 0bc4115: feat (provider/openai): support predicted outputs
-
-## 0.0.71
-
-### Patch Changes
-
-- 54a3a59: fix (provider/openai): support object-json mode without schema
-
-## 0.0.70
-
-### Patch Changes
-
-- 3b1b69a: feat: provider-defined tools
-- Updated dependencies
- - @ai-sdk/provider-utils@1.0.22
- - @ai-sdk/provider@0.0.26
-
-## 0.0.69
-
-### Patch Changes
-
-- b9b0d7b: feat (ai): access raw request body
-- Updated dependencies [b9b0d7b]
- - @ai-sdk/provider@0.0.25
- - @ai-sdk/provider-utils@1.0.21
-
-## 0.0.68
-
-### Patch Changes
-
-- 741ca51: feat (provider/openai): support mp3 and wav audio inputs
-
-## 0.0.67
-
-### Patch Changes
-
-- 39fccee: feat (provider/openai): provider name can be changed for 3rd party openai compatible providers
-
-## 0.0.66
-
-### Patch Changes
-
-- 3f29c10: feat (provider/openai): support metadata field for distillation
-
-## 0.0.65
-
-### Patch Changes
-
-- e8aed44: Add OpenAI cached prompt tokens to experimental_providerMetadata for generateText and streamText
-
-## 0.0.64
-
-### Patch Changes
-
-- 5aa576d: feat (provider/openai): support store parameter for distillation
-
-## 0.0.63
-
-### Patch Changes
-
-- Updated dependencies [d595d0d]
- - @ai-sdk/provider@0.0.24
- - @ai-sdk/provider-utils@1.0.20
-
-## 0.0.62
-
-### Patch Changes
-
-- 7efa867: feat (provider/openai): simulated streaming for reasoning models
-
-## 0.0.61
-
-### Patch Changes
-
-- 8132a60: feat (provider/openai): support reasoning token usage and max_completion_tokens
-
-## 0.0.60
-
-### Patch Changes
-
-- Updated dependencies [273f696]
- - @ai-sdk/provider-utils@1.0.19
-
-## 0.0.59
-
-### Patch Changes
-
-- a0991ec: feat (provider/openai): add o1-preview and o1-mini models
-
-## 0.0.58
-
-### Patch Changes
-
-- e0c36bd: feat (provider/openai): support image detail
-
-## 0.0.57
-
-### Patch Changes
-
-- d1aaeae: feat (provider/openai): support ai sdk image download
-
-## 0.0.56
-
-### Patch Changes
-
-- 03313cd: feat (ai): expose response id, response model, response timestamp in telemetry and api
-- Updated dependencies
- - @ai-sdk/provider-utils@1.0.18
- - @ai-sdk/provider@0.0.23
-
-## 0.0.55
-
-### Patch Changes
-
-- 28cbf2e: fix (provider/openai): support tool call deltas when arguments are sent in the first chunk
-
-## 0.0.54
-
-### Patch Changes
-
-- 26515cb: feat (ai/provider): introduce ProviderV1 specification
-- Updated dependencies [26515cb]
- - @ai-sdk/provider@0.0.22
- - @ai-sdk/provider-utils@1.0.17
-
-## 0.0.53
-
-### Patch Changes
-
-- Updated dependencies [09f895f]
- - @ai-sdk/provider-utils@1.0.16
-
-## 0.0.52
-
-### Patch Changes
-
-- d5b6a15: feat (provider/openai): support partial usage information
-
-## 0.0.51
-
-### Patch Changes
-
-- Updated dependencies [d67fa9c]
- - @ai-sdk/provider-utils@1.0.15
-
-## 0.0.50
-
-### Patch Changes
-
-- Updated dependencies [f2c025e]
- - @ai-sdk/provider@0.0.21
- - @ai-sdk/provider-utils@1.0.14
-
-## 0.0.49
-
-### Patch Changes
-
-- f42d9bd: fix (provider/openai): support OpenRouter streaming errors
-
-## 0.0.48
-
-### Patch Changes
-
-- Updated dependencies [6ac355e]
- - @ai-sdk/provider@0.0.20
- - @ai-sdk/provider-utils@1.0.13
-
-## 0.0.47
-
-### Patch Changes
-
-- 4ffbaee: fix (provider/openai): fix strict flag for structured outputs with tools
-- dd712ac: fix: use FetchFunction type to prevent self-reference
-- Updated dependencies [dd712ac]
- - @ai-sdk/provider-utils@1.0.12
-
-## 0.0.46
-
-### Patch Changes
-
-- 89b18ca: fix (ai/provider): send finish reason 'unknown' by default
-- Updated dependencies [dd4a0f5]
- - @ai-sdk/provider@0.0.19
- - @ai-sdk/provider-utils@1.0.11
-
-## 0.0.45
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@1.0.10
- - @ai-sdk/provider@0.0.18
-
-## 0.0.44
-
-### Patch Changes
-
-- 029af4c: feat (ai/core): support schema name & description in generateObject & streamObject
-- Updated dependencies [029af4c]
- - @ai-sdk/provider@0.0.17
- - @ai-sdk/provider-utils@1.0.9
-
-## 0.0.43
-
-### Patch Changes
-
-- d58517b: feat (ai/openai): structured outputs
-- c0a73ee: feat (provider/openai): add gpt-4o-2024-08-06 to list of supported models
-- Updated dependencies [d58517b]
- - @ai-sdk/provider@0.0.16
- - @ai-sdk/provider-utils@1.0.8
-
-## 0.0.42
-
-### Patch Changes
-
-- Updated dependencies [96aed25]
- - @ai-sdk/provider@0.0.15
- - @ai-sdk/provider-utils@1.0.7
-
-## 0.0.41
-
-### Patch Changes
-
-- 7a2eb27: feat (provider/openai): make role nullish to enhance provider support
-- Updated dependencies
- - @ai-sdk/provider-utils@1.0.6
-
-## 0.0.40
-
-### Patch Changes
-
-- Updated dependencies [a8d1c9e9]
- - @ai-sdk/provider-utils@1.0.5
- - @ai-sdk/provider@0.0.14
-
-## 0.0.39
-
-### Patch Changes
-
-- Updated dependencies [4f88248f]
- - @ai-sdk/provider-utils@1.0.4
-
-## 0.0.38
-
-### Patch Changes
-
-- 2b9da0f0: feat (core): support stopSequences setting.
-- 909b9d27: feat (ai/openai): Support legacy function calls
-- a5b58845: feat (core): support topK setting
-- 4aa8deb3: feat (provider): support responseFormat setting in provider api
-- 13b27ec6: chore (ai/core): remove grammar mode
-- Updated dependencies
- - @ai-sdk/provider@0.0.13
- - @ai-sdk/provider-utils@1.0.3
-
-## 0.0.37
-
-### Patch Changes
-
-- 89947fc5: chore (provider/openai): update model list for type-ahead support
-
-## 0.0.36
-
-### Patch Changes
-
-- b7290943: feat (ai/core): add token usage to embed and embedMany
-- Updated dependencies [b7290943]
- - @ai-sdk/provider@0.0.12
- - @ai-sdk/provider-utils@1.0.2
-
-## 0.0.35
-
-### Patch Changes
-
-- Updated dependencies [d481729f]
- - @ai-sdk/provider-utils@1.0.1
-
-## 0.0.34
-
-### Patch Changes
-
-- 5edc6110: feat (ai/core): add custom request header support
-- Updated dependencies
- - @ai-sdk/provider@0.0.11
- - @ai-sdk/provider-utils@1.0.0
-
-## 0.0.33
-
-### Patch Changes
-
-- Updated dependencies [02f6a088]
- - @ai-sdk/provider-utils@0.0.16
-
-## 0.0.32
-
-### Patch Changes
-
-- 1b37b8b9: fix (@ai-sdk/openai): only send logprobs settings when logprobs are requested
-
-## 0.0.31
-
-### Patch Changes
-
-- eba071dd: feat (@ai-sdk/azure): add azure openai completion support
-- 1ea890fe: feat (@ai-sdk/azure): add azure openai completion support
-
-## 0.0.30
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider-utils@0.0.15
-
-## 0.0.29
-
-### Patch Changes
-
-- 4728c37f: feat (core): add text embedding model support to provider registry
-- 7910ae84: feat (providers): support custom fetch implementations
-- Updated dependencies [7910ae84]
- - @ai-sdk/provider-utils@0.0.14
-
-## 0.0.28
-
-### Patch Changes
-
-- f9db8fd6: feat (@ai-sdk/openai): add parallelToolCalls setting
-
-## 0.0.27
-
-### Patch Changes
-
-- fc9552ec: fix (@ai-sdk/azure): allow for nullish delta
-
-## 0.0.26
-
-### Patch Changes
-
-- 7530f861: fix (@ai-sdk/openai): add internal dist to bundle
-
-## 0.0.25
-
-### Patch Changes
-
-- 8b1362a7: chore (@ai-sdk/openai): expose models under /internal for reuse in other providers
-
-## 0.0.24
-
-### Patch Changes
-
-- 0e78960c: fix (@ai-sdk/openai): make function name and arguments nullish
-
-## 0.0.23
-
-### Patch Changes
-
-- a68fe74a: fix (@ai-sdk/openai): allow null tool_calls value.
-
-## 0.0.22
-
-### Patch Changes
-
-- Updated dependencies [102ca22f]
- - @ai-sdk/provider@0.0.10
- - @ai-sdk/provider-utils@0.0.13
-
-## 0.0.21
-
-### Patch Changes
-
-- fca7d026: feat (provider/openai): support streaming tool calls that are sent in one chunk
-- Updated dependencies
- - @ai-sdk/provider@0.0.9
- - @ai-sdk/provider-utils@0.0.12
-
-## 0.0.20
-
-### Patch Changes
-
-- a1d08f3e: fix (provider/openai): handle error chunks when streaming
-
-## 0.0.19
-
-### Patch Changes
-
-- beb8b739: fix (provider/openai): return unknown finish reasons as unknown
-
-## 0.0.18
-
-### Patch Changes
-
-- fb42e760: feat (provider/openai): send user message content as text when possible
-
-## 0.0.17
-
-### Patch Changes
-
-- f39c0dd2: feat (provider): implement toolChoice support
-- Updated dependencies [f39c0dd2]
- - @ai-sdk/provider@0.0.8
- - @ai-sdk/provider-utils@0.0.11
-
-## 0.0.16
-
-### Patch Changes
-
-- 2b18fa11: fix (provider/openai): remove object type validation
-
-## 0.0.15
-
-### Patch Changes
-
-- 24683b72: fix (providers): Zod is required dependency
-- Updated dependencies [8e780288]
- - @ai-sdk/provider@0.0.7
- - @ai-sdk/provider-utils@0.0.10
-
-## 0.0.14
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@0.0.6
- - @ai-sdk/provider-utils@0.0.9
-
-## 0.0.13
-
-### Patch Changes
-
-- 4e3c922: fix (provider/openai): introduce compatibility mode in which "stream_options" are not sent
-
-## 0.0.12
-
-### Patch Changes
-
-- 6f48839: feat (provider/openai): add gpt-4o to the list of supported models
-- 1009594: feat (provider/openai): set stream_options/include_usage to true when streaming
-- 0f6bc4e: feat (ai/core): add embed function
-- Updated dependencies [0f6bc4e]
- - @ai-sdk/provider@0.0.5
- - @ai-sdk/provider-utils@0.0.8
-
-## 0.0.11
-
-### Patch Changes
-
-- Updated dependencies [325ca55]
- - @ai-sdk/provider@0.0.4
- - @ai-sdk/provider-utils@0.0.7
-
-## 0.0.10
-
-### Patch Changes
-
-- Updated dependencies [276f22b]
- - @ai-sdk/provider-utils@0.0.6
-
-## 0.0.9
-
-### Patch Changes
-
-- Updated dependencies [41d5736]
- - @ai-sdk/provider@0.0.3
- - @ai-sdk/provider-utils@0.0.5
-
-## 0.0.8
-
-### Patch Changes
-
-- Updated dependencies [56ef84a]
- - @ai-sdk/provider-utils@0.0.4
-
-## 0.0.7
-
-### Patch Changes
-
-- 0833e19: Allow optional content to support Fireworks function calling.
-
-## 0.0.6
-
-### Patch Changes
-
-- d6431ae: ai/core: add logprobs support (thanks @SamStenner for the contribution)
-- 25f3350: ai/core: add support for getting raw response headers.
-- Updated dependencies
- - @ai-sdk/provider@0.0.2
- - @ai-sdk/provider-utils@0.0.3
-
-## 0.0.5
-
-### Patch Changes
-
-- eb150a6: ai/core: remove scaling of setting values (breaking change). If you were using the temperature, frequency penalty, or presence penalty settings, you need to update the providers and adjust the setting values.
-- Updated dependencies [eb150a6]
- - @ai-sdk/provider-utils@0.0.2
- - @ai-sdk/provider@0.0.1
-
-## 0.0.4
-
-### Patch Changes
-
-- c6fc35b: Add custom header and OpenAI project support.
-
-## 0.0.3
-
-### Patch Changes
-
-- ab60b18: Simplified model construction by directly calling provider functions. Add create... functions to create provider instances.
-
-## 0.0.2
-
-### Patch Changes
-
-- 2bff460: Fix build for release.
-
-## 0.0.1
-
-### Patch Changes
-
-- 7b8791d: Support streams with 'chat.completion' objects.
-- 7b8791d: Rename baseUrl to baseURL. Automatically remove trailing slashes.
-- Updated dependencies [7b8791d]
- - @ai-sdk/provider-utils@0.0.1
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/LICENSE b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/LICENSE
deleted file mode 100644
index 6c16c29f4..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/LICENSE
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright 2023 Vercel, Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
\ No newline at end of file
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/README.md b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/README.md
deleted file mode 100644
index 8e027b8c4..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/README.md
+++ /dev/null
@@ -1,44 +0,0 @@
-# AI SDK - OpenAI Provider
-
-The **[OpenAI provider](https://ai-sdk.dev/providers/ai-sdk-providers/openai)** for the [AI SDK](https://ai-sdk.dev/docs)
-contains language model support for the OpenAI chat and completion APIs and embedding model support for the OpenAI embeddings API.
-
-## Setup
-
-The OpenAI provider is available in the `@ai-sdk/openai` module. You can install it with
-
-```bash
-npm i @ai-sdk/openai
-```
-
-## Skill for Coding Agents
-
-If you use coding agents such as Claude Code or Cursor, we highly recommend adding the AI SDK skill to your repository:
-
-```shell
-npx skills add vercel/ai
-```
-
-## Provider Instance
-
-You can import the default provider instance `openai` from `@ai-sdk/openai`:
-
-```ts
-import { openai } from '@ai-sdk/openai';
-```
-
-## Example
-
-```ts
-import { openai } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: openai('gpt-5-mini'),
- prompt: 'Write a vegetarian lasagna recipe for 4 people.',
-});
-```
-
-## Documentation
-
-Please check out the **[OpenAI provider documentation](https://ai-sdk.dev/providers/ai-sdk-providers/openai)** for more information.
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/docs/03-openai.mdx b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/docs/03-openai.mdx
deleted file mode 100644
index bc673dcf1..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/docs/03-openai.mdx
+++ /dev/null
@@ -1,2540 +0,0 @@
----
-title: OpenAI
-description: Learn how to use the OpenAI provider for the AI SDK.
----
-
-# OpenAI Provider
-
-The [OpenAI](https://openai.com/) provider contains language model support for the OpenAI responses, chat, and completion APIs, as well as embedding model support for the OpenAI embeddings API.
-
-## Setup
-
-The OpenAI provider is available in the `@ai-sdk/openai` module. You can install it with
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-## Provider Instance
-
-You can import the default provider instance `openai` from `@ai-sdk/openai`:
-
-```ts
-import { openai } from '@ai-sdk/openai';
-```
-
-If you need a customized setup, you can import `createOpenAI` from `@ai-sdk/openai` and create a provider instance with your settings:
-
-```ts
-import { createOpenAI } from '@ai-sdk/openai';
-
-const openai = createOpenAI({
- // custom settings, e.g.
- headers: {
- 'header-name': 'header-value',
- },
-});
-```
-
-You can use the following optional settings to customize the OpenAI provider instance:
-
-- **baseURL** _string_
-
- Use a different URL prefix for API calls, e.g. to use proxy servers.
- The default prefix is `https://api.openai.com/v1`.
-
-- **apiKey** _string_
-
- API key that is being sent using the `Authorization` header.
- It defaults to the `OPENAI_API_KEY` environment variable.
-
-- **name** _string_
-
- The provider name. You can set this when using OpenAI compatible providers
- to change the model provider property. Defaults to `openai`.
-
-- **organization** _string_
-
- OpenAI Organization.
-
-- **project** _string_
-
- OpenAI project.
-
-- **headers** _Record<string,string>_
-
- Custom headers to include in the requests.
-
-- **fetch** _(input: RequestInfo, init?: RequestInit) => Promise<Response>_
-
- Custom [fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch) implementation.
- Defaults to the global `fetch` function.
- You can use it as a middleware to intercept requests,
- or to provide a custom fetch implementation for e.g. testing.
-
-## Language Models
-
-The OpenAI provider instance is a function that you can invoke to create a language model:
-
-```ts
-const model = openai('gpt-5');
-```
-
-It automatically selects the correct API based on the model id.
-You can also pass additional settings in the second argument:
-
-```ts
-const model = openai('gpt-5', {
- // additional settings
-});
-```
-
-The available options depend on the API that's automatically chosen for the model (see below).
-If you want to explicitly select a specific model API, you can use `.responses`, `.chat`, or `.completion`.
-
-
- Since AI SDK 5, the OpenAI responses API is called by default (unless you
- specify e.g. 'openai.chat')
-
-
-### Example
-
-You can use OpenAI language models to generate text with the `generateText` function:
-
-```ts
-import { openai } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const { text } = await generateText({
- model: openai('gpt-5'),
- prompt: 'Write a vegetarian lasagna recipe for 4 people.',
-});
-```
-
-OpenAI language models can also be used in the `streamText` function
-and support structured data generation with [`Output`](/docs/reference/ai-sdk-core/output)
-(see [AI SDK Core](/docs/ai-sdk-core)).
-
-### Responses Models
-
-You can use the OpenAI responses API with the `openai(modelId)` or `openai.responses(modelId)` factory methods. It is the default API that is used by the OpenAI provider (since AI SDK 5).
-
-```ts
-const model = openai('gpt-5');
-```
-
-Further configuration can be done using OpenAI provider options.
-You can validate the provider options using the `OpenAILanguageModelResponsesOptions` type.
-
-```ts
-import { openai, OpenAILanguageModelResponsesOptions } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai('gpt-5'), // or openai.responses('gpt-5')
- providerOptions: {
- openai: {
- parallelToolCalls: false,
- store: false,
- user: 'user_123',
- // ...
- } satisfies OpenAILanguageModelResponsesOptions,
- },
- // ...
-});
-```
-
-The following provider options are available:
-
-- **parallelToolCalls** _boolean_
- Whether to use parallel tool calls. Defaults to `true`.
-
-- **store** _boolean_
-
- Whether to store the generation. Defaults to `true`.
-
-- **maxToolCalls** _integer_
- The maximum number of total calls to built-in tools that can be processed in a response.
- This maximum number applies across all built-in tool calls, not per individual tool.
- Any further attempts to call a tool by the model will be ignored.
-
-- **metadata** _Record<string, string>_
- Additional metadata to store with the generation.
-
-- **conversation** _string_
- The ID of the OpenAI Conversation to continue.
- You must create a conversation first via the [OpenAI API](https://platform.openai.com/docs/api-reference/conversations/create).
- Cannot be used in conjunction with `previousResponseId`.
- Defaults to `undefined`.
-
-- **previousResponseId** _string_
- The ID of the previous response. You can use it to continue a conversation. Defaults to `undefined`.
-
-- **instructions** _string_
- Instructions for the model.
- They can be used to change the system or developer message when continuing a conversation using the `previousResponseId` option.
- Defaults to `undefined`.
-
-- **logprobs** _boolean | number_
- Return the log probabilities of the tokens. Including logprobs will increase the response size and can slow down response times. However, it can be useful to better understand how the model is behaving. Setting to `true` returns the log probabilities of the tokens that were generated. Setting to a number (1-20) returns the log probabilities of the top n tokens that were generated.
-
-- **user** _string_
- A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. Defaults to `undefined`.
-
-- **reasoningEffort** _'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'_
- Reasoning effort for reasoning models. Defaults to `medium`. If you use `providerOptions` to set the `reasoningEffort` option, this model setting will be ignored.
-
-
- The 'none' type for `reasoningEffort` is only available for OpenAI's GPT-5.1
- models. Also, the 'xhigh' type for `reasoningEffort` is only available for
- OpenAI's GPT-5.1-Codex-Max model. Setting `reasoningEffort` to 'none' or
- 'xhigh' with unsupported models will result in an error.
-
-
-- **reasoningSummary** _'auto' | 'detailed'_
- Controls whether the model returns its reasoning process. Set to `'auto'` for a condensed summary, `'detailed'` for more comprehensive reasoning. Defaults to `undefined` (no reasoning summaries). When enabled, reasoning summaries appear in the stream as events with type `'reasoning'` and in non-streaming responses within the `reasoning` field.
-
-- **strictJsonSchema** _boolean_
- Whether to use strict JSON schema validation. Defaults to `true`.
-
-
- OpenAI structured outputs have several
- [limitations](https://openai.com/index/introducing-structured-outputs-in-the-api),
- in particular around the [supported
- schemas](https://platform.openai.com/docs/guides/structured-outputs/supported-schemas),
- and are therefore opt-in. For example, optional schema properties are not
- supported. You need to change Zod `.nullish()` and `.optional()` to
- `.nullable()`.
-
-
-- **serviceTier** _'auto' | 'flex' | 'priority' | 'default'_
- Service tier for the request. Set to 'flex' for 50% cheaper processing
- at the cost of increased latency (available for o3, o4-mini, and gpt-5 models).
- Set to 'priority' for faster processing with Enterprise access (available for gpt-4, gpt-5, gpt-5-mini, o3, o4-mini; gpt-5-nano is not supported).
-
- Defaults to 'auto'.
-
-- **textVerbosity** _'low' | 'medium' | 'high'_
- Controls the verbosity of the model's response. Lower values result in more concise responses,
- while higher values result in more verbose responses. Defaults to `'medium'`.
-
-- **include** _Array<string>_
- Specifies additional content to include in the response. Supported values:
- `['file_search_call.results']` for including file search results in responses.
- `['message.output_text.logprobs']` for logprobs.
- Defaults to `undefined`.
-
-- **truncation** _string_
- The truncation strategy to use for the model response.
-
- - Auto: If the input to this Response exceeds the model's context window size, the model will truncate the response to fit the context window by dropping items from the beginning of the conversation.
- - disabled (default): If the input size will exceed the context window size for a model, the request will fail with a 400 error.
-
-- **promptCacheKey** _string_
- A cache key for manual prompt caching control. Used by OpenAI to cache responses for similar requests to optimize your cache hit rates.
-
-- **promptCacheRetention** _'in_memory' | '24h'_
- The retention policy for the prompt cache. Set to `'24h'` to enable extended prompt caching, which keeps cached prefixes active for up to 24 hours. Defaults to `'in_memory'` for standard prompt caching. Note: `'24h'` is currently only available for the 5.1 series of models.
-
-- **safetyIdentifier** _string_
- A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely identifies each user.
-
-- **systemMessageMode** _'system' | 'developer' | 'remove'_
- Controls the role of the system message when making requests. By default (when omitted), for models that support reasoning the `system` message is automatically converted to a `developer` message. Setting `systemMessageMode` to `system` passes the system message as a system-level instruction; `developer` passes it as a developer message; `remove` omits the system message from the request.
-
-- **forceReasoning** _boolean_
- Force treating this model as a reasoning model. This is useful for "stealth" reasoning models (e.g. via a custom baseURL) where the model ID is not recognized by the SDK's allowlist. When enabled, the SDK applies reasoning-model parameter compatibility rules and defaults `systemMessageMode` to `developer` unless overridden.
-
-The OpenAI responses provider also returns provider-specific metadata:
-
-For Responses models, you can type this metadata using `OpenaiResponsesProviderMetadata`:
-
-```ts
-import { openai, type OpenaiResponsesProviderMetadata } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai('gpt-5'),
-});
-
-const providerMetadata = result.providerMetadata as
- | OpenaiResponsesProviderMetadata
- | undefined;
-
-const { responseId, logprobs, serviceTier } = providerMetadata?.openai ?? {};
-
-// responseId can be used to continue a conversation (previousResponseId).
-console.log(responseId);
-```
-
-The following OpenAI-specific metadata may be returned:
-
-- **responseId** _string | null | undefined_
- The ID of the response. Can be used to continue a conversation.
-- **logprobs** _(optional)_
- Log probabilities of output tokens (when enabled).
-- **serviceTier** _(optional)_
- Service tier information returned by the API.
-
-#### Reasoning Output
-
-For reasoning models like `gpt-5`, you can enable reasoning summaries to see the model's thought process. Different models support different summarizers—for example, `o4-mini` supports detailed summaries. Set `reasoningSummary: "auto"` to automatically receive the richest level available.
-
-```ts highlight="8-9,16"
-import {
- openai,
- type OpenAILanguageModelResponsesOptions,
-} from '@ai-sdk/openai';
-import { streamText } from 'ai';
-
-const result = streamText({
- model: openai('gpt-5'),
- prompt: 'Tell me about the Mission burrito debate in San Francisco.',
- providerOptions: {
- openai: {
- reasoningSummary: 'detailed', // 'auto' for condensed or 'detailed' for comprehensive
- } satisfies OpenAILanguageModelResponsesOptions,
- },
-});
-
-for await (const part of result.fullStream) {
- if (part.type === 'reasoning') {
- console.log(`Reasoning: ${part.textDelta}`);
- } else if (part.type === 'text-delta') {
- process.stdout.write(part.textDelta);
- }
-}
-```
-
-For non-streaming calls with `generateText`, the reasoning summaries are available in the `reasoning` field of the response:
-
-```ts highlight="8-9,13"
-import {
- openai,
- type OpenAILanguageModelResponsesOptions,
-} from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai('gpt-5'),
- prompt: 'Tell me about the Mission burrito debate in San Francisco.',
- providerOptions: {
- openai: {
- reasoningSummary: 'auto',
- } satisfies OpenAILanguageModelResponsesOptions,
- },
-});
-console.log('Reasoning:', result.reasoning);
-```
-
-Learn more about reasoning summaries in the [OpenAI documentation](https://platform.openai.com/docs/guides/reasoning?api-mode=responses#reasoning-summaries).
-
-#### WebSocket Transport
-
-OpenAI's [WebSocket API](https://developers.openai.com/api/docs/guides/websocket-mode) keeps a persistent connection open, which can significantly
-reduce Time-to-First-Byte (TTFB) in agentic workflows with many tool calls.
-After the initial connection, subsequent requests skip TCP/TLS/HTTP negotiation entirely.
-
-The [`ai-sdk-openai-websocket-fetch`](https://www.npmjs.com/package/ai-sdk-openai-websocket-fetch)
-package provides a drop-in `fetch` replacement that routes streaming requests
-through a persistent WebSocket connection.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Pass the WebSocket fetch to `createOpenAI` via the `fetch` option:
-
-```ts highlight="2,6-7,15"
-import { createOpenAI } from '@ai-sdk/openai';
-import { createWebSocketFetch } from 'ai-sdk-openai-websocket-fetch';
-import { streamText } from 'ai';
-
-// Create a WebSocket-backed fetch instance
-const wsFetch = createWebSocketFetch();
-const openai = createOpenAI({ fetch: wsFetch });
-
-const result = streamText({
- model: openai('gpt-4.1-mini'),
- prompt: 'Hello!',
- tools: {
- // ...
- },
- onFinish: () => wsFetch.close(), // close the WebSocket when done
-});
-```
-
-The first request will be slower because it must establish the WebSocket connection
-(DNS + TCP + TLS + WebSocket upgrade). After that, subsequent steps in a
-multi-step tool-calling loop reuse the open connection, resulting in lower TTFB
-per step.
-
-
- The WebSocket transport only routes streaming requests to the OpenAI Responses
- API (`POST /responses` with `stream: true`) through the WebSocket. All other
- requests (non-streaming, embeddings, etc.) fall through to the standard
- `fetch` implementation.
-
-
-You can see a live side-by-side comparison of HTTP vs WebSocket streaming performance
-in the [demo app](https://github.com/vercel-labs/ai-sdk-openai-websocket).
-
-#### Verbosity Control
-
-You can control the length and detail of model responses using the `textVerbosity` parameter:
-
-```ts
-import {
- openai,
- type OpenAILanguageModelResponsesOptions,
-} from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai('gpt-5-mini'),
- prompt: 'Write a poem about a boy and his first pet dog.',
- providerOptions: {
- openai: {
- textVerbosity: 'low', // 'low' for concise, 'medium' (default), or 'high' for verbose
- } satisfies OpenAILanguageModelResponsesOptions,
- },
-});
-```
-
-The `textVerbosity` parameter scales output length without changing the underlying prompt:
-
-- `'low'`: Produces terse, minimal responses
-- `'medium'`: Balanced detail (default)
-- `'high'`: Verbose responses with comprehensive detail
-
-#### Web Search Tool
-
-The OpenAI responses API supports web search through the `openai.tools.webSearch` tool.
-
-```ts
-const result = await generateText({
- model: openai('gpt-5'),
- prompt: 'What happened in San Francisco last week?',
- tools: {
- web_search: openai.tools.webSearch({
- // optional configuration:
- externalWebAccess: true,
- searchContextSize: 'high',
- userLocation: {
- type: 'approximate',
- city: 'San Francisco',
- region: 'California',
- },
- filters: {
- allowedDomains: ['sfchronicle.com', 'sfgate.com'],
- },
- }),
- },
- // Force web search tool (optional):
- toolChoice: { type: 'tool', toolName: 'web_search' },
-});
-
-// URL sources directly from `results`
-const sources = result.sources;
-
-// Or access sources from tool results
-for (const toolResult of result.toolResults) {
- if (toolResult.toolName === 'web_search') {
- console.log('Query:', toolResult.output.action.query);
- console.log('Sources:', toolResult.output.sources);
- // `sources` is an array of object: { type: 'url', url: string }
- }
-}
-```
-
-The web search tool supports the following configuration options:
-
-- **externalWebAccess** _boolean_ - Whether to use external web access for fetching live content. Defaults to `true`.
-- **searchContextSize** _'low' | 'medium' | 'high'_ - Controls the amount of context used for the search. Higher values provide more comprehensive results but may have higher latency and cost.
-- **userLocation** - Optional location information to provide geographically relevant results. Includes `type` (always `'approximate'`), `country`, `city`, `region`, and `timezone`.
-- **filters** - Optional filter configuration to restrict search results.
- - **allowedDomains** _string[]_ - Array of allowed domains for the search. Subdomains of the provided domains are automatically included.
-
-For detailed information on configuration options see the [OpenAI Web Search Tool documentation](https://platform.openai.com/docs/guides/tools-web-search?api-mode=responses).
-
-#### File Search Tool
-
-The OpenAI responses API supports file search through the `openai.tools.fileSearch` tool.
-
-You can force the use of the file search tool by setting the `toolChoice` parameter to `{ type: 'tool', toolName: 'file_search' }`.
-
-```ts
-const result = await generateText({
- model: openai('gpt-5'),
- prompt: 'What does the document say about user authentication?',
- tools: {
- file_search: openai.tools.fileSearch({
- vectorStoreIds: ['vs_123'],
- // configuration below is optional:
- maxNumResults: 5,
- filters: {
- key: 'author',
- type: 'eq',
- value: 'Jane Smith',
- },
- ranking: {
- ranker: 'auto',
- scoreThreshold: 0.5,
- },
- }),
- },
- providerOptions: {
- openai: {
- // optional: include results
- include: ['file_search_call.results'],
- } satisfies OpenAILanguageModelResponsesOptions,
- },
-});
-```
-
-The file search tool supports filtering with both comparison and compound filters:
-
-**Comparison filters** - Filter by a single attribute:
-
-- `eq` - Equal to
-- `ne` - Not equal to
-- `gt` - Greater than
-- `gte` - Greater than or equal to
-- `lt` - Less than
-- `lte` - Less than or equal to
-- `in` - Value is in array
-- `nin` - Value is not in array
-
-```ts
-// Single comparison filter
-filters: { key: 'year', type: 'gte', value: 2023 }
-
-// Filter with array values
-filters: { key: 'status', type: 'in', value: ['published', 'reviewed'] }
-```
-
-**Compound filters** - Combine multiple filters with `and` or `or`:
-
-```ts
-// Compound filter with AND
-filters: {
- type: 'and',
- filters: [
- { key: 'author', type: 'eq', value: 'Jane Smith' },
- { key: 'year', type: 'gte', value: 2023 },
- ],
-}
-
-// Compound filter with OR
-filters: {
- type: 'or',
- filters: [
- { key: 'department', type: 'eq', value: 'Engineering' },
- { key: 'department', type: 'eq', value: 'Research' },
- ],
-}
-```
-
-#### Image Generation Tool
-
-OpenAI's Responses API supports multi-modal image generation as a provider-defined tool.
-Availability is restricted to specific models (for example, `gpt-5` variants).
-
-You can use the image tool with either `generateText` or `streamText`:
-
-```ts
-import { openai } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai('gpt-5'),
- prompt:
- 'Generate an image of an echidna swimming across the Mozambique channel.',
- tools: {
- image_generation: openai.tools.imageGeneration({ outputFormat: 'webp' }),
- },
-});
-
-for (const toolResult of result.staticToolResults) {
- if (toolResult.toolName === 'image_generation') {
- const base64Image = toolResult.output.result;
- }
-}
-```
-
-```ts
-import { openai } from '@ai-sdk/openai';
-import { streamText } from 'ai';
-
-const result = streamText({
- model: openai('gpt-5'),
- prompt:
- 'Generate an image of an echidna swimming across the Mozambique channel.',
- tools: {
- image_generation: openai.tools.imageGeneration({
- outputFormat: 'webp',
- quality: 'low',
- }),
- },
-});
-
-for await (const part of result.fullStream) {
- if (part.type == 'tool-result' && !part.dynamic) {
- const base64Image = part.output.result;
- }
-}
-```
-
-
- When you set `store: false`, then previously generated images will not be
- accessible by the model. We recommend using the image generation tool without
- setting `store: false`.
-
-
-For complete details on model availability, image quality controls, supported sizes, and tool-specific parameters,
-refer to the OpenAI documentation:
-
-- Image generation overview and models: [OpenAI Image Generation](https://platform.openai.com/docs/guides/image-generation)
-- Image generation tool parameters (background, size, quality, format, etc.): [Image Generation Tool Options](https://platform.openai.com/docs/guides/tools-image-generation#tool-options)
-
-#### Code Interpreter Tool
-
-The OpenAI responses API supports the code interpreter tool through the `openai.tools.codeInterpreter` tool.
-This allows models to write and execute Python code.
-
-```ts
-import { openai } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai('gpt-5'),
- prompt: 'Write and run Python code to calculate the factorial of 10',
- tools: {
- code_interpreter: openai.tools.codeInterpreter({
- // optional configuration:
- container: {
- fileIds: ['file-123', 'file-456'], // optional file IDs to make available
- },
- }),
- },
-});
-```
-
-The code interpreter tool can be configured with:
-
-- **container**: Either a container ID string or an object with `fileIds` to specify uploaded files that should be available to the code interpreter
-
-
- When working with files generated by the Code Interpreter, reference
- information can be obtained from both [annotations in Text
- Parts](#typed-providermetadata-in-text-parts) and [`providerMetadata` in
- Source Document Parts](#typed-providermetadata-in-source-document-parts).
-
-
-#### MCP Tool
-
-The OpenAI responses API supports connecting to [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) servers through the `openai.tools.mcp` tool. This allows models to call tools exposed by remote MCP servers or service connectors.
-
-```ts
-import { openai } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai('gpt-5'),
- prompt: 'Search the web for the latest news about AI developments',
- tools: {
- mcp: openai.tools.mcp({
- serverLabel: 'web-search',
- serverUrl: 'https://mcp.exa.ai/mcp',
- serverDescription: 'A web-search API for AI agents',
- }),
- },
-});
-```
-
-The MCP tool can be configured with:
-
-- **serverLabel** _string_ (required)
-
- A label to identify the MCP server. This label is used in tool calls to distinguish between multiple MCP servers.
-
-- **serverUrl** _string_ (required if `connectorId` is not provided)
-
- The URL for the MCP server. Either `serverUrl` or `connectorId` must be provided.
-
-- **connectorId** _string_ (required if `serverUrl` is not provided)
-
- Identifier for a service connector. Either `serverUrl` or `connectorId` must be provided.
-
-- **serverDescription** _string_ (optional)
-
- Optional description of the MCP server that helps the model understand its purpose.
-
-- **allowedTools** _string[] | object_ (optional)
-
- Controls which tools from the MCP server are available. Can be:
-
- - An array of tool names: `['tool1', 'tool2']`
- - An object with filters:
- ```ts
- {
- readOnly: true, // Only allow read-only tools
- toolNames: ['tool1', 'tool2'] // Specific tool names
- }
- ```
-
-- **authorization** _string_ (optional)
-
- OAuth access token for authenticating with the MCP server or connector.
-
-- **headers** _Record<string, string>_ (optional)
-
- Optional HTTP headers to include in requests to the MCP server.
-
-- **requireApproval** _'always' | 'never' | object_ (optional)
-
- Controls which MCP tool calls require user approval before execution. Can be:
-
- - `'always'`: All MCP tool calls require approval
- - `'never'`: No MCP tool calls require approval (default)
- - An object with filters:
- ```ts
- {
- never: {
- toolNames: ['safe_tool', 'another_safe_tool']; // Skip approval for these tools
- }
- }
- ```
-
- When approval is required, the model will return a `tool-approval-request` content part that you can use to prompt the user for approval. See [Human in the Loop](/cookbook/next/human-in-the-loop) for more details on implementing approval workflows.
-
-
- When `requireApproval` is not set, tool calls are approved by default. Be sure
- to connect to only trusted MCP servers, who you trust to share your data with.
-
-
-
- The OpenAI MCP tool is different from the general MCP client approach
- documented in [MCP Tools](/docs/ai-sdk-core/mcp-tools). The OpenAI MCP tool is
- a built-in provider-defined tool that allows OpenAI models to directly connect
- to MCP servers, while the general MCP client requires you to convert MCP tools
- to AI SDK tools first.
-
-
-#### Local Shell Tool
-
-The OpenAI responses API support the local shell tool for Codex models through the `openai.tools.localShell` tool.
-Local shell is a tool that allows agents to run shell commands locally on a machine you or the user provides.
-
-```ts
-import { openai } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai.responses('gpt-5-codex'),
- tools: {
- local_shell: openai.tools.localShell({
- execute: async ({ action }) => {
- // ... your implementation, e.g. sandbox access ...
- return { output: stdout };
- },
- }),
- },
- prompt: 'List the files in my home directory.',
- stopWhen: stepCountIs(2),
-});
-```
-
-#### Shell Tool
-
-The OpenAI Responses API supports the shell tool through the `openai.tools.shell` tool.
-The shell tool allows running bash commands and interacting with a command line.
-The model proposes shell commands; your integration executes them and returns the outputs.
-
-
- Running arbitrary shell commands can be dangerous. Always sandbox execution or
- add strict allow-/deny-lists before forwarding a command to the system shell.
-
-
-The shell tool supports three environment modes that control where commands are executed:
-
-##### Local Execution (default)
-
-When no `environment` is specified (or `type: 'local'` is used), commands are executed locally via your `execute` callback:
-
-```ts
-import { openai } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai('gpt-5.2'),
- tools: {
- shell: openai.tools.shell({
- execute: async ({ action }) => {
- // ... your implementation, e.g. sandbox access ...
- return { output: results };
- },
- }),
- },
- prompt: 'List the files in the current directory and show disk usage.',
-});
-```
-
-##### Hosted Container (auto)
-
-Set `environment.type` to `'containerAuto'` to run commands in an OpenAI-hosted container. No `execute` callback is needed — OpenAI handles execution server-side:
-
-```ts
-const result = await generateText({
- model: openai('gpt-5.2'),
- tools: {
- shell: openai.tools.shell({
- environment: {
- type: 'containerAuto',
- // optional configuration:
- memoryLimit: '4g',
- fileIds: ['file-abc123'],
- networkPolicy: {
- type: 'allowlist',
- allowedDomains: ['example.com'],
- },
- },
- }),
- },
- prompt: 'Install numpy and compute the eigenvalues of a 3x3 matrix.',
-});
-```
-
-The `containerAuto` environment supports:
-
-- **fileIds** _string[]_ - File IDs to make available in the container
-- **memoryLimit** _'1g' | '4g' | '16g' | '64g'_ - Memory limit for the container
-- **networkPolicy** - Network access policy:
- - `{ type: 'disabled' }` — no network access
- - `{ type: 'allowlist', allowedDomains: string[], domainSecrets?: Array<{ domain, name, value }> }` — allow specific domains with optional secrets
-
-##### Existing Container Reference
-
-Set `environment.type` to `'containerReference'` to use an existing container by ID:
-
-```ts
-const result = await generateText({
- model: openai('gpt-5.2'),
- tools: {
- shell: openai.tools.shell({
- environment: {
- type: 'containerReference',
- containerId: 'cntr_abc123',
- },
- }),
- },
- prompt: 'Check the status of running processes.',
-});
-```
-
-##### Execute Callback
-
-For local execution (default or `type: 'local'`), your execute function must return an output array with results for each command:
-
-- **stdout** _string_ - Standard output from the command
-- **stderr** _string_ - Standard error from the command
-- **outcome** - Either `{ type: 'timeout' }` or `{ type: 'exit', exitCode: number }`
-
-##### Skills
-
-[Skills](https://platform.openai.com/docs/guides/tools-skills) are versioned bundles of files with a `SKILL.md` manifest that extend the shell tool's capabilities. They can be attached to both `containerAuto` and `local` environments.
-
-**Container skills** support two formats — by reference (for skills uploaded to OpenAI) or inline (as a base64-encoded zip):
-
-```ts
-const result = await generateText({
- model: openai('gpt-5.2'),
- tools: {
- shell: openai.tools.shell({
- environment: {
- type: 'containerAuto',
- skills: [
- // By reference:
- { type: 'skillReference', skillId: 'skill_abc123' },
- // Or inline:
- {
- type: 'inline',
- name: 'my-skill',
- description: 'What this skill does',
- source: {
- type: 'base64',
- mediaType: 'application/zip',
- data: readFileSync('./my-skill.zip').toString('base64'),
- },
- },
- ],
- },
- }),
- },
- prompt: 'Use the skill to solve this problem.',
-});
-```
-
-**Local skills** point to a directory on disk containing a `SKILL.md` file:
-
-```ts
-const result = await generateText({
- model: openai('gpt-5.2'),
- tools: {
- shell: openai.tools.shell({
- execute: async ({ action }) => {
- // ... your local execution implementation ...
- return { output: results };
- },
- environment: {
- type: 'local',
- skills: [
- {
- name: 'my-skill',
- description: 'What this skill does',
- path: resolve('path/to/skill-directory'),
- },
- ],
- },
- }),
- },
- prompt: 'Use the skill to solve this problem.',
- stopWhen: stepCountIs(5),
-});
-```
-
-For more details on creating skills, see the [OpenAI Skills documentation](https://platform.openai.com/docs/guides/tools-skills).
-
-#### Apply Patch Tool
-
-The OpenAI Responses API supports the apply patch tool for GPT-5.1 models through the `openai.tools.applyPatch` tool.
-The apply patch tool lets the model create, update, and delete files in your codebase using structured diffs.
-Instead of just suggesting edits, the model emits patch operations that your application applies and reports back on,
-enabling iterative, multi-step code editing workflows.
-
-```ts
-import { openai } from '@ai-sdk/openai';
-import { generateText, stepCountIs } from 'ai';
-
-const result = await generateText({
- model: openai('gpt-5.1'),
- tools: {
- apply_patch: openai.tools.applyPatch({
- execute: async ({ callId, operation }) => {
- // ... your implementation for applying the diffs.
- },
- }),
- },
- prompt: 'Create a python file that calculates the factorial of a number',
- stopWhen: stepCountIs(5),
-});
-```
-
-Your execute function must return:
-
-- **status** _'completed' | 'failed'_ - Whether the patch was applied successfully
-- **output** _string_ (optional) - Human-readable log text (e.g., results or error messages)
-
-#### Tool Search
-
-Tool search allows the model to dynamically search for and load tools into context as needed,
-rather than loading all tool definitions up front. This can reduce token usage, cost, and latency
-when you have many tools. Mark the tools you want to make searchable with `deferLoading: true`
-in their `providerOptions`.
-
-There are two execution modes:
-
-- **Server-executed (hosted):** OpenAI searches across the deferred tools declared in the request and returns the loaded subset in the same response. No extra round-trip is needed.
-- **Client-executed:** The model emits a `tool_search_call`, your application performs the lookup, and you return the matching tools via the `execute` callback.
-
-##### Server-Executed (Hosted) Tool Search
-
-Use hosted tool search when the candidate tools are already known at request time.
-Add `openai.tools.toolSearch()` with no arguments and mark your tools with `deferLoading: true`:
-
-```ts
-import { openai } from '@ai-sdk/openai';
-import { generateText, tool, stepCountIs } from 'ai';
-import { z } from 'zod';
-
-const result = await generateText({
- model: openai.responses('gpt-5.4'),
- prompt: 'What is the weather in San Francisco?',
- stopWhen: stepCountIs(10),
- tools: {
- toolSearch: openai.tools.toolSearch(),
-
- get_weather: tool({
- description: 'Get the current weather at a specific location',
- inputSchema: z.object({
- location: z.string(),
- unit: z.enum(['celsius', 'fahrenheit']),
- }),
- execute: async ({ location, unit }) => ({
- location,
- temperature: unit === 'celsius' ? 18 : 64,
- }),
- providerOptions: {
- openai: { deferLoading: true },
- },
- }),
-
- search_files: tool({
- description: 'Search through files in the workspace',
- inputSchema: z.object({ query: z.string() }),
- execute: async ({ query }) => ({
- results: [`Found 3 files matching "${query}"`],
- }),
- providerOptions: {
- openai: { deferLoading: true },
- },
- }),
- },
-});
-```
-
-In hosted mode, the model internally searches the deferred tools, loads the relevant ones, and
-proceeds to call them — all within a single response. The `tool_search_call` and
-`tool_search_output` items appear in the response with `execution: 'server'` and `call_id: null`.
-
-##### Client-Executed Tool Search
-
-Use client-executed tool search when tool discovery depends on runtime state — for example,
-tools that vary per tenant, project, or external system. Pass `execution: 'client'` along with
-a `description`, `parameters` schema, and an `execute` callback:
-
-```ts
-import { openai } from '@ai-sdk/openai';
-import { generateText, tool, stepCountIs } from 'ai';
-import { z } from 'zod';
-
-const result = await generateText({
- model: openai.responses('gpt-5.4'),
- prompt: 'What is the weather in San Francisco?',
- stopWhen: stepCountIs(10),
- tools: {
- toolSearch: openai.tools.toolSearch({
- execution: 'client',
- description: 'Search for available tools based on what the user needs.',
- parameters: {
- type: 'object',
- properties: {
- goal: {
- type: 'string',
- description: 'What the user is trying to accomplish',
- },
- },
- required: ['goal'],
- additionalProperties: false,
- },
- execute: async ({ arguments: args }) => {
- // Your custom tool discovery logic here.
- // Return the tools that match the search goal.
- return {
- tools: [
- {
- type: 'function',
- name: 'get_weather',
- description: 'Get the current weather at a specific location',
- deferLoading: true,
- parameters: {
- type: 'object',
- properties: {
- location: { type: 'string' },
- },
- required: ['location'],
- additionalProperties: false,
- },
- },
- ],
- };
- },
- }),
-
- get_weather: tool({
- description: 'Get the current weather at a specific location',
- inputSchema: z.object({ location: z.string() }),
- execute: async ({ location }) => ({
- location,
- temperature: 64,
- condition: 'Partly cloudy',
- }),
- providerOptions: {
- openai: { deferLoading: true },
- },
- }),
- },
-});
-```
-
-In client mode, the flow spans two steps:
-
-1. **Step 1:** The model emits a `tool_search_call` with `execution: 'client'` and a non-null `call_id`. The SDK calls your `execute` callback with the search arguments. Your callback returns the discovered tools.
-2. **Step 2:** The SDK sends the `tool_search_output` (with the matching `call_id`) back to the model. The model can now call the loaded tools as normal function calls.
-
-For more details, see the [OpenAI Tool Search documentation](https://platform.openai.com/docs/guides/tools-tool-search).
-
-#### Custom Tool
-
-The OpenAI Responses API supports
-[custom tools](https://developers.openai.com/api/docs/guides/function-calling/#custom-tools)
-through the `openai.tools.customTool` tool.
-Custom tools return a raw string instead of JSON, optionally constrained to a grammar
-(regex or Lark syntax). This makes them useful for generating structured text like
-SQL queries, code snippets, or any output that must match a specific pattern.
-
-```ts
-import { openai } from '@ai-sdk/openai';
-import { generateText, stepCountIs } from 'ai';
-
-const result = await generateText({
- model: openai.responses('gpt-5.2-codex'),
- tools: {
- write_sql: openai.tools.customTool({
- name: 'write_sql',
- description: 'Write a SQL SELECT query to answer the user question.',
- format: {
- type: 'grammar',
- syntax: 'regex',
- definition: 'SELECT .+',
- },
- execute: async input => {
- // input is a raw string matching the grammar, e.g. "SELECT * FROM users WHERE age > 25"
- const rows = await db.query(input);
- return JSON.stringify(rows);
- },
- }),
- },
- toolChoice: 'required',
- prompt: 'Write a SQL query to get all users older than 25.',
- stopWhen: stepCountIs(3),
-});
-```
-
-Custom tools also work with `streamText`:
-
-```ts
-import { openai } from '@ai-sdk/openai';
-import { streamText } from 'ai';
-
-const result = streamText({
- model: openai.responses('gpt-5.2-codex'),
- tools: {
- write_sql: openai.tools.customTool({
- name: 'write_sql',
- description: 'Write a SQL SELECT query to answer the user question.',
- format: {
- type: 'grammar',
- syntax: 'regex',
- definition: 'SELECT .+',
- },
- }),
- },
- toolChoice: 'required',
- prompt: 'Write a SQL query to get all users older than 25.',
-});
-
-for await (const chunk of result.fullStream) {
- if (chunk.type === 'tool-call') {
- console.log(`Tool: ${chunk.toolName}`);
- console.log(`Input: ${chunk.input}`);
- }
-}
-```
-
-The custom tool can be configured with:
-
-- **name** _string_ (required) - The name of the custom tool. Used to identify the tool in tool calls.
-- **description** _string_ (optional) - A description of what the tool does, to help the model understand when to use it.
-- **format** _object_ (optional) - The output format constraint. Omit for unconstrained text output.
- - **type** _'grammar' | 'text'_ - The format type. Use `'grammar'` for constrained output or `'text'` for explicit unconstrained text.
- - **syntax** _'regex' | 'lark'_ - (grammar only) The grammar syntax. Use `'regex'` for regular expression patterns or `'lark'` for [Lark parser grammar](https://lark-parser.readthedocs.io/).
- - **definition** _string_ - (grammar only) The grammar definition string (a regex pattern or Lark grammar).
-- **execute** _function_ (optional) - An async function that receives the raw string input and returns a string result. Enables multi-turn tool calling.
-
-#### Image Inputs
-
-The OpenAI Responses API supports Image inputs for appropriate models.
-You can pass Image files as part of the message content using the 'image' type:
-
-```ts
-const result = await generateText({
- model: openai('gpt-5'),
- messages: [
- {
- role: 'user',
- content: [
- {
- type: 'text',
- text: 'Please describe the image.',
- },
- {
- type: 'image',
- image: readFileSync('./data/image.png'),
- },
- ],
- },
- ],
-});
-```
-
-The model will have access to the image and will respond to questions about it.
-The image should be passed using the `image` field.
-
-You can also pass a file-id from the OpenAI Files API.
-
-```ts
-{
- type: 'image',
- image: 'file-8EFBcWHsQxZV7YGezBC1fq'
-}
-```
-
-You can also pass the URL of an image.
-
-```ts
-{
- type: 'image',
- image: 'https://sample.edu/image.png',
-}
-```
-
-#### PDF Inputs
-
-The OpenAI Responses API supports reading PDF files.
-You can pass PDF files as part of the message content using the `file` type:
-
-```ts
-const result = await generateText({
- model: openai('gpt-5'),
- messages: [
- {
- role: 'user',
- content: [
- {
- type: 'text',
- text: 'What is an embedding model?',
- },
- {
- type: 'file',
- data: readFileSync('./data/ai.pdf'),
- mediaType: 'application/pdf',
- filename: 'ai.pdf', // optional
- },
- ],
- },
- ],
-});
-```
-
-You can also pass a file-id from the OpenAI Files API.
-
-```ts
-{
- type: 'file',
- data: 'file-8EFBcWHsQxZV7YGezBC1fq',
- mediaType: 'application/pdf',
-}
-```
-
-You can also pass the URL of a pdf.
-
-```ts
-{
- type: 'file',
- data: 'https://sample.edu/example.pdf',
- mediaType: 'application/pdf',
- filename: 'ai.pdf', // optional
-}
-```
-
-The model will have access to the contents of the PDF file and
-respond to questions about it.
-The PDF file should be passed using the `data` field,
-and the `mediaType` should be set to `'application/pdf'`.
-
-#### Structured Outputs
-
-The OpenAI Responses API supports structured outputs. You can use `generateText` or `streamText` with [`Output`](/docs/reference/ai-sdk-core/output) to enforce structured outputs.
-
-```ts
-const result = await generateText({
- model: openai('gpt-4.1'),
- output: Output.object({
- schema: z.object({
- recipe: z.object({
- name: z.string(),
- ingredients: z.array(
- z.object({
- name: z.string(),
- amount: z.string(),
- }),
- ),
- steps: z.array(z.string()),
- }),
- }),
- }),
- prompt: 'Generate a lasagna recipe.',
-});
-```
-
-#### Typed providerMetadata in Text Parts
-
-When using the OpenAI Responses API, the SDK attaches OpenAI-specific metadata to output parts via `providerMetadata`.
-
-This metadata can be used on the client side for tasks such as rendering citations or downloading files generated by the Code Interpreter.
-To enable type-safe handling of this metadata, the AI SDK exports dedicated TypeScript types.
-
-For text parts, when `part.type === 'text'`, the `providerMetadata` is provided in the form of `OpenaiResponsesTextProviderMetadata`.
-
-This metadata includes the following fields:
-
-- `itemId`
- The ID of the output item in the Responses API.
-- `annotations` (optional)
- An array of annotation objects generated by the model.
- If no annotations are present, this property itself may be omitted (`undefined`).
-
- Each element in `annotations` is a discriminated union with a required `type` field. Supported types include, for example:
-
- - `url_citation`
- - `file_citation`
- - `container_file_citation`
- - `file_path`
-
- These annotations directly correspond to the annotation objects defined by the Responses API and can be used for inline reference rendering or output analysis.
- For details, see the official OpenAI documentation:
- [Responses API – output text annotations](https://platform.openai.com/docs/api-reference/responses/object?lang=javascript#responses-object-output-output_message-content-output_text-annotations).
-
-```ts
-import {
- openai,
- type OpenaiResponsesTextProviderMetadata,
-} from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai('gpt-4.1-mini'),
- prompt:
- 'Create a program that generates five random numbers between 1 and 100 with two decimal places, and show me the execution results. Also save the result to a file.',
- tools: {
- code_interpreter: openai.tools.codeInterpreter(),
- web_search: openai.tools.webSearch(),
- file_search: openai.tools.fileSearch({ vectorStoreIds: ['vs_1234'] }), // requires a configured vector store
- },
-});
-
-for (const part of result.content) {
- if (part.type === 'text') {
- const providerMetadata = part.providerMetadata as
- | OpenaiResponsesTextProviderMetadata
- | undefined;
- if (!providerMetadata) continue;
- const { itemId: _itemId, annotations } = providerMetadata.openai;
-
- if (!annotations) continue;
- for (const annotation of annotations) {
- switch (annotation.type) {
- case 'url_citation':
- // url_citation is returned from web_search and provides:
- // properties: type, url, title, start_index and end_index
- break;
- case 'file_citation':
- // file_citation is returned from file_search and provides:
- // properties: type, file_id, filename and index
- break;
- case 'container_file_citation':
- // container_file_citation is returned from code_interpreter and provides:
- // properties: type, container_id, file_id, filename, start_index and end_index
- break;
- case 'file_path':
- // file_path provides:
- // properties: type, file_id and index
- break;
- default: {
- const _exhaustiveCheck: never = annotation;
- throw new Error(
- `Unhandled annotation: ${JSON.stringify(_exhaustiveCheck)}`,
- );
- }
- }
- }
- }
-}
-```
-
-
- When implementing file downloads for files generated by the Code Interpreter,
- the `container_id` and `file_id` available in `providerMetadata` can be used
- to retrieve the file content. For details, see the [Retrieve container file
- content](https://platform.openai.com/docs/api-reference/container-files/retrieveContainerFileContent)
- API.
-
-
-#### Typed providerMetadata in Reasoning Parts
-
-When using the OpenAI Responses API, reasoning output parts can include provider metadata.
-To handle this metadata in a type-safe way, use `OpenaiResponsesReasoningProviderMetadata`.
-
-For reasoning parts, when `part.type === 'reasoning'`, the `providerMetadata` is provided in the form of `OpenaiResponsesReasoningProviderMetadata`.
-
-This metadata includes the following fields:
-
-- `itemId`
- The ID of the reasoning item in the Responses API.
-- `reasoningEncryptedContent` (optional)
- Encrypted reasoning content (only returned when requested via `include: ['reasoning.encrypted_content']`).
-
-```ts
-import {
- openai,
- type OpenaiResponsesReasoningProviderMetadata,
- type OpenAILanguageModelResponsesOptions,
-} from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai('gpt-5'),
- prompt: 'How many "r"s are in the word "strawberry"?',
- providerOptions: {
- openai: {
- store: false,
- include: ['reasoning.encrypted_content'],
- } satisfies OpenAILanguageModelResponsesOptions,
- },
-});
-
-for (const part of result.content) {
- if (part.type === 'reasoning') {
- const providerMetadata = part.providerMetadata as
- | OpenaiResponsesReasoningProviderMetadata
- | undefined;
-
- const { itemId, reasoningEncryptedContent } =
- providerMetadata?.openai ?? {};
- console.log(itemId, reasoningEncryptedContent);
- }
-}
-```
-
-#### Typed providerMetadata in Source Document Parts
-
-For source document parts, when `part.type === 'source'` and `sourceType === 'document'`, the `providerMetadata` is provided as `OpenaiResponsesSourceDocumentProviderMetadata`.
-
-This metadata is also a discriminated union with a required `type` field. Supported types include:
-
-- `file_citation`
-- `container_file_citation`
-- `file_path`
-
-Each type includes the identifiers required to work with the referenced resource, such as `fileId` and `containerId`.
-
-```ts
-import {
- openai,
- type OpenaiResponsesSourceDocumentProviderMetadata,
-} from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai('gpt-4.1-mini'),
- prompt:
- 'Create a program that generates five random numbers between 1 and 100 with two decimal places, and show me the execution results. Also save the result to a file.',
- tools: {
- code_interpreter: openai.tools.codeInterpreter(),
- web_search: openai.tools.webSearch(),
- file_search: openai.tools.fileSearch({ vectorStoreIds: ['vs_1234'] }), // requires a configured vector store
- },
-});
-
-for (const part of result.content) {
- if (part.type === 'source') {
- if (part.sourceType === 'document') {
- const providerMetadata = part.providerMetadata as
- | OpenaiResponsesSourceDocumentProviderMetadata
- | undefined;
- if (!providerMetadata) continue;
- const annotation = providerMetadata.openai;
- switch (annotation.type) {
- case 'file_citation':
- // file_citation is returned from file_search and provides:
- // properties: type, fileId and index
- // The filename can be accessed via part.filename.
- break;
- case 'container_file_citation':
- // container_file_citation is returned from code_interpreter and provides:
- // properties: type, containerId and fileId
- // The filename can be accessed via part.filename.
- break;
- case 'file_path':
- // file_path provides:
- // properties: type, fileId and index
- break;
- default: {
- const _exhaustiveCheck: never = annotation;
- throw new Error(
- `Unhandled annotation: ${JSON.stringify(_exhaustiveCheck)}`,
- );
- }
- }
- }
- }
-}
-```
-
-
- Annotations in text parts follow the OpenAI Responses API specification and
- therefore use snake_case properties (e.g. `file_id`, `container_id`). In
- contrast, `providerMetadata` for source document parts is normalized by the
- SDK to camelCase (e.g. `fileId`, `containerId`). Fields that depend on the
- original text content, such as `start_index` and `end_index`, are omitted, as
- are fields like `filename` that are directly available on the source object.
-
-
-### Chat Models
-
-You can create models that call the [OpenAI chat API](https://platform.openai.com/docs/api-reference/chat) using the `.chat()` factory method.
-The first argument is the model id, e.g. `gpt-4`.
-The OpenAI chat models support tool calls and some have multi-modal capabilities.
-
-```ts
-const model = openai.chat('gpt-5');
-```
-
-OpenAI chat models support also some model specific provider options that are not part of the [standard call settings](/docs/ai-sdk-core/settings).
-You can pass them in the `providerOptions` argument:
-
-```ts
-import { openai, type OpenAILanguageModelChatOptions } from '@ai-sdk/openai';
-
-const model = openai.chat('gpt-5');
-
-await generateText({
- model,
- providerOptions: {
- openai: {
- logitBias: {
- // optional likelihood for specific tokens
- '50256': -100,
- },
- user: 'test-user', // optional unique user identifier
- } satisfies OpenAILanguageModelChatOptions,
- },
-});
-```
-
-The following optional provider options are available for OpenAI chat models:
-
-- **logitBias** _Record<number, number>_
-
- Modifies the likelihood of specified tokens appearing in the completion.
-
- Accepts a JSON object that maps tokens (specified by their token ID in
- the GPT tokenizer) to an associated bias value from -100 to 100. You
- can use this tokenizer tool to convert text to token IDs. Mathematically,
- the bias is added to the logits generated by the model prior to sampling.
- The exact effect will vary per model, but values between -1 and 1 should
- decrease or increase likelihood of selection; values like -100 or 100
- should result in a ban or exclusive selection of the relevant token.
-
- As an example, you can pass `{"50256": -100}` to prevent the token from being generated.
-
-- **logprobs** _boolean | number_
-
- Return the log probabilities of the tokens. Including logprobs will increase
- the response size and can slow down response times. However, it can
- be useful to better understand how the model is behaving.
-
- Setting to true will return the log probabilities of the tokens that
- were generated.
-
- Setting to a number will return the log probabilities of the top n
- tokens that were generated.
-
-- **parallelToolCalls** _boolean_
-
- Whether to enable parallel function calling during tool use. Defaults to `true`.
-
-- **user** _string_
-
- A unique identifier representing your end-user, which can help OpenAI to
- monitor and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids).
-
-- **reasoningEffort** _'minimal' | 'low' | 'medium' | 'high' | 'xhigh'_
-
- Reasoning effort for reasoning models. Defaults to `medium`. If you use
- `providerOptions` to set the `reasoningEffort` option, this
- model setting will be ignored.
-
-- **maxCompletionTokens** _number_
-
- Maximum number of completion tokens to generate. Useful for reasoning models.
-
-- **store** _boolean_
-
- Whether to enable persistence in Responses API.
-
-- **metadata** _Record<string, string>_
-
- Metadata to associate with the request.
-
-- **prediction** _Record<string, any>_
-
- Parameters for prediction mode.
-
-- **serviceTier** _'auto' | 'flex' | 'priority' | 'default'_
-
- Service tier for the request. Set to 'flex' for 50% cheaper processing
- at the cost of increased latency (available for o3, o4-mini, and gpt-5 models).
- Set to 'priority' for faster processing with Enterprise access (available for gpt-4, gpt-5, gpt-5-mini, o3, o4-mini; gpt-5-nano is not supported).
-
- Defaults to 'auto'.
-
-- **strictJsonSchema** _boolean_
-
- Whether to use strict JSON schema validation.
- Defaults to `true`.
-
-- **textVerbosity** _'low' | 'medium' | 'high'_
-
- Controls the verbosity of the model's responses. Lower values will result in more concise responses, while higher values will result in more verbose responses.
-
-- **promptCacheKey** _string_
-
- A cache key for manual prompt caching control. Used by OpenAI to cache responses for similar requests to optimize your cache hit rates.
-
-- **promptCacheRetention** _'in_memory' | '24h'_
-
- The retention policy for the prompt cache. Set to `'24h'` to enable extended prompt caching, which keeps cached prefixes active for up to 24 hours. Defaults to `'in_memory'` for standard prompt caching. Note: `'24h'` is currently only available for the 5.1 series of models.
-
-- **safetyIdentifier** _string_
-
- A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies. The IDs should be a string that uniquely identifies each user.
-
-- **systemMessageMode** _'system' | 'developer' | 'remove'_
-
- Override the system message mode for this model. If not specified, the mode is automatically determined based on the model. `system` uses the 'system' role for system messages (default for most models); `developer` uses the 'developer' role (used by reasoning models); `remove` removes system messages entirely.
-
-- **forceReasoning** _boolean_
-
- Force treating this model as a reasoning model. This is useful for "stealth" reasoning models (e.g. via a custom baseURL) where the model ID is not recognized by the SDK's allowlist. When enabled, the SDK applies reasoning-model parameter compatibility rules and defaults `systemMessageMode` to `developer` unless overridden.
-
-#### Reasoning
-
-OpenAI has introduced the `o1`,`o3`, and `o4` series of [reasoning models](https://platform.openai.com/docs/guides/reasoning).
-Currently, `o4-mini`, `o3`, `o3-mini`, and `o1` are available via both the chat and responses APIs. The
-model `gpt-5.1-codex-mini` is available only via the [responses API](#responses-models).
-
-Reasoning models currently only generate text, have several limitations, and are only supported using `generateText` and `streamText`.
-
-They support additional settings and response metadata:
-
-- You can use `providerOptions` to set
-
- - the `reasoningEffort` option (or alternatively the `reasoningEffort` model setting), which determines the amount of reasoning the model performs.
-
-- You can use response `providerMetadata` to access the number of reasoning tokens that the model generated.
-
-```ts highlight="4,7-11,17"
-import { openai, type OpenAILanguageModelChatOptions } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const { text, usage, providerMetadata } = await generateText({
- model: openai.chat('gpt-5'),
- prompt: 'Invent a new holiday and describe its traditions.',
- providerOptions: {
- openai: {
- reasoningEffort: 'low',
- } satisfies OpenAILanguageModelChatOptions,
- },
-});
-
-console.log(text);
-console.log('Usage:', {
- ...usage,
- reasoningTokens: providerMetadata?.openai?.reasoningTokens,
-});
-```
-
-
- System messages are automatically converted to OpenAI developer messages for
- reasoning models when supported.
-
-
-- You can control how system messages are handled by providerOptions `systemMessageMode`:
-
- - `developer`: treat the prompt as a developer message (default for reasoning models).
- - `system`: keep the system message as a system-level instruction.
- - `remove`: remove the system message from the messages.
-
-```ts highlight="12"
-import { openai, type OpenAILanguageModelChatOptions } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai.chat('gpt-5'),
- messages: [
- { role: 'system', content: 'You are a helpful assistant.' },
- { role: 'user', content: 'Tell me a joke.' },
- ],
- providerOptions: {
- openai: {
- systemMessageMode: 'system',
- } satisfies OpenAILanguageModelChatOptions,
- },
-});
-```
-
-
- Reasoning models require additional runtime inference to complete their
- reasoning phase before generating a response. This introduces longer latency
- compared to other models.
-
-
-
- `maxOutputTokens` is automatically mapped to `max_completion_tokens` for
- reasoning models.
-
-
-#### Strict Structured Outputs
-
-Strict structured outputs are enabled by default.
-You can disable them by setting the `strictJsonSchema` option to `false`.
-
-```ts highlight="7"
-import { openai, OpenAILanguageModelChatOptions } from '@ai-sdk/openai';
-import { generateText, Output } from 'ai';
-import { z } from 'zod';
-
-const result = await generateText({
- model: openai.chat('gpt-4o-2024-08-06'),
- providerOptions: {
- openai: {
- strictJsonSchema: false,
- } satisfies OpenAILanguageModelChatOptions,
- },
- output: Output.object({
- schema: z.object({
- name: z.string(),
- ingredients: z.array(
- z.object({
- name: z.string(),
- amount: z.string(),
- }),
- ),
- steps: z.array(z.string()),
- }),
- schemaName: 'recipe',
- schemaDescription: 'A recipe for lasagna.',
- }),
- prompt: 'Generate a lasagna recipe.',
-});
-
-console.log(JSON.stringify(result.output, null, 2));
-```
-
-
- OpenAI structured outputs have several
- [limitations](https://openai.com/index/introducing-structured-outputs-in-the-api),
- in particular around the [supported schemas](https://platform.openai.com/docs/guides/structured-outputs/supported-schemas),
- and are therefore opt-in.
-
-For example, optional schema properties are not supported.
-You need to change Zod `.nullish()` and `.optional()` to `.nullable()`.
-
-
-
-#### Logprobs
-
-OpenAI provides logprobs information for completion/chat models.
-You can access it in the `providerMetadata` object.
-
-```ts highlight="11"
-import { openai, type OpenAILanguageModelChatOptions } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai.chat('gpt-5'),
- prompt: 'Write a vegetarian lasagna recipe for 4 people.',
- providerOptions: {
- openai: {
- // this can also be a number,
- // refer to logprobs provider options section for more
- logprobs: true,
- } satisfies OpenAILanguageModelChatOptions,
- },
-});
-
-const openaiMetadata = (await result.providerMetadata)?.openai;
-
-const logprobs = openaiMetadata?.logprobs;
-```
-
-#### Image Support
-
-The OpenAI Chat API supports Image inputs for appropriate models.
-You can pass Image files as part of the message content using the 'image' type:
-
-```ts
-const result = await generateText({
- model: openai.chat('gpt-5'),
- messages: [
- {
- role: 'user',
- content: [
- {
- type: 'text',
- text: 'Please describe the image.',
- },
- {
- type: 'image',
- image: readFileSync('./data/image.png'),
- },
- ],
- },
- ],
-});
-```
-
-The model will have access to the image and will respond to questions about it.
-The image should be passed using the `image` field.
-
-You can also pass the URL of an image.
-
-```ts
-{
- type: 'image',
- image: 'https://sample.edu/image.png',
-}
-```
-
-#### PDF support
-
-The OpenAI Chat API supports reading PDF files.
-You can pass PDF files as part of the message content using the `file` type:
-
-```ts
-const result = await generateText({
- model: openai.chat('gpt-5'),
- messages: [
- {
- role: 'user',
- content: [
- {
- type: 'text',
- text: 'What is an embedding model?',
- },
- {
- type: 'file',
- data: readFileSync('./data/ai.pdf'),
- mediaType: 'application/pdf',
- filename: 'ai.pdf', // optional
- },
- ],
- },
- ],
-});
-```
-
-The model will have access to the contents of the PDF file and
-respond to questions about it.
-The PDF file should be passed using the `data` field,
-and the `mediaType` should be set to `'application/pdf'`.
-
-You can also pass a file-id from the OpenAI Files API.
-
-```ts
-{
- type: 'file',
- data: 'file-8EFBcWHsQxZV7YGezBC1fq',
- mediaType: 'application/pdf',
-}
-```
-
-You can also pass the URL of a PDF.
-
-```ts
-{
- type: 'file',
- data: 'https://sample.edu/example.pdf',
- mediaType: 'application/pdf',
- filename: 'ai.pdf', // optional
-}
-```
-
-#### Predicted Outputs
-
-OpenAI supports [predicted outputs](https://platform.openai.com/docs/guides/latency-optimization#use-predicted-outputs) for `gpt-4o` and `gpt-4o-mini`.
-Predicted outputs help you reduce latency by allowing you to specify a base text that the model should modify.
-You can enable predicted outputs by adding the `prediction` option to the `providerOptions.openai` object:
-
-```ts highlight="15-18"
-const result = streamText({
- model: openai.chat('gpt-5'),
- messages: [
- {
- role: 'user',
- content: 'Replace the Username property with an Email property.',
- },
- {
- role: 'user',
- content: existingCode,
- },
- ],
- providerOptions: {
- openai: {
- prediction: {
- type: 'content',
- content: existingCode,
- },
- } satisfies OpenAILanguageModelChatOptions,
- },
-});
-```
-
-OpenAI provides usage information for predicted outputs (`acceptedPredictionTokens` and `rejectedPredictionTokens`).
-You can access it in the `providerMetadata` object.
-
-```ts highlight="11"
-const openaiMetadata = (await result.providerMetadata)?.openai;
-
-const acceptedPredictionTokens = openaiMetadata?.acceptedPredictionTokens;
-const rejectedPredictionTokens = openaiMetadata?.rejectedPredictionTokens;
-```
-
-
- OpenAI Predicted Outputs have several
- [limitations](https://platform.openai.com/docs/guides/predicted-outputs#limitations),
- e.g. unsupported API parameters and no tool calling support.
-
-
-#### Image Detail
-
-You can use the `openai` provider option to set the [image input detail](https://platform.openai.com/docs/guides/images-vision?api-mode=responses#specify-image-input-detail-level) to `high`, `low`, or `auto`:
-
-```ts highlight="13-16"
-const result = await generateText({
- model: openai.chat('gpt-5'),
- messages: [
- {
- role: 'user',
- content: [
- { type: 'text', text: 'Describe the image in detail.' },
- {
- type: 'image',
- image:
- 'https://github.com/vercel/ai/blob/main/examples/ai-functions/data/comic-cat.png?raw=true',
-
- // OpenAI specific options - image detail:
- providerOptions: {
- openai: { imageDetail: 'low' },
- },
- },
- ],
- },
- ],
-});
-```
-
-
- Because the `UIMessage` type (used by AI SDK UI hooks like `useChat`) does not
- support the `providerOptions` property, you can use `convertToModelMessages`
- first before passing the messages to functions like `generateText` or
- `streamText`. For more details on `providerOptions` usage, see
- [here](/docs/foundations/prompts#provider-options).
-
-
-#### Distillation
-
-OpenAI supports model distillation for some models.
-If you want to store a generation for use in the distillation process, you can add the `store` option to the `providerOptions.openai` object.
-This will save the generation to the OpenAI platform for later use in distillation.
-
-```typescript highlight="9-16"
-import { openai, type OpenAILanguageModelChatOptions } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-import 'dotenv/config';
-
-async function main() {
- const { text, usage } = await generateText({
- model: openai.chat('gpt-4o-mini'),
- prompt: 'Who worked on the original macintosh?',
- providerOptions: {
- openai: {
- store: true,
- metadata: {
- custom: 'value',
- },
- } satisfies OpenAILanguageModelChatOptions,
- },
- });
-
- console.log(text);
- console.log();
- console.log('Usage:', usage);
-}
-
-main().catch(console.error);
-```
-
-#### Prompt Caching
-
-OpenAI has introduced [Prompt Caching](https://platform.openai.com/docs/guides/prompt-caching) for supported models
-including `gpt-4o` and `gpt-4o-mini`.
-
-- Prompt caching is automatically enabled for these models, when the prompt is 1024 tokens or longer. It does
- not need to be explicitly enabled.
-- You can use response `providerMetadata` to access the number of prompt tokens that were a cache hit.
-- Note that caching behavior is dependent on load on OpenAI's infrastructure. Prompt prefixes generally remain in the
- cache following 5-10 minutes of inactivity before they are evicted, but during off-peak periods they may persist for up
- to an hour.
-
-```ts highlight="11"
-import { openai } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const { text, usage, providerMetadata } = await generateText({
- model: openai.chat('gpt-4o-mini'),
- prompt: `A 1024-token or longer prompt...`,
-});
-
-console.log(`usage:`, {
- ...usage,
- cachedPromptTokens: providerMetadata?.openai?.cachedPromptTokens,
-});
-```
-
-To improve cache hit rates, you can manually control caching using the `promptCacheKey` option:
-
-```ts highlight="7-11"
-import { openai, type OpenAILanguageModelChatOptions } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const { text, usage, providerMetadata } = await generateText({
- model: openai.chat('gpt-5'),
- prompt: `A 1024-token or longer prompt...`,
- providerOptions: {
- openai: {
- promptCacheKey: 'my-custom-cache-key-123',
- } satisfies OpenAILanguageModelChatOptions,
- },
-});
-
-console.log(`usage:`, {
- ...usage,
- cachedPromptTokens: providerMetadata?.openai?.cachedPromptTokens,
-});
-```
-
-For GPT-5.1 models, you can enable extended prompt caching that keeps cached prefixes active for up to 24 hours:
-
-```ts highlight="7-12"
-import { openai, type OpenAILanguageModelChatOptions } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const { text, usage, providerMetadata } = await generateText({
- model: openai.chat('gpt-5.1'),
- prompt: `A 1024-token or longer prompt...`,
- providerOptions: {
- openai: {
- promptCacheKey: 'my-custom-cache-key-123',
- promptCacheRetention: '24h', // Extended caching for GPT-5.1
- } satisfies OpenAILanguageModelChatOptions,
- },
-});
-
-console.log(`usage:`, {
- ...usage,
- cachedPromptTokens: providerMetadata?.openai?.cachedPromptTokens,
-});
-```
-
-#### Audio Input
-
-With the `gpt-4o-audio-preview` model, you can pass audio files to the model.
-
-
- The `gpt-4o-audio-preview` model is currently in preview and requires at least
- some audio inputs. It will not work with non-audio data.
-
-
-```ts highlight="12-14"
-import { openai } from '@ai-sdk/openai';
-import { generateText } from 'ai';
-
-const result = await generateText({
- model: openai.chat('gpt-4o-audio-preview'),
- messages: [
- {
- role: 'user',
- content: [
- { type: 'text', text: 'What is the audio saying?' },
- {
- type: 'file',
- mediaType: 'audio/mpeg',
- data: readFileSync('./data/galileo.mp3'),
- },
- ],
- },
- ],
-});
-```
-
-### Completion Models
-
-You can create models that call the [OpenAI completions API](https://platform.openai.com/docs/api-reference/completions) using the `.completion()` factory method.
-The first argument is the model id.
-Currently only `gpt-3.5-turbo-instruct` is supported.
-
-```ts
-const model = openai.completion('gpt-3.5-turbo-instruct');
-```
-
-OpenAI completion models support also some model specific settings that are not part of the [standard call settings](/docs/ai-sdk-core/settings).
-You can pass them as an options argument:
-
-```ts
-const model = openai.completion('gpt-3.5-turbo-instruct');
-
-await model.doGenerate({
- providerOptions: {
- openai: {
- echo: true, // optional, echo the prompt in addition to the completion
- logitBias: {
- // optional likelihood for specific tokens
- '50256': -100,
- },
- suffix: 'some text', // optional suffix that comes after a completion of inserted text
- user: 'test-user', // optional unique user identifier
- } satisfies OpenAILanguageModelCompletionOptions,
- },
-});
-```
-
-The following optional provider options are available for OpenAI completion models:
-
-- **echo**: _boolean_
-
- Echo back the prompt in addition to the completion.
-
-- **logitBias** _Record<number, number>_
-
- Modifies the likelihood of specified tokens appearing in the completion.
-
- Accepts a JSON object that maps tokens (specified by their token ID in
- the GPT tokenizer) to an associated bias value from -100 to 100. You
- can use this tokenizer tool to convert text to token IDs. Mathematically,
- the bias is added to the logits generated by the model prior to sampling.
- The exact effect will vary per model, but values between -1 and 1 should
- decrease or increase likelihood of selection; values like -100 or 100
- should result in a ban or exclusive selection of the relevant token.
-
- As an example, you can pass `{"50256": -100}` to prevent the <|endoftext|>
- token from being generated.
-
-- **logprobs** _boolean | number_
-
- Return the log probabilities of the tokens. Including logprobs will increase
- the response size and can slow down response times. However, it can
- be useful to better understand how the model is behaving.
-
- Setting to true will return the log probabilities of the tokens that
- were generated.
-
- Setting to a number will return the log probabilities of the top n
- tokens that were generated.
-
-- **suffix** _string_
-
- The suffix that comes after a completion of inserted text.
-
-- **user** _string_
-
- A unique identifier representing your end-user, which can help OpenAI to
- monitor and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids).
-
-### Model Capabilities
-
-| Model | Image Input | Audio Input | Object Generation | Tool Usage |
-| --------------------- | ------------------- | ------------------- | ------------------- | ------------------- |
-| `gpt-5.4-pro` | | | | |
-| `gpt-5.4` | | | | |
-| `gpt-5.4-mini` | | | | |
-| `gpt-5.4-nano` | | | | |
-| `gpt-5.3-chat-latest` | | | | |
-| `gpt-5.2-pro` | | | | |
-| `gpt-5.2-chat-latest` | | | | |
-| `gpt-5.2` | | | | |
-| `gpt-5.1-codex-mini` | | | | |
-| `gpt-5.1-codex` | | | | |
-| `gpt-5.1-chat-latest` | | | | |
-| `gpt-5.1` | | | | |
-| `gpt-5-pro` | | | | |
-| `gpt-5` | | | | |
-| `gpt-5-mini` | | | | |
-| `gpt-5-nano` | | | | |
-| `gpt-5-codex` | | | | |
-| `gpt-5-chat-latest` | | | | |
-| `gpt-4.1` | | | | |
-| `gpt-4.1-mini` | | | | |
-| `gpt-4.1-nano` | | | | |
-| `gpt-4o` | | | | |
-| `gpt-4o-mini` | | | | |
-
-
- The table above lists popular models. Please see the [OpenAI
- docs](https://platform.openai.com/docs/models) for a full list of available
- models. The table above lists popular models. You can also pass any available
- provider model ID as a string if needed.
-
-
-## Embedding Models
-
-You can create models that call the [OpenAI embeddings API](https://platform.openai.com/docs/api-reference/embeddings)
-using the `.embedding()` factory method.
-
-```ts
-const model = openai.embedding('text-embedding-3-large');
-```
-
-OpenAI embedding models support several additional provider options.
-You can pass them as an options argument:
-
-```ts
-import { openai, type OpenAIEmbeddingModelOptions } from '@ai-sdk/openai';
-import { embed } from 'ai';
-
-const { embedding } = await embed({
- model: openai.embedding('text-embedding-3-large'),
- value: 'sunny day at the beach',
- providerOptions: {
- openai: {
- dimensions: 512, // optional, number of dimensions for the embedding
- user: 'test-user', // optional unique user identifier
- } satisfies OpenAIEmbeddingModelOptions,
- },
-});
-```
-
-The following optional provider options are available for OpenAI embedding models:
-
-- **dimensions**: _number_
-
- The number of dimensions the resulting output embeddings should have.
- Only supported in text-embedding-3 and later models.
-
-- **user** _string_
-
- A unique identifier representing your end-user, which can help OpenAI to
- monitor and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids).
-
-### Model Capabilities
-
-| Model | Default Dimensions | Custom Dimensions |
-| ------------------------ | ------------------ | ------------------- |
-| `text-embedding-3-large` | 3072 | |
-| `text-embedding-3-small` | 1536 | |
-| `text-embedding-ada-002` | 1536 | |
-
-## Image Models
-
-You can create models that call the [OpenAI image generation API](https://platform.openai.com/docs/api-reference/images)
-using the `.image()` factory method.
-
-```ts
-const model = openai.image('dall-e-3');
-```
-
-
- Dall-E models do not support the `aspectRatio` parameter. Use the `size`
- parameter instead.
-
-
-### Image Editing
-
-OpenAI's `gpt-image-1` model supports powerful image editing capabilities. Pass input images via `prompt.images` to transform, combine, or edit existing images.
-
-#### Basic Image Editing
-
-Transform an existing image using text prompts:
-
-```ts
-const imageBuffer = readFileSync('./input-image.png');
-
-const { images } = await generateImage({
- model: openai.image('gpt-image-1'),
- prompt: {
- text: 'Turn the cat into a dog but retain the style of the original image',
- images: [imageBuffer],
- },
-});
-```
-
-#### Inpainting with Mask
-
-Edit specific parts of an image using a mask. Transparent areas in the mask indicate where the image should be edited:
-
-```ts
-const image = readFileSync('./input-image.png');
-const mask = readFileSync('./mask.png'); // Transparent areas = edit regions
-
-const { images } = await generateImage({
- model: openai.image('gpt-image-1'),
- prompt: {
- text: 'A sunlit indoor lounge area with a pool containing a flamingo',
- images: [image],
- mask: mask,
- },
-});
-```
-
-#### Background Removal
-
-Remove the background from an image by setting `background` to `transparent`:
-
-```ts
-const imageBuffer = readFileSync('./input-image.png');
-
-const { images } = await generateImage({
- model: openai.image('gpt-image-1'),
- prompt: {
- text: 'do not change anything',
- images: [imageBuffer],
- },
- providerOptions: {
- openai: {
- background: 'transparent',
- output_format: 'png',
- },
- },
-});
-```
-
-#### Multi-Image Combining
-
-Combine multiple reference images into a single output. `gpt-image-1` supports up to 16 input images:
-
-```ts
-const cat = readFileSync('./cat.png');
-const dog = readFileSync('./dog.png');
-const owl = readFileSync('./owl.png');
-const bear = readFileSync('./bear.png');
-
-const { images } = await generateImage({
- model: openai.image('gpt-image-1'),
- prompt: {
- text: 'Combine these animals into a group photo, retaining the original style',
- images: [cat, dog, owl, bear],
- },
-});
-```
-
-
- Input images can be provided as `Buffer`, `ArrayBuffer`, `Uint8Array`, or
- base64-encoded strings. For `gpt-image-1`, each image should be a `png`,
- `webp`, or `jpg` file less than 50MB.
-
-
-### Model Capabilities
-
-| Model | Sizes |
-| ------------------ | ------------------------------- |
-| `gpt-image-1.5` | 1024x1024, 1536x1024, 1024x1536 |
-| `gpt-image-1-mini` | 1024x1024, 1536x1024, 1024x1536 |
-| `gpt-image-1` | 1024x1024, 1536x1024, 1024x1536 |
-| `dall-e-3` | 1024x1024, 1792x1024, 1024x1792 |
-| `dall-e-2` | 256x256, 512x512, 1024x1024 |
-
-You can pass optional `providerOptions` to the image model. These are prone to change by OpenAI and are model dependent. For example, the `gpt-image-1` model supports the `quality` option:
-
-```ts
-const { image, providerMetadata } = await generateImage({
- model: openai.image('gpt-image-1.5'),
- prompt: 'A salamander at sunrise in a forest pond in the Seychelles.',
- providerOptions: {
- openai: { quality: 'high' },
- },
-});
-```
-
-For more on `generateImage()` see [Image Generation](/docs/ai-sdk-core/image-generation).
-
-OpenAI's image models return additional metadata in the response that can be
-accessed via `providerMetadata.openai`. The following OpenAI-specific metadata
-is available:
-
-- **images** _Array<object>_
-
- Array of image-specific metadata. Each image object may contain:
-
- - `revisedPrompt` _string_ - The revised prompt that was actually used to generate the image (OpenAI may modify your prompt for safety or clarity)
- - `created` _number_ - The Unix timestamp (in seconds) of when the image was created
- - `size` _string_ - The size of the generated image. One of `1024x1024`, `1024x1536`, or `1536x1024`
- - `quality` _string_ - The quality of the generated image. One of `low`, `medium`, or `high`
- - `background` _string_ - The background parameter used for the image generation. Either `transparent` or `opaque`
- - `outputFormat` _string_ - The output format of the generated image. One of `png`, `webp`, or `jpeg`
-
-For more information on the available OpenAI image model options, see the [OpenAI API reference](https://platform.openai.com/docs/api-reference/images/create).
-
-## Transcription Models
-
-You can create models that call the [OpenAI transcription API](https://platform.openai.com/docs/api-reference/audio/transcribe)
-using the `.transcription()` factory method.
-
-The first argument is the model id e.g. `whisper-1`.
-
-```ts
-const model = openai.transcription('whisper-1');
-```
-
-You can also pass additional provider-specific options using the `providerOptions` argument. For example, supplying the input language in ISO-639-1 (e.g. `en`) format will improve accuracy and latency.
-
-```ts highlight="6"
-import { experimental_transcribe as transcribe } from 'ai';
-import { openai, type OpenAITranscriptionModelOptions } from '@ai-sdk/openai';
-
-const result = await transcribe({
- model: openai.transcription('whisper-1'),
- audio: new Uint8Array([1, 2, 3, 4]),
- providerOptions: {
- openai: { language: 'en' } satisfies OpenAITranscriptionModelOptions,
- },
-});
-```
-
-To get word-level timestamps, specify the granularity:
-
-```ts highlight="8-9"
-import { experimental_transcribe as transcribe } from 'ai';
-import { openai, type OpenAITranscriptionModelOptions } from '@ai-sdk/openai';
-
-const result = await transcribe({
- model: openai.transcription('whisper-1'),
- audio: new Uint8Array([1, 2, 3, 4]),
- providerOptions: {
- openai: {
- //timestampGranularities: ['word'],
- timestampGranularities: ['segment'],
- } satisfies OpenAITranscriptionModelOptions,
- },
-});
-
-// Access word-level timestamps
-console.log(result.segments); // Array of segments with startSecond/endSecond
-```
-
-The following provider options are available:
-
-- **timestampGranularities** _string[]_
- The granularity of the timestamps in the transcription.
- Defaults to `['segment']`.
- Possible values are `['word']`, `['segment']`, and `['word', 'segment']`.
- Note: There is no additional latency for segment timestamps, but generating word timestamps incurs additional latency.
-
-- **language** _string_
- The language of the input audio. Supplying the input language in ISO-639-1 format (e.g. 'en') will improve accuracy and latency.
- Optional.
-
-- **prompt** _string_
- An optional text to guide the model's style or continue a previous audio segment. The prompt should match the audio language.
- Optional.
-
-- **temperature** _number_
- The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.
- Defaults to 0.
- Optional.
-
-- **include** _string[]_
- Additional information to include in the transcription response.
-
-### Model Capabilities
-
-| Model | Transcription | Duration | Segments | Language |
-| ------------------------ | ------------------- | ------------------- | ------------------- | ------------------- |
-| `whisper-1` | | | | |
-| `gpt-4o-mini-transcribe` | | | | |
-| `gpt-4o-transcribe` | | | | |
-
-## Speech Models
-
-You can create models that call the [OpenAI speech API](https://platform.openai.com/docs/api-reference/audio/speech)
-using the `.speech()` factory method.
-
-The first argument is the model id e.g. `tts-1`.
-
-```ts
-const model = openai.speech('tts-1');
-```
-
-The `voice` argument can be set to one of OpenAI's available voices: `alloy`, `ash`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, or `shimmer`.
-
-```ts highlight="6"
-import { experimental_generateSpeech as generateSpeech } from 'ai';
-import { openai } from '@ai-sdk/openai';
-
-const result = await generateSpeech({
- model: openai.speech('tts-1'),
- text: 'Hello, world!',
- voice: 'alloy', // OpenAI voice ID
-});
-```
-
-You can also pass additional provider-specific options using the `providerOptions` argument:
-
-```ts highlight="7-9"
-import { experimental_generateSpeech as generateSpeech } from 'ai';
-import { openai, type OpenAISpeechModelOptions } from '@ai-sdk/openai';
-
-const result = await generateSpeech({
- model: openai.speech('tts-1'),
- text: 'Hello, world!',
- voice: 'alloy',
- providerOptions: {
- openai: {
- speed: 1.2,
- } satisfies OpenAISpeechModelOptions,
- },
-});
-```
-
-- **instructions** _string_
- Control the voice of your generated audio with additional instructions e.g. "Speak in a slow and steady tone".
- Does not work with `tts-1` or `tts-1-hd`.
- Optional.
-
-- **speed** _number_
- The speed of the generated audio.
- Select a value from 0.25 to 4.0.
- Defaults to 1.0.
- Optional.
-
-### Model Capabilities
-
-| Model | Instructions |
-| ----------------- | ------------------- |
-| `tts-1` | |
-| `tts-1-hd` | |
-| `gpt-4o-mini-tts` | |
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/internal.d.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/internal.d.ts
deleted file mode 100644
index be034cd88..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/internal.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './dist/internal';
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/package.json b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/package.json
deleted file mode 100644
index 79bd3f868..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/package.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "name": "@ai-sdk/openai",
- "version": "3.0.48",
- "license": "Apache-2.0",
- "sideEffects": false,
- "main": "./dist/index.js",
- "module": "./dist/index.mjs",
- "types": "./dist/index.d.ts",
- "files": [
- "dist/**/*",
- "docs/**/*",
- "src",
- "!src/**/*.test.ts",
- "!src/**/*.test-d.ts",
- "!src/**/__snapshots__",
- "!src/**/__fixtures__",
- "CHANGELOG.md",
- "README.md",
- "internal.d.ts"
- ],
- "directories": {
- "doc": "./docs"
- },
- "exports": {
- "./package.json": "./package.json",
- ".": {
- "types": "./dist/index.d.ts",
- "import": "./dist/index.mjs",
- "require": "./dist/index.js"
- },
- "./internal": {
- "types": "./dist/internal/index.d.ts",
- "import": "./dist/internal/index.mjs",
- "module": "./dist/internal/index.mjs",
- "require": "./dist/internal/index.js"
- }
- },
- "dependencies": {
- "@ai-sdk/provider": "3.0.8",
- "@ai-sdk/provider-utils": "4.0.21"
- },
- "devDependencies": {
- "@types/node": "20.17.24",
- "tsup": "^8",
- "typescript": "5.8.3",
- "zod": "3.25.76",
- "@vercel/ai-tsconfig": "0.0.0",
- "@ai-sdk/test-server": "1.0.3"
- },
- "peerDependencies": {
- "zod": "^3.25.76 || ^4.1.8"
- },
- "engines": {
- "node": ">=18"
- },
- "publishConfig": {
- "access": "public"
- },
- "homepage": "https://ai-sdk.dev/docs",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/vercel/ai.git"
- },
- "bugs": {
- "url": "https://github.com/vercel/ai/issues"
- },
- "keywords": [
- "ai"
- ],
- "scripts": {
- "build": "pnpm clean && tsup --tsconfig tsconfig.build.json",
- "build:watch": "pnpm clean && tsup --watch",
- "clean": "del-cli dist docs *.tsbuildinfo",
- "type-check": "tsc --build",
- "test": "pnpm test:node && pnpm test:edge",
- "test:update": "pnpm test:node -u",
- "test:watch": "vitest --config vitest.node.config.js",
- "test:edge": "vitest --config vitest.edge.config.js --run",
- "test:node": "vitest --config vitest.node.config.js --run"
- }
-}
\ No newline at end of file
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/convert-openai-chat-usage.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/convert-openai-chat-usage.ts
deleted file mode 100644
index 9e62acd1b..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/convert-openai-chat-usage.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { LanguageModelV3Usage } from '@ai-sdk/provider';
-
-export type OpenAIChatUsage = {
- prompt_tokens?: number | null;
- completion_tokens?: number | null;
- total_tokens?: number | null;
- prompt_tokens_details?: {
- cached_tokens?: number | null;
- } | null;
- completion_tokens_details?: {
- reasoning_tokens?: number | null;
- accepted_prediction_tokens?: number | null;
- rejected_prediction_tokens?: number | null;
- } | null;
-};
-
-export function convertOpenAIChatUsage(
- usage: OpenAIChatUsage | undefined | null,
-): LanguageModelV3Usage {
- if (usage == null) {
- return {
- inputTokens: {
- total: undefined,
- noCache: undefined,
- cacheRead: undefined,
- cacheWrite: undefined,
- },
- outputTokens: {
- total: undefined,
- text: undefined,
- reasoning: undefined,
- },
- raw: undefined,
- };
- }
-
- const promptTokens = usage.prompt_tokens ?? 0;
- const completionTokens = usage.completion_tokens ?? 0;
- const cachedTokens = usage.prompt_tokens_details?.cached_tokens ?? 0;
- const reasoningTokens =
- usage.completion_tokens_details?.reasoning_tokens ?? 0;
-
- return {
- inputTokens: {
- total: promptTokens,
- noCache: promptTokens - cachedTokens,
- cacheRead: cachedTokens,
- cacheWrite: undefined,
- },
- outputTokens: {
- total: completionTokens,
- text: completionTokens - reasoningTokens,
- reasoning: reasoningTokens,
- },
- raw: usage,
- };
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/convert-to-openai-chat-messages.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/convert-to-openai-chat-messages.ts
deleted file mode 100644
index d6c520b73..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/convert-to-openai-chat-messages.ts
+++ /dev/null
@@ -1,225 +0,0 @@
-import {
- SharedV3Warning,
- LanguageModelV3Prompt,
- UnsupportedFunctionalityError,
-} from '@ai-sdk/provider';
-import { OpenAIChatPrompt } from './openai-chat-prompt';
-import { convertToBase64 } from '@ai-sdk/provider-utils';
-
-export function convertToOpenAIChatMessages({
- prompt,
- systemMessageMode = 'system',
-}: {
- prompt: LanguageModelV3Prompt;
- systemMessageMode?: 'system' | 'developer' | 'remove';
-}): {
- messages: OpenAIChatPrompt;
- warnings: Array;
-} {
- const messages: OpenAIChatPrompt = [];
- const warnings: Array = [];
-
- for (const { role, content } of prompt) {
- switch (role) {
- case 'system': {
- switch (systemMessageMode) {
- case 'system': {
- messages.push({ role: 'system', content });
- break;
- }
- case 'developer': {
- messages.push({ role: 'developer', content });
- break;
- }
- case 'remove': {
- warnings.push({
- type: 'other',
- message: 'system messages are removed for this model',
- });
- break;
- }
- default: {
- const _exhaustiveCheck: never = systemMessageMode;
- throw new Error(
- `Unsupported system message mode: ${_exhaustiveCheck}`,
- );
- }
- }
- break;
- }
-
- case 'user': {
- if (content.length === 1 && content[0].type === 'text') {
- messages.push({ role: 'user', content: content[0].text });
- break;
- }
-
- messages.push({
- role: 'user',
- content: content.map((part, index) => {
- switch (part.type) {
- case 'text': {
- return { type: 'text', text: part.text };
- }
- case 'file': {
- if (part.mediaType.startsWith('image/')) {
- const mediaType =
- part.mediaType === 'image/*'
- ? 'image/jpeg'
- : part.mediaType;
-
- return {
- type: 'image_url',
- image_url: {
- url:
- part.data instanceof URL
- ? part.data.toString()
- : `data:${mediaType};base64,${convertToBase64(part.data)}`,
-
- // OpenAI specific extension: image detail
- detail: part.providerOptions?.openai?.imageDetail,
- },
- };
- } else if (part.mediaType.startsWith('audio/')) {
- if (part.data instanceof URL) {
- throw new UnsupportedFunctionalityError({
- functionality: 'audio file parts with URLs',
- });
- }
-
- switch (part.mediaType) {
- case 'audio/wav': {
- return {
- type: 'input_audio',
- input_audio: {
- data: convertToBase64(part.data),
- format: 'wav',
- },
- };
- }
- case 'audio/mp3':
- case 'audio/mpeg': {
- return {
- type: 'input_audio',
- input_audio: {
- data: convertToBase64(part.data),
- format: 'mp3',
- },
- };
- }
-
- default: {
- throw new UnsupportedFunctionalityError({
- functionality: `audio content parts with media type ${part.mediaType}`,
- });
- }
- }
- } else if (part.mediaType === 'application/pdf') {
- if (part.data instanceof URL) {
- throw new UnsupportedFunctionalityError({
- functionality: 'PDF file parts with URLs',
- });
- }
-
- return {
- type: 'file',
- file:
- typeof part.data === 'string' &&
- part.data.startsWith('file-')
- ? { file_id: part.data }
- : {
- filename: part.filename ?? `part-${index}.pdf`,
- file_data: `data:application/pdf;base64,${convertToBase64(part.data)}`,
- },
- };
- } else {
- throw new UnsupportedFunctionalityError({
- functionality: `file part media type ${part.mediaType}`,
- });
- }
- }
- }
- }),
- });
-
- break;
- }
-
- case 'assistant': {
- let text = '';
- const toolCalls: Array<{
- id: string;
- type: 'function';
- function: { name: string; arguments: string };
- }> = [];
-
- for (const part of content) {
- switch (part.type) {
- case 'text': {
- text += part.text;
- break;
- }
- case 'tool-call': {
- toolCalls.push({
- id: part.toolCallId,
- type: 'function',
- function: {
- name: part.toolName,
- arguments: JSON.stringify(part.input),
- },
- });
- break;
- }
- }
- }
-
- messages.push({
- role: 'assistant',
- content: text,
- tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
- });
-
- break;
- }
-
- case 'tool': {
- for (const toolResponse of content) {
- if (toolResponse.type === 'tool-approval-response') {
- continue;
- }
- const output = toolResponse.output;
-
- let contentValue: string;
- switch (output.type) {
- case 'text':
- case 'error-text':
- contentValue = output.value;
- break;
- case 'execution-denied':
- contentValue = output.reason ?? 'Tool execution denied.';
- break;
- case 'content':
- case 'json':
- case 'error-json':
- contentValue = JSON.stringify(output.value);
- break;
- }
-
- messages.push({
- role: 'tool',
- tool_call_id: toolResponse.toolCallId,
- content: contentValue,
- });
- }
- break;
- }
-
- default: {
- const _exhaustiveCheck: never = role;
- throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
- }
- }
- }
-
- return { messages, warnings };
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/get-response-metadata.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/get-response-metadata.ts
deleted file mode 100644
index 7c6ca41fd..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/get-response-metadata.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-export function getResponseMetadata({
- id,
- model,
- created,
-}: {
- id?: string | undefined | null;
- created?: number | undefined | null;
- model?: string | undefined | null;
-}) {
- return {
- id: id ?? undefined,
- modelId: model ?? undefined,
- timestamp: created ? new Date(created * 1000) : undefined,
- };
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/map-openai-finish-reason.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/map-openai-finish-reason.ts
deleted file mode 100644
index f3005bb8d..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/map-openai-finish-reason.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { LanguageModelV3FinishReason } from '@ai-sdk/provider';
-
-export function mapOpenAIFinishReason(
- finishReason: string | null | undefined,
-): LanguageModelV3FinishReason['unified'] {
- switch (finishReason) {
- case 'stop':
- return 'stop';
- case 'length':
- return 'length';
- case 'content_filter':
- return 'content-filter';
- case 'function_call':
- case 'tool_calls':
- return 'tool-calls';
- default:
- return 'other';
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-api.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-api.ts
deleted file mode 100644
index 7b634112a..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-api.ts
+++ /dev/null
@@ -1,198 +0,0 @@
-import { JSONSchema7 } from '@ai-sdk/provider';
-import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-import { openaiErrorDataSchema } from '../openai-error';
-
-export interface OpenAIChatFunctionTool {
- type: 'function';
- function: {
- name: string;
- description: string | undefined;
- parameters: JSONSchema7;
- strict?: boolean;
- };
-}
-
-export type OpenAIChatToolChoice =
- | 'auto'
- | 'none'
- | 'required'
- | { type: 'function'; function: { name: string } };
-
-// limited version of the schema, focussed on what is needed for the implementation
-// this approach limits breakages when the API changes and increases efficiency
-export const openaiChatResponseSchema = lazySchema(() =>
- zodSchema(
- z.object({
- id: z.string().nullish(),
- created: z.number().nullish(),
- model: z.string().nullish(),
- choices: z.array(
- z.object({
- message: z.object({
- role: z.literal('assistant').nullish(),
- content: z.string().nullish(),
- tool_calls: z
- .array(
- z.object({
- id: z.string().nullish(),
- type: z.literal('function'),
- function: z.object({
- name: z.string(),
- arguments: z.string(),
- }),
- }),
- )
- .nullish(),
- annotations: z
- .array(
- z.object({
- type: z.literal('url_citation'),
- url_citation: z.object({
- start_index: z.number(),
- end_index: z.number(),
- url: z.string(),
- title: z.string(),
- }),
- }),
- )
- .nullish(),
- }),
- index: z.number(),
- logprobs: z
- .object({
- content: z
- .array(
- z.object({
- token: z.string(),
- logprob: z.number(),
- top_logprobs: z.array(
- z.object({
- token: z.string(),
- logprob: z.number(),
- }),
- ),
- }),
- )
- .nullish(),
- })
- .nullish(),
- finish_reason: z.string().nullish(),
- }),
- ),
- usage: z
- .object({
- prompt_tokens: z.number().nullish(),
- completion_tokens: z.number().nullish(),
- total_tokens: z.number().nullish(),
- prompt_tokens_details: z
- .object({
- cached_tokens: z.number().nullish(),
- })
- .nullish(),
- completion_tokens_details: z
- .object({
- reasoning_tokens: z.number().nullish(),
- accepted_prediction_tokens: z.number().nullish(),
- rejected_prediction_tokens: z.number().nullish(),
- })
- .nullish(),
- })
- .nullish(),
- }),
- ),
-);
-
-// limited version of the schema, focussed on what is needed for the implementation
-// this approach limits breakages when the API changes and increases efficiency
-export const openaiChatChunkSchema = lazySchema(() =>
- zodSchema(
- z.union([
- z.object({
- id: z.string().nullish(),
- created: z.number().nullish(),
- model: z.string().nullish(),
- choices: z.array(
- z.object({
- delta: z
- .object({
- role: z.enum(['assistant']).nullish(),
- content: z.string().nullish(),
- tool_calls: z
- .array(
- z.object({
- index: z.number(),
- id: z.string().nullish(),
- type: z.literal('function').nullish(),
- function: z.object({
- name: z.string().nullish(),
- arguments: z.string().nullish(),
- }),
- }),
- )
- .nullish(),
- annotations: z
- .array(
- z.object({
- type: z.literal('url_citation'),
- url_citation: z.object({
- start_index: z.number(),
- end_index: z.number(),
- url: z.string(),
- title: z.string(),
- }),
- }),
- )
- .nullish(),
- })
- .nullish(),
- logprobs: z
- .object({
- content: z
- .array(
- z.object({
- token: z.string(),
- logprob: z.number(),
- top_logprobs: z.array(
- z.object({
- token: z.string(),
- logprob: z.number(),
- }),
- ),
- }),
- )
- .nullish(),
- })
- .nullish(),
- finish_reason: z.string().nullish(),
- index: z.number(),
- }),
- ),
- usage: z
- .object({
- prompt_tokens: z.number().nullish(),
- completion_tokens: z.number().nullish(),
- total_tokens: z.number().nullish(),
- prompt_tokens_details: z
- .object({
- cached_tokens: z.number().nullish(),
- })
- .nullish(),
- completion_tokens_details: z
- .object({
- reasoning_tokens: z.number().nullish(),
- accepted_prediction_tokens: z.number().nullish(),
- rejected_prediction_tokens: z.number().nullish(),
- })
- .nullish(),
- })
- .nullish(),
- }),
- openaiErrorDataSchema,
- ]),
- ),
-);
-
-export type OpenAIChatResponse = InferSchema;
-
-export type OpenAIChatChunk = InferSchema;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-language-model.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-language-model.ts
deleted file mode 100644
index 96077d47c..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-language-model.ts
+++ /dev/null
@@ -1,703 +0,0 @@
-import {
- InvalidResponseDataError,
- LanguageModelV3,
- LanguageModelV3CallOptions,
- LanguageModelV3Content,
- LanguageModelV3FinishReason,
- LanguageModelV3GenerateResult,
- LanguageModelV3StreamPart,
- LanguageModelV3StreamResult,
- SharedV3ProviderMetadata,
- SharedV3Warning,
-} from '@ai-sdk/provider';
-import {
- FetchFunction,
- ParseResult,
- combineHeaders,
- createEventSourceResponseHandler,
- createJsonResponseHandler,
- generateId,
- isParsableJson,
- parseProviderOptions,
- postJsonToApi,
-} from '@ai-sdk/provider-utils';
-import { openaiFailedResponseHandler } from '../openai-error';
-import { getOpenAILanguageModelCapabilities } from '../openai-language-model-capabilities';
-import {
- OpenAIChatUsage,
- convertOpenAIChatUsage,
-} from './convert-openai-chat-usage';
-import { convertToOpenAIChatMessages } from './convert-to-openai-chat-messages';
-import { getResponseMetadata } from './get-response-metadata';
-import { mapOpenAIFinishReason } from './map-openai-finish-reason';
-import {
- OpenAIChatChunk,
- openaiChatChunkSchema,
- openaiChatResponseSchema,
-} from './openai-chat-api';
-import {
- OpenAIChatModelId,
- openaiLanguageModelChatOptions,
-} from './openai-chat-options';
-import { prepareChatTools } from './openai-chat-prepare-tools';
-
-type OpenAIChatConfig = {
- provider: string;
- headers: () => Record;
- url: (options: { modelId: string; path: string }) => string;
- fetch?: FetchFunction;
-};
-
-export class OpenAIChatLanguageModel implements LanguageModelV3 {
- readonly specificationVersion = 'v3';
-
- readonly modelId: OpenAIChatModelId;
-
- readonly supportedUrls = {
- 'image/*': [/^https?:\/\/.*$/],
- };
-
- private readonly config: OpenAIChatConfig;
-
- constructor(modelId: OpenAIChatModelId, config: OpenAIChatConfig) {
- this.modelId = modelId;
- this.config = config;
- }
-
- get provider(): string {
- return this.config.provider;
- }
-
- private async getArgs({
- prompt,
- maxOutputTokens,
- temperature,
- topP,
- topK,
- frequencyPenalty,
- presencePenalty,
- stopSequences,
- responseFormat,
- seed,
- tools,
- toolChoice,
- providerOptions,
- }: LanguageModelV3CallOptions) {
- const warnings: SharedV3Warning[] = [];
-
- // Parse provider options
- const openaiOptions =
- (await parseProviderOptions({
- provider: 'openai',
- providerOptions,
- schema: openaiLanguageModelChatOptions,
- })) ?? {};
-
- const modelCapabilities = getOpenAILanguageModelCapabilities(this.modelId);
- const isReasoningModel =
- openaiOptions.forceReasoning ?? modelCapabilities.isReasoningModel;
-
- if (topK != null) {
- warnings.push({ type: 'unsupported', feature: 'topK' });
- }
-
- const { messages, warnings: messageWarnings } = convertToOpenAIChatMessages(
- {
- prompt,
- systemMessageMode:
- openaiOptions.systemMessageMode ??
- (isReasoningModel
- ? 'developer'
- : modelCapabilities.systemMessageMode),
- },
- );
-
- warnings.push(...messageWarnings);
-
- const strictJsonSchema = openaiOptions.strictJsonSchema ?? true;
-
- const baseArgs = {
- // model id:
- model: this.modelId,
-
- // model specific settings:
- logit_bias: openaiOptions.logitBias,
- logprobs:
- openaiOptions.logprobs === true ||
- typeof openaiOptions.logprobs === 'number'
- ? true
- : undefined,
- top_logprobs:
- typeof openaiOptions.logprobs === 'number'
- ? openaiOptions.logprobs
- : typeof openaiOptions.logprobs === 'boolean'
- ? openaiOptions.logprobs
- ? 0
- : undefined
- : undefined,
- user: openaiOptions.user,
- parallel_tool_calls: openaiOptions.parallelToolCalls,
-
- // standardized settings:
- max_tokens: maxOutputTokens,
- temperature,
- top_p: topP,
- frequency_penalty: frequencyPenalty,
- presence_penalty: presencePenalty,
- response_format:
- responseFormat?.type === 'json'
- ? responseFormat.schema != null
- ? {
- type: 'json_schema',
- json_schema: {
- schema: responseFormat.schema,
- strict: strictJsonSchema,
- name: responseFormat.name ?? 'response',
- description: responseFormat.description,
- },
- }
- : { type: 'json_object' }
- : undefined,
- stop: stopSequences,
- seed,
- verbosity: openaiOptions.textVerbosity,
-
- // openai specific settings:
- // TODO AI SDK 6: remove, we auto-map maxOutputTokens now
- max_completion_tokens: openaiOptions.maxCompletionTokens,
- store: openaiOptions.store,
- metadata: openaiOptions.metadata,
- prediction: openaiOptions.prediction,
- reasoning_effort: openaiOptions.reasoningEffort,
- service_tier: openaiOptions.serviceTier,
- prompt_cache_key: openaiOptions.promptCacheKey,
- prompt_cache_retention: openaiOptions.promptCacheRetention,
- safety_identifier: openaiOptions.safetyIdentifier,
-
- // messages:
- messages,
- };
-
- // remove unsupported settings for reasoning models
- // see https://platform.openai.com/docs/guides/reasoning#limitations
- if (isReasoningModel) {
- // when reasoning effort is none, gpt-5.1 models allow temperature, topP, logprobs
- // https://platform.openai.com/docs/guides/latest-model#gpt-5-1-parameter-compatibility
- if (
- openaiOptions.reasoningEffort !== 'none' ||
- !modelCapabilities.supportsNonReasoningParameters
- ) {
- if (baseArgs.temperature != null) {
- baseArgs.temperature = undefined;
- warnings.push({
- type: 'unsupported',
- feature: 'temperature',
- details: 'temperature is not supported for reasoning models',
- });
- }
- if (baseArgs.top_p != null) {
- baseArgs.top_p = undefined;
- warnings.push({
- type: 'unsupported',
- feature: 'topP',
- details: 'topP is not supported for reasoning models',
- });
- }
- if (baseArgs.logprobs != null) {
- baseArgs.logprobs = undefined;
- warnings.push({
- type: 'other',
- message: 'logprobs is not supported for reasoning models',
- });
- }
- }
-
- if (baseArgs.frequency_penalty != null) {
- baseArgs.frequency_penalty = undefined;
- warnings.push({
- type: 'unsupported',
- feature: 'frequencyPenalty',
- details: 'frequencyPenalty is not supported for reasoning models',
- });
- }
- if (baseArgs.presence_penalty != null) {
- baseArgs.presence_penalty = undefined;
- warnings.push({
- type: 'unsupported',
- feature: 'presencePenalty',
- details: 'presencePenalty is not supported for reasoning models',
- });
- }
- if (baseArgs.logit_bias != null) {
- baseArgs.logit_bias = undefined;
- warnings.push({
- type: 'other',
- message: 'logitBias is not supported for reasoning models',
- });
- }
-
- if (baseArgs.top_logprobs != null) {
- baseArgs.top_logprobs = undefined;
- warnings.push({
- type: 'other',
- message: 'topLogprobs is not supported for reasoning models',
- });
- }
-
- // reasoning models use max_completion_tokens instead of max_tokens:
- if (baseArgs.max_tokens != null) {
- if (baseArgs.max_completion_tokens == null) {
- baseArgs.max_completion_tokens = baseArgs.max_tokens;
- }
- baseArgs.max_tokens = undefined;
- }
- } else if (
- this.modelId.startsWith('gpt-4o-search-preview') ||
- this.modelId.startsWith('gpt-4o-mini-search-preview')
- ) {
- if (baseArgs.temperature != null) {
- baseArgs.temperature = undefined;
- warnings.push({
- type: 'unsupported',
- feature: 'temperature',
- details:
- 'temperature is not supported for the search preview models and has been removed.',
- });
- }
- }
-
- // Validate flex processing support
- if (
- openaiOptions.serviceTier === 'flex' &&
- !modelCapabilities.supportsFlexProcessing
- ) {
- warnings.push({
- type: 'unsupported',
- feature: 'serviceTier',
- details:
- 'flex processing is only available for o3, o4-mini, and gpt-5 models',
- });
- baseArgs.service_tier = undefined;
- }
-
- // Validate priority processing support
- if (
- openaiOptions.serviceTier === 'priority' &&
- !modelCapabilities.supportsPriorityProcessing
- ) {
- warnings.push({
- type: 'unsupported',
- feature: 'serviceTier',
- details:
- 'priority processing is only available for supported models (gpt-4, gpt-5, gpt-5-mini, o3, o4-mini) and requires Enterprise access. gpt-5-nano is not supported',
- });
- baseArgs.service_tier = undefined;
- }
-
- const {
- tools: openaiTools,
- toolChoice: openaiToolChoice,
- toolWarnings,
- } = prepareChatTools({
- tools,
- toolChoice,
- });
-
- return {
- args: {
- ...baseArgs,
- tools: openaiTools,
- tool_choice: openaiToolChoice,
- },
- warnings: [...warnings, ...toolWarnings],
- };
- }
-
- async doGenerate(
- options: LanguageModelV3CallOptions,
- ): Promise {
- const { args: body, warnings } = await this.getArgs(options);
-
- const {
- responseHeaders,
- value: response,
- rawValue: rawResponse,
- } = await postJsonToApi({
- url: this.config.url({
- path: '/chat/completions',
- modelId: this.modelId,
- }),
- headers: combineHeaders(this.config.headers(), options.headers),
- body,
- failedResponseHandler: openaiFailedResponseHandler,
- successfulResponseHandler: createJsonResponseHandler(
- openaiChatResponseSchema,
- ),
- abortSignal: options.abortSignal,
- fetch: this.config.fetch,
- });
-
- const choice = response.choices[0];
- const content: Array = [];
-
- // text content:
- const text = choice.message.content;
- if (text != null && text.length > 0) {
- content.push({ type: 'text', text });
- }
-
- // tool calls:
- for (const toolCall of choice.message.tool_calls ?? []) {
- content.push({
- type: 'tool-call' as const,
- toolCallId: toolCall.id ?? generateId(),
- toolName: toolCall.function.name,
- input: toolCall.function.arguments!,
- });
- }
-
- // annotations/citations:
- for (const annotation of choice.message.annotations ?? []) {
- content.push({
- type: 'source',
- sourceType: 'url',
- id: generateId(),
- url: annotation.url_citation.url,
- title: annotation.url_citation.title,
- });
- }
-
- // provider metadata:
- const completionTokenDetails = response.usage?.completion_tokens_details;
- const promptTokenDetails = response.usage?.prompt_tokens_details;
- const providerMetadata: SharedV3ProviderMetadata = { openai: {} };
- if (completionTokenDetails?.accepted_prediction_tokens != null) {
- providerMetadata.openai.acceptedPredictionTokens =
- completionTokenDetails?.accepted_prediction_tokens;
- }
- if (completionTokenDetails?.rejected_prediction_tokens != null) {
- providerMetadata.openai.rejectedPredictionTokens =
- completionTokenDetails?.rejected_prediction_tokens;
- }
- if (choice.logprobs?.content != null) {
- providerMetadata.openai.logprobs = choice.logprobs.content;
- }
-
- return {
- content,
- finishReason: {
- unified: mapOpenAIFinishReason(choice.finish_reason),
- raw: choice.finish_reason ?? undefined,
- },
- usage: convertOpenAIChatUsage(response.usage),
- request: { body },
- response: {
- ...getResponseMetadata(response),
- headers: responseHeaders,
- body: rawResponse,
- },
- warnings,
- providerMetadata,
- };
- }
-
- async doStream(
- options: LanguageModelV3CallOptions,
- ): Promise {
- const { args, warnings } = await this.getArgs(options);
-
- const body = {
- ...args,
- stream: true,
- stream_options: {
- include_usage: true,
- },
- };
-
- const { responseHeaders, value: response } = await postJsonToApi({
- url: this.config.url({
- path: '/chat/completions',
- modelId: this.modelId,
- }),
- headers: combineHeaders(this.config.headers(), options.headers),
- body,
- failedResponseHandler: openaiFailedResponseHandler,
- successfulResponseHandler: createEventSourceResponseHandler(
- openaiChatChunkSchema,
- ),
- abortSignal: options.abortSignal,
- fetch: this.config.fetch,
- });
-
- const toolCalls: Array<{
- id: string;
- type: 'function';
- function: {
- name: string;
- arguments: string;
- };
- hasFinished: boolean;
- }> = [];
-
- let finishReason: LanguageModelV3FinishReason = {
- unified: 'other',
- raw: undefined,
- };
- let usage: OpenAIChatUsage | undefined = undefined;
- let metadataExtracted = false;
- let isActiveText = false;
-
- const providerMetadata: SharedV3ProviderMetadata = { openai: {} };
-
- return {
- stream: response.pipeThrough(
- new TransformStream<
- ParseResult,
- LanguageModelV3StreamPart
- >({
- start(controller) {
- controller.enqueue({ type: 'stream-start', warnings });
- },
-
- transform(chunk, controller) {
- if (options.includeRawChunks) {
- controller.enqueue({ type: 'raw', rawValue: chunk.rawValue });
- }
-
- // handle failed chunk parsing / validation:
- if (!chunk.success) {
- finishReason = { unified: 'error', raw: undefined };
- controller.enqueue({ type: 'error', error: chunk.error });
- return;
- }
-
- const value = chunk.value;
-
- // handle error chunks:
- if ('error' in value) {
- finishReason = { unified: 'error', raw: undefined };
- controller.enqueue({ type: 'error', error: value.error });
- return;
- }
-
- // extract and emit response metadata once. Usually it comes in the first chunk.
- // Azure may prepend a chunk with a `"prompt_filter_results"` key which does not contain other metadata,
- // https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/content-filter-annotations?tabs=powershell
- if (!metadataExtracted) {
- const metadata = getResponseMetadata(value);
- if (Object.values(metadata).some(Boolean)) {
- metadataExtracted = true;
- controller.enqueue({
- type: 'response-metadata',
- ...getResponseMetadata(value),
- });
- }
- }
-
- if (value.usage != null) {
- usage = value.usage;
-
- if (
- value.usage.completion_tokens_details
- ?.accepted_prediction_tokens != null
- ) {
- providerMetadata.openai.acceptedPredictionTokens =
- value.usage.completion_tokens_details?.accepted_prediction_tokens;
- }
- if (
- value.usage.completion_tokens_details
- ?.rejected_prediction_tokens != null
- ) {
- providerMetadata.openai.rejectedPredictionTokens =
- value.usage.completion_tokens_details?.rejected_prediction_tokens;
- }
- }
-
- const choice = value.choices[0];
-
- if (choice?.finish_reason != null) {
- finishReason = {
- unified: mapOpenAIFinishReason(choice.finish_reason),
- raw: choice.finish_reason,
- };
- }
-
- if (choice?.logprobs?.content != null) {
- providerMetadata.openai.logprobs = choice.logprobs.content;
- }
-
- if (choice?.delta == null) {
- return;
- }
-
- const delta = choice.delta;
-
- if (delta.content != null) {
- if (!isActiveText) {
- controller.enqueue({ type: 'text-start', id: '0' });
- isActiveText = true;
- }
-
- controller.enqueue({
- type: 'text-delta',
- id: '0',
- delta: delta.content,
- });
- }
-
- if (delta.tool_calls != null) {
- for (const toolCallDelta of delta.tool_calls) {
- const index = toolCallDelta.index;
-
- // Tool call start. OpenAI returns all information except the arguments in the first chunk.
- if (toolCalls[index] == null) {
- if (
- toolCallDelta.type != null &&
- toolCallDelta.type !== 'function'
- ) {
- throw new InvalidResponseDataError({
- data: toolCallDelta,
- message: `Expected 'function' type.`,
- });
- }
-
- if (toolCallDelta.id == null) {
- throw new InvalidResponseDataError({
- data: toolCallDelta,
- message: `Expected 'id' to be a string.`,
- });
- }
-
- if (toolCallDelta.function?.name == null) {
- throw new InvalidResponseDataError({
- data: toolCallDelta,
- message: `Expected 'function.name' to be a string.`,
- });
- }
-
- controller.enqueue({
- type: 'tool-input-start',
- id: toolCallDelta.id,
- toolName: toolCallDelta.function.name,
- });
-
- toolCalls[index] = {
- id: toolCallDelta.id,
- type: 'function',
- function: {
- name: toolCallDelta.function.name,
- arguments: toolCallDelta.function.arguments ?? '',
- },
- hasFinished: false,
- };
-
- const toolCall = toolCalls[index];
-
- if (
- toolCall.function?.name != null &&
- toolCall.function?.arguments != null
- ) {
- // send delta if the argument text has already started:
- if (toolCall.function.arguments.length > 0) {
- controller.enqueue({
- type: 'tool-input-delta',
- id: toolCall.id,
- delta: toolCall.function.arguments,
- });
- }
-
- // check if tool call is complete
- // (some providers send the full tool call in one chunk):
- if (isParsableJson(toolCall.function.arguments)) {
- controller.enqueue({
- type: 'tool-input-end',
- id: toolCall.id,
- });
-
- controller.enqueue({
- type: 'tool-call',
- toolCallId: toolCall.id ?? generateId(),
- toolName: toolCall.function.name,
- input: toolCall.function.arguments,
- });
- toolCall.hasFinished = true;
- }
- }
-
- continue;
- }
-
- // existing tool call, merge if not finished
- const toolCall = toolCalls[index];
-
- if (toolCall.hasFinished) {
- continue;
- }
-
- if (toolCallDelta.function?.arguments != null) {
- toolCall.function!.arguments +=
- toolCallDelta.function?.arguments ?? '';
- }
-
- // send delta
- controller.enqueue({
- type: 'tool-input-delta',
- id: toolCall.id,
- delta: toolCallDelta.function.arguments ?? '',
- });
-
- // check if tool call is complete
- if (
- toolCall.function?.name != null &&
- toolCall.function?.arguments != null &&
- isParsableJson(toolCall.function.arguments)
- ) {
- controller.enqueue({
- type: 'tool-input-end',
- id: toolCall.id,
- });
-
- controller.enqueue({
- type: 'tool-call',
- toolCallId: toolCall.id ?? generateId(),
- toolName: toolCall.function.name,
- input: toolCall.function.arguments,
- });
- toolCall.hasFinished = true;
- }
- }
- }
-
- // annotations/citations:
- if (delta.annotations != null) {
- for (const annotation of delta.annotations) {
- controller.enqueue({
- type: 'source',
- sourceType: 'url',
- id: generateId(),
- url: annotation.url_citation.url,
- title: annotation.url_citation.title,
- });
- }
- }
- },
-
- flush(controller) {
- if (isActiveText) {
- controller.enqueue({ type: 'text-end', id: '0' });
- }
-
- controller.enqueue({
- type: 'finish',
- finishReason,
- usage: convertOpenAIChatUsage(usage),
- ...(providerMetadata != null ? { providerMetadata } : {}),
- });
- },
- }),
- ),
- request: { body },
- response: { headers: responseHeaders },
- };
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-options.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-options.ts
deleted file mode 100644
index d876e62e8..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-options.ts
+++ /dev/null
@@ -1,201 +0,0 @@
-import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-// https://platform.openai.com/docs/models
-export type OpenAIChatModelId =
- | 'o1'
- | 'o1-2024-12-17'
- | 'o3-mini'
- | 'o3-mini-2025-01-31'
- | 'o3'
- | 'o3-2025-04-16'
- | 'o4-mini'
- | 'o4-mini-2025-04-16'
- | 'gpt-4.1'
- | 'gpt-4.1-2025-04-14'
- | 'gpt-4.1-mini'
- | 'gpt-4.1-mini-2025-04-14'
- | 'gpt-4.1-nano'
- | 'gpt-4.1-nano-2025-04-14'
- | 'gpt-4o'
- | 'gpt-4o-2024-05-13'
- | 'gpt-4o-2024-08-06'
- | 'gpt-4o-2024-11-20'
- | 'gpt-4o-audio-preview'
- | 'gpt-4o-audio-preview-2024-12-17'
- | 'gpt-4o-audio-preview-2025-06-03'
- | 'gpt-4o-mini'
- | 'gpt-4o-mini-2024-07-18'
- | 'gpt-4o-mini-audio-preview'
- | 'gpt-4o-mini-audio-preview-2024-12-17'
- | 'gpt-4o-search-preview'
- | 'gpt-4o-search-preview-2025-03-11'
- | 'gpt-4o-mini-search-preview'
- | 'gpt-4o-mini-search-preview-2025-03-11'
- | 'gpt-3.5-turbo-0125'
- | 'gpt-3.5-turbo'
- | 'gpt-3.5-turbo-1106'
- | 'gpt-3.5-turbo-16k'
- | 'gpt-5'
- | 'gpt-5-2025-08-07'
- | 'gpt-5-mini'
- | 'gpt-5-mini-2025-08-07'
- | 'gpt-5-nano'
- | 'gpt-5-nano-2025-08-07'
- | 'gpt-5-chat-latest'
- | 'gpt-5.1'
- | 'gpt-5.1-2025-11-13'
- | 'gpt-5.1-chat-latest'
- | 'gpt-5.2'
- | 'gpt-5.2-2025-12-11'
- | 'gpt-5.2-chat-latest'
- | 'gpt-5.2-pro'
- | 'gpt-5.2-pro-2025-12-11'
- | 'gpt-5.3-chat-latest'
- | 'gpt-5.4'
- | 'gpt-5.4-2026-03-05'
- | 'gpt-5.4-mini'
- | 'gpt-5.4-mini-2026-03-17'
- | 'gpt-5.4-nano'
- | 'gpt-5.4-nano-2026-03-17'
- | 'gpt-5.4-pro'
- | 'gpt-5.4-pro-2026-03-05'
- | (string & {});
-
-export const openaiLanguageModelChatOptions = lazySchema(() =>
- zodSchema(
- z.object({
- /**
- * Modify the likelihood of specified tokens appearing in the completion.
- *
- * Accepts a JSON object that maps tokens (specified by their token ID in
- * the GPT tokenizer) to an associated bias value from -100 to 100.
- */
- logitBias: z.record(z.coerce.number(), z.number()).optional(),
-
- /**
- * Return the log probabilities of the tokens.
- *
- * Setting to true will return the log probabilities of the tokens that
- * were generated.
- *
- * Setting to a number will return the log probabilities of the top n
- * tokens that were generated.
- */
- logprobs: z.union([z.boolean(), z.number()]).optional(),
-
- /**
- * Whether to enable parallel function calling during tool use. Default to true.
- */
- parallelToolCalls: z.boolean().optional(),
-
- /**
- * A unique identifier representing your end-user, which can help OpenAI to
- * monitor and detect abuse.
- */
- user: z.string().optional(),
-
- /**
- * Reasoning effort for reasoning models. Defaults to `medium`.
- */
- reasoningEffort: z
- .enum(['none', 'minimal', 'low', 'medium', 'high', 'xhigh'])
- .optional(),
-
- /**
- * Maximum number of completion tokens to generate. Useful for reasoning models.
- */
- maxCompletionTokens: z.number().optional(),
-
- /**
- * Whether to enable persistence in responses API.
- */
- store: z.boolean().optional(),
-
- /**
- * Metadata to associate with the request.
- */
- metadata: z.record(z.string().max(64), z.string().max(512)).optional(),
-
- /**
- * Parameters for prediction mode.
- */
- prediction: z.record(z.string(), z.any()).optional(),
-
- /**
- * Service tier for the request.
- * - 'auto': Default service tier. The request will be processed with the service tier configured in the
- * Project settings. Unless otherwise configured, the Project will use 'default'.
- * - 'flex': 50% cheaper processing at the cost of increased latency. Only available for o3 and o4-mini models.
- * - 'priority': Higher-speed processing with predictably low latency at premium cost. Available for Enterprise customers.
- * - 'default': The request will be processed with the standard pricing and performance for the selected model.
- *
- * @default 'auto'
- */
- serviceTier: z.enum(['auto', 'flex', 'priority', 'default']).optional(),
-
- /**
- * Whether to use strict JSON schema validation.
- *
- * @default true
- */
- strictJsonSchema: z.boolean().optional(),
-
- /**
- * Controls the verbosity of the model's responses.
- * Lower values will result in more concise responses, while higher values will result in more verbose responses.
- */
- textVerbosity: z.enum(['low', 'medium', 'high']).optional(),
-
- /**
- * A cache key for prompt caching. Allows manual control over prompt caching behavior.
- * Useful for improving cache hit rates and working around automatic caching issues.
- */
- promptCacheKey: z.string().optional(),
-
- /**
- * The retention policy for the prompt cache.
- * - 'in_memory': Default. Standard prompt caching behavior.
- * - '24h': Extended prompt caching that keeps cached prefixes active for up to 24 hours.
- * Currently only available for 5.1 series models.
- *
- * @default 'in_memory'
- */
- promptCacheRetention: z.enum(['in_memory', '24h']).optional(),
-
- /**
- * A stable identifier used to help detect users of your application
- * that may be violating OpenAI's usage policies. The IDs should be a
- * string that uniquely identifies each user. We recommend hashing their
- * username or email address, in order to avoid sending us any identifying
- * information.
- */
- safetyIdentifier: z.string().optional(),
-
- /**
- * Override the system message mode for this model.
- * - 'system': Use the 'system' role for system messages (default for most models)
- * - 'developer': Use the 'developer' role for system messages (used by reasoning models)
- * - 'remove': Remove system messages entirely
- *
- * If not specified, the mode is automatically determined based on the model.
- */
- systemMessageMode: z.enum(['system', 'developer', 'remove']).optional(),
-
- /**
- * Force treating this model as a reasoning model.
- *
- * This is useful for "stealth" reasoning models (e.g. via a custom baseURL)
- * where the model ID is not recognized by the SDK's allowlist.
- *
- * When enabled, the SDK applies reasoning-model parameter compatibility rules
- * and defaults `systemMessageMode` to `developer` unless overridden.
- */
- forceReasoning: z.boolean().optional(),
- }),
- ),
-);
-
-export type OpenAILanguageModelChatOptions = InferSchema<
- typeof openaiLanguageModelChatOptions
->;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-prepare-tools.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-prepare-tools.ts
deleted file mode 100644
index 9080896fe..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-prepare-tools.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import {
- LanguageModelV3CallOptions,
- SharedV3Warning,
- UnsupportedFunctionalityError,
-} from '@ai-sdk/provider';
-import {
- OpenAIChatToolChoice,
- OpenAIChatFunctionTool,
-} from './openai-chat-api';
-
-export function prepareChatTools({
- tools,
- toolChoice,
-}: {
- tools: LanguageModelV3CallOptions['tools'];
- toolChoice?: LanguageModelV3CallOptions['toolChoice'];
-}): {
- tools?: OpenAIChatFunctionTool[];
- toolChoice?: OpenAIChatToolChoice;
- toolWarnings: Array;
-} {
- // when the tools array is empty, change it to undefined to prevent errors:
- tools = tools?.length ? tools : undefined;
-
- const toolWarnings: SharedV3Warning[] = [];
-
- if (tools == null) {
- return { tools: undefined, toolChoice: undefined, toolWarnings };
- }
-
- const openaiTools: OpenAIChatFunctionTool[] = [];
-
- for (const tool of tools) {
- switch (tool.type) {
- case 'function':
- openaiTools.push({
- type: 'function',
- function: {
- name: tool.name,
- description: tool.description,
- parameters: tool.inputSchema,
- ...(tool.strict != null ? { strict: tool.strict } : {}),
- },
- });
- break;
- default:
- toolWarnings.push({
- type: 'unsupported',
- feature: `tool type: ${tool.type}`,
- });
- break;
- }
- }
-
- if (toolChoice == null) {
- return { tools: openaiTools, toolChoice: undefined, toolWarnings };
- }
-
- const type = toolChoice.type;
-
- switch (type) {
- case 'auto':
- case 'none':
- case 'required':
- return { tools: openaiTools, toolChoice: type, toolWarnings };
- case 'tool':
- return {
- tools: openaiTools,
- toolChoice: {
- type: 'function',
- function: {
- name: toolChoice.toolName,
- },
- },
- toolWarnings,
- };
- default: {
- const _exhaustiveCheck: never = type;
- throw new UnsupportedFunctionalityError({
- functionality: `tool choice type: ${_exhaustiveCheck}`,
- });
- }
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-prompt.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-prompt.ts
deleted file mode 100644
index 379530416..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/chat/openai-chat-prompt.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-export type OpenAIChatPrompt = Array;
-
-export type ChatCompletionMessage =
- | ChatCompletionSystemMessage
- | ChatCompletionDeveloperMessage
- | ChatCompletionUserMessage
- | ChatCompletionAssistantMessage
- | ChatCompletionToolMessage;
-
-export interface ChatCompletionSystemMessage {
- role: 'system';
- content: string;
-}
-
-export interface ChatCompletionDeveloperMessage {
- role: 'developer';
- content: string;
-}
-
-export interface ChatCompletionUserMessage {
- role: 'user';
- content: string | Array;
-}
-
-export type ChatCompletionContentPart =
- | ChatCompletionContentPartText
- | ChatCompletionContentPartImage
- | ChatCompletionContentPartInputAudio
- | ChatCompletionContentPartFile;
-
-export interface ChatCompletionContentPartText {
- type: 'text';
- text: string;
-}
-
-export interface ChatCompletionContentPartImage {
- type: 'image_url';
- image_url: { url: string };
-}
-
-export interface ChatCompletionContentPartInputAudio {
- type: 'input_audio';
- input_audio: { data: string; format: 'wav' | 'mp3' };
-}
-
-export interface ChatCompletionContentPartFile {
- type: 'file';
- file: { filename: string; file_data: string } | { file_id: string };
-}
-
-export interface ChatCompletionAssistantMessage {
- role: 'assistant';
- content?: string | null;
- tool_calls?: Array;
-}
-
-export interface ChatCompletionMessageToolCall {
- type: 'function';
- id: string;
- function: {
- arguments: string;
- name: string;
- };
-}
-
-export interface ChatCompletionToolMessage {
- role: 'tool';
- content: string;
- tool_call_id: string;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/convert-openai-completion-usage.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/convert-openai-completion-usage.ts
deleted file mode 100644
index 3b4dc14df..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/convert-openai-completion-usage.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { LanguageModelV3Usage } from '@ai-sdk/provider';
-
-export type OpenAICompletionUsage = {
- prompt_tokens?: number | null;
- completion_tokens?: number | null;
- total_tokens?: number | null;
-};
-
-export function convertOpenAICompletionUsage(
- usage: OpenAICompletionUsage | undefined | null,
-): LanguageModelV3Usage {
- if (usage == null) {
- return {
- inputTokens: {
- total: undefined,
- noCache: undefined,
- cacheRead: undefined,
- cacheWrite: undefined,
- },
- outputTokens: {
- total: undefined,
- text: undefined,
- reasoning: undefined,
- },
- raw: undefined,
- };
- }
-
- const promptTokens = usage.prompt_tokens ?? 0;
- const completionTokens = usage.completion_tokens ?? 0;
-
- return {
- inputTokens: {
- total: usage.prompt_tokens ?? undefined,
- noCache: promptTokens,
- cacheRead: undefined,
- cacheWrite: undefined,
- },
- outputTokens: {
- total: usage.completion_tokens ?? undefined,
- text: completionTokens,
- reasoning: undefined,
- },
- raw: usage,
- };
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/convert-to-openai-completion-prompt.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/convert-to-openai-completion-prompt.ts
deleted file mode 100644
index ed67f480d..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/convert-to-openai-completion-prompt.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-import {
- InvalidPromptError,
- LanguageModelV3Prompt,
- UnsupportedFunctionalityError,
-} from '@ai-sdk/provider';
-
-export function convertToOpenAICompletionPrompt({
- prompt,
- user = 'user',
- assistant = 'assistant',
-}: {
- prompt: LanguageModelV3Prompt;
- user?: string;
- assistant?: string;
-}): {
- prompt: string;
- stopSequences?: string[];
-} {
- // transform to a chat message format:
- let text = '';
-
- // if first message is a system message, add it to the text:
- if (prompt[0].role === 'system') {
- text += `${prompt[0].content}\n\n`;
- prompt = prompt.slice(1);
- }
-
- for (const { role, content } of prompt) {
- switch (role) {
- case 'system': {
- throw new InvalidPromptError({
- message: 'Unexpected system message in prompt: ${content}',
- prompt,
- });
- }
-
- case 'user': {
- const userMessage = content
- .map(part => {
- switch (part.type) {
- case 'text': {
- return part.text;
- }
- }
- })
- .filter(Boolean)
- .join('');
-
- text += `${user}:\n${userMessage}\n\n`;
- break;
- }
-
- case 'assistant': {
- const assistantMessage = content
- .map(part => {
- switch (part.type) {
- case 'text': {
- return part.text;
- }
- case 'tool-call': {
- throw new UnsupportedFunctionalityError({
- functionality: 'tool-call messages',
- });
- }
- }
- })
- .join('');
-
- text += `${assistant}:\n${assistantMessage}\n\n`;
- break;
- }
-
- case 'tool': {
- throw new UnsupportedFunctionalityError({
- functionality: 'tool messages',
- });
- }
-
- default: {
- const _exhaustiveCheck: never = role;
- throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
- }
- }
- }
-
- // Assistant message prefix:
- text += `${assistant}:\n`;
-
- return {
- prompt: text,
- stopSequences: [`\n${user}:`],
- };
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/get-response-metadata.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/get-response-metadata.ts
deleted file mode 100644
index bd358b23f..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/get-response-metadata.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-export function getResponseMetadata({
- id,
- model,
- created,
-}: {
- id?: string | undefined | null;
- created?: number | undefined | null;
- model?: string | undefined | null;
-}) {
- return {
- id: id ?? undefined,
- modelId: model ?? undefined,
- timestamp: created != null ? new Date(created * 1000) : undefined,
- };
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/map-openai-finish-reason.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/map-openai-finish-reason.ts
deleted file mode 100644
index f3005bb8d..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/map-openai-finish-reason.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { LanguageModelV3FinishReason } from '@ai-sdk/provider';
-
-export function mapOpenAIFinishReason(
- finishReason: string | null | undefined,
-): LanguageModelV3FinishReason['unified'] {
- switch (finishReason) {
- case 'stop':
- return 'stop';
- case 'length':
- return 'length';
- case 'content_filter':
- return 'content-filter';
- case 'function_call':
- case 'tool_calls':
- return 'tool-calls';
- default:
- return 'other';
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/openai-completion-api.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/openai-completion-api.ts
deleted file mode 100644
index 312ab046c..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/openai-completion-api.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import { z } from 'zod/v4';
-import { openaiErrorDataSchema } from '../openai-error';
-import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-
-// limited version of the schema, focussed on what is needed for the implementation
-// this approach limits breakages when the API changes and increases efficiency
-export const openaiCompletionResponseSchema = lazySchema(() =>
- zodSchema(
- z.object({
- id: z.string().nullish(),
- created: z.number().nullish(),
- model: z.string().nullish(),
- choices: z.array(
- z.object({
- text: z.string(),
- finish_reason: z.string(),
- logprobs: z
- .object({
- tokens: z.array(z.string()),
- token_logprobs: z.array(z.number()),
- top_logprobs: z.array(z.record(z.string(), z.number())).nullish(),
- })
- .nullish(),
- }),
- ),
- usage: z
- .object({
- prompt_tokens: z.number(),
- completion_tokens: z.number(),
- total_tokens: z.number(),
- })
- .nullish(),
- }),
- ),
-);
-
-// limited version of the schema, focussed on what is needed for the implementation
-// this approach limits breakages when the API changes and increases efficiency
-export const openaiCompletionChunkSchema = lazySchema(() =>
- zodSchema(
- z.union([
- z.object({
- id: z.string().nullish(),
- created: z.number().nullish(),
- model: z.string().nullish(),
- choices: z.array(
- z.object({
- text: z.string(),
- finish_reason: z.string().nullish(),
- index: z.number(),
- logprobs: z
- .object({
- tokens: z.array(z.string()),
- token_logprobs: z.array(z.number()),
- top_logprobs: z
- .array(z.record(z.string(), z.number()))
- .nullish(),
- })
- .nullish(),
- }),
- ),
- usage: z
- .object({
- prompt_tokens: z.number(),
- completion_tokens: z.number(),
- total_tokens: z.number(),
- })
- .nullish(),
- }),
- openaiErrorDataSchema,
- ]),
- ),
-);
-
-export type OpenAICompletionChunk = InferSchema<
- typeof openaiCompletionChunkSchema
->;
-
-export type OpenAICompletionResponse = InferSchema<
- typeof openaiCompletionResponseSchema
->;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/openai-completion-language-model.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/openai-completion-language-model.ts
deleted file mode 100644
index 836b30634..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/openai-completion-language-model.ts
+++ /dev/null
@@ -1,336 +0,0 @@
-import {
- LanguageModelV3,
- LanguageModelV3CallOptions,
- LanguageModelV3FinishReason,
- LanguageModelV3GenerateResult,
- LanguageModelV3StreamPart,
- LanguageModelV3StreamResult,
- SharedV3ProviderMetadata,
- SharedV3Warning,
-} from '@ai-sdk/provider';
-import {
- combineHeaders,
- createEventSourceResponseHandler,
- createJsonResponseHandler,
- FetchFunction,
- parseProviderOptions,
- ParseResult,
- postJsonToApi,
-} from '@ai-sdk/provider-utils';
-import { openaiFailedResponseHandler } from '../openai-error';
-import {
- convertOpenAICompletionUsage,
- OpenAICompletionUsage,
-} from './convert-openai-completion-usage';
-import { convertToOpenAICompletionPrompt } from './convert-to-openai-completion-prompt';
-import { getResponseMetadata } from './get-response-metadata';
-import { mapOpenAIFinishReason } from './map-openai-finish-reason';
-import {
- OpenAICompletionChunk,
- openaiCompletionChunkSchema,
- openaiCompletionResponseSchema,
-} from './openai-completion-api';
-import {
- OpenAICompletionModelId,
- openaiLanguageModelCompletionOptions,
-} from './openai-completion-options';
-
-type OpenAICompletionConfig = {
- provider: string;
- headers: () => Record;
- url: (options: { modelId: string; path: string }) => string;
- fetch?: FetchFunction;
-};
-
-export class OpenAICompletionLanguageModel implements LanguageModelV3 {
- readonly specificationVersion = 'v3';
-
- readonly modelId: OpenAICompletionModelId;
-
- private readonly config: OpenAICompletionConfig;
-
- private get providerOptionsName(): string {
- return this.config.provider.split('.')[0].trim();
- }
-
- constructor(
- modelId: OpenAICompletionModelId,
- config: OpenAICompletionConfig,
- ) {
- this.modelId = modelId;
- this.config = config;
- }
-
- get provider(): string {
- return this.config.provider;
- }
-
- readonly supportedUrls: Record = {
- // No URLs are supported for completion models.
- };
-
- private async getArgs({
- prompt,
- maxOutputTokens,
- temperature,
- topP,
- topK,
- frequencyPenalty,
- presencePenalty,
- stopSequences: userStopSequences,
- responseFormat,
- tools,
- toolChoice,
- seed,
- providerOptions,
- }: LanguageModelV3CallOptions) {
- const warnings: SharedV3Warning[] = [];
-
- // Parse provider options
- const openaiOptions = {
- ...(await parseProviderOptions({
- provider: 'openai',
- providerOptions,
- schema: openaiLanguageModelCompletionOptions,
- })),
- ...(await parseProviderOptions({
- provider: this.providerOptionsName,
- providerOptions,
- schema: openaiLanguageModelCompletionOptions,
- })),
- };
-
- if (topK != null) {
- warnings.push({ type: 'unsupported', feature: 'topK' });
- }
-
- if (tools?.length) {
- warnings.push({ type: 'unsupported', feature: 'tools' });
- }
-
- if (toolChoice != null) {
- warnings.push({ type: 'unsupported', feature: 'toolChoice' });
- }
-
- if (responseFormat != null && responseFormat.type !== 'text') {
- warnings.push({
- type: 'unsupported',
- feature: 'responseFormat',
- details: 'JSON response format is not supported.',
- });
- }
-
- const { prompt: completionPrompt, stopSequences } =
- convertToOpenAICompletionPrompt({ prompt });
-
- const stop = [...(stopSequences ?? []), ...(userStopSequences ?? [])];
-
- return {
- args: {
- // model id:
- model: this.modelId,
-
- // model specific settings:
- echo: openaiOptions.echo,
- logit_bias: openaiOptions.logitBias,
- logprobs:
- openaiOptions?.logprobs === true
- ? 0
- : openaiOptions?.logprobs === false
- ? undefined
- : openaiOptions?.logprobs,
- suffix: openaiOptions.suffix,
- user: openaiOptions.user,
-
- // standardized settings:
- max_tokens: maxOutputTokens,
- temperature,
- top_p: topP,
- frequency_penalty: frequencyPenalty,
- presence_penalty: presencePenalty,
- seed,
-
- // prompt:
- prompt: completionPrompt,
-
- // stop sequences:
- stop: stop.length > 0 ? stop : undefined,
- },
- warnings,
- };
- }
-
- async doGenerate(
- options: LanguageModelV3CallOptions,
- ): Promise {
- const { args, warnings } = await this.getArgs(options);
-
- const {
- responseHeaders,
- value: response,
- rawValue: rawResponse,
- } = await postJsonToApi({
- url: this.config.url({
- path: '/completions',
- modelId: this.modelId,
- }),
- headers: combineHeaders(this.config.headers(), options.headers),
- body: args,
- failedResponseHandler: openaiFailedResponseHandler,
- successfulResponseHandler: createJsonResponseHandler(
- openaiCompletionResponseSchema,
- ),
- abortSignal: options.abortSignal,
- fetch: this.config.fetch,
- });
-
- const choice = response.choices[0];
-
- const providerMetadata: SharedV3ProviderMetadata = { openai: {} };
-
- if (choice.logprobs != null) {
- providerMetadata.openai.logprobs = choice.logprobs;
- }
-
- return {
- content: [{ type: 'text', text: choice.text }],
- usage: convertOpenAICompletionUsage(response.usage),
- finishReason: {
- unified: mapOpenAIFinishReason(choice.finish_reason),
- raw: choice.finish_reason ?? undefined,
- },
- request: { body: args },
- response: {
- ...getResponseMetadata(response),
- headers: responseHeaders,
- body: rawResponse,
- },
- providerMetadata,
- warnings,
- };
- }
-
- async doStream(
- options: LanguageModelV3CallOptions,
- ): Promise {
- const { args, warnings } = await this.getArgs(options);
-
- const body = {
- ...args,
- stream: true,
-
- stream_options: {
- include_usage: true,
- },
- };
-
- const { responseHeaders, value: response } = await postJsonToApi({
- url: this.config.url({
- path: '/completions',
- modelId: this.modelId,
- }),
- headers: combineHeaders(this.config.headers(), options.headers),
- body,
- failedResponseHandler: openaiFailedResponseHandler,
- successfulResponseHandler: createEventSourceResponseHandler(
- openaiCompletionChunkSchema,
- ),
- abortSignal: options.abortSignal,
- fetch: this.config.fetch,
- });
-
- let finishReason: LanguageModelV3FinishReason = {
- unified: 'other',
- raw: undefined,
- };
- const providerMetadata: SharedV3ProviderMetadata = { openai: {} };
- let usage: OpenAICompletionUsage | undefined = undefined;
- let isFirstChunk = true;
-
- return {
- stream: response.pipeThrough(
- new TransformStream<
- ParseResult,
- LanguageModelV3StreamPart
- >({
- start(controller) {
- controller.enqueue({ type: 'stream-start', warnings });
- },
-
- transform(chunk, controller) {
- if (options.includeRawChunks) {
- controller.enqueue({ type: 'raw', rawValue: chunk.rawValue });
- }
-
- // handle failed chunk parsing / validation:
- if (!chunk.success) {
- finishReason = { unified: 'error', raw: undefined };
- controller.enqueue({ type: 'error', error: chunk.error });
- return;
- }
-
- const value = chunk.value;
-
- // handle error chunks:
- if ('error' in value) {
- finishReason = { unified: 'error', raw: undefined };
- controller.enqueue({ type: 'error', error: value.error });
- return;
- }
-
- if (isFirstChunk) {
- isFirstChunk = false;
-
- controller.enqueue({
- type: 'response-metadata',
- ...getResponseMetadata(value),
- });
-
- controller.enqueue({ type: 'text-start', id: '0' });
- }
-
- if (value.usage != null) {
- usage = value.usage;
- }
-
- const choice = value.choices[0];
-
- if (choice?.finish_reason != null) {
- finishReason = {
- unified: mapOpenAIFinishReason(choice.finish_reason),
- raw: choice.finish_reason,
- };
- }
-
- if (choice?.logprobs != null) {
- providerMetadata.openai.logprobs = choice.logprobs;
- }
-
- if (choice?.text != null && choice.text.length > 0) {
- controller.enqueue({
- type: 'text-delta',
- id: '0',
- delta: choice.text,
- });
- }
- },
-
- flush(controller) {
- if (!isFirstChunk) {
- controller.enqueue({ type: 'text-end', id: '0' });
- }
-
- controller.enqueue({
- type: 'finish',
- finishReason,
- providerMetadata,
- usage: convertOpenAICompletionUsage(usage),
- });
- },
- }),
- ),
- request: { body },
- response: { headers: responseHeaders },
- };
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/openai-completion-options.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/openai-completion-options.ts
deleted file mode 100644
index a936f3b39..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/completion/openai-completion-options.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-// https://platform.openai.com/docs/models
-export type OpenAICompletionModelId =
- | 'gpt-3.5-turbo-instruct'
- | 'gpt-3.5-turbo-instruct-0914'
- | (string & {});
-
-export const openaiLanguageModelCompletionOptions = lazySchema(() =>
- zodSchema(
- z.object({
- /**
- * Echo back the prompt in addition to the completion.
- */
- echo: z.boolean().optional(),
-
- /**
- * Modify the likelihood of specified tokens appearing in the completion.
- *
- * Accepts a JSON object that maps tokens (specified by their token ID in
- * the GPT tokenizer) to an associated bias value from -100 to 100. You
- * can use this tokenizer tool to convert text to token IDs. Mathematically,
- * the bias is added to the logits generated by the model prior to sampling.
- * The exact effect will vary per model, but values between -1 and 1 should
- * decrease or increase likelihood of selection; values like -100 or 100
- * should result in a ban or exclusive selection of the relevant token.
- *
- * As an example, you can pass {"50256": -100} to prevent the <|endoftext|>
- * token from being generated.
- */
- logitBias: z.record(z.string(), z.number()).optional(),
-
- /**
- * The suffix that comes after a completion of inserted text.
- */
- suffix: z.string().optional(),
-
- /**
- * A unique identifier representing your end-user, which can help OpenAI to
- * monitor and detect abuse. Learn more.
- */
- user: z.string().optional(),
-
- /**
- * Return the log probabilities of the tokens. Including logprobs will increase
- * the response size and can slow down response times. However, it can
- * be useful to better understand how the model is behaving.
- * Setting to true will return the log probabilities of the tokens that
- * were generated.
- * Setting to a number will return the log probabilities of the top n
- * tokens that were generated.
- */
- logprobs: z.union([z.boolean(), z.number()]).optional(),
- }),
- ),
-);
-
-export type OpenAILanguageModelCompletionOptions = InferSchema<
- typeof openaiLanguageModelCompletionOptions
->;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/embedding/openai-embedding-api.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/embedding/openai-embedding-api.ts
deleted file mode 100644
index 87ab6c106..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/embedding/openai-embedding-api.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-// minimal version of the schema, focussed on what is needed for the implementation
-// this approach limits breakages when the API changes and increases efficiency
-export const openaiTextEmbeddingResponseSchema = lazySchema(() =>
- zodSchema(
- z.object({
- data: z.array(z.object({ embedding: z.array(z.number()) })),
- usage: z.object({ prompt_tokens: z.number() }).nullish(),
- }),
- ),
-);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/embedding/openai-embedding-model.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/embedding/openai-embedding-model.ts
deleted file mode 100644
index a1e2c7615..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/embedding/openai-embedding-model.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-import {
- EmbeddingModelV3,
- TooManyEmbeddingValuesForCallError,
-} from '@ai-sdk/provider';
-import {
- combineHeaders,
- createJsonResponseHandler,
- parseProviderOptions,
- postJsonToApi,
-} from '@ai-sdk/provider-utils';
-import { OpenAIConfig } from '../openai-config';
-import { openaiFailedResponseHandler } from '../openai-error';
-import {
- OpenAIEmbeddingModelId,
- openaiEmbeddingModelOptions,
-} from './openai-embedding-options';
-import { openaiTextEmbeddingResponseSchema } from './openai-embedding-api';
-
-export class OpenAIEmbeddingModel implements EmbeddingModelV3 {
- readonly specificationVersion = 'v3';
- readonly modelId: OpenAIEmbeddingModelId;
- readonly maxEmbeddingsPerCall = 2048;
- readonly supportsParallelCalls = true;
-
- private readonly config: OpenAIConfig;
-
- get provider(): string {
- return this.config.provider;
- }
-
- constructor(modelId: OpenAIEmbeddingModelId, config: OpenAIConfig) {
- this.modelId = modelId;
- this.config = config;
- }
-
- async doEmbed({
- values,
- headers,
- abortSignal,
- providerOptions,
- }: Parameters[0]): Promise<
- Awaited>
- > {
- if (values.length > this.maxEmbeddingsPerCall) {
- throw new TooManyEmbeddingValuesForCallError({
- provider: this.provider,
- modelId: this.modelId,
- maxEmbeddingsPerCall: this.maxEmbeddingsPerCall,
- values,
- });
- }
-
- // Parse provider options
- const openaiOptions =
- (await parseProviderOptions({
- provider: 'openai',
- providerOptions,
- schema: openaiEmbeddingModelOptions,
- })) ?? {};
-
- const {
- responseHeaders,
- value: response,
- rawValue,
- } = await postJsonToApi({
- url: this.config.url({
- path: '/embeddings',
- modelId: this.modelId,
- }),
- headers: combineHeaders(this.config.headers(), headers),
- body: {
- model: this.modelId,
- input: values,
- encoding_format: 'float',
- dimensions: openaiOptions.dimensions,
- user: openaiOptions.user,
- },
- failedResponseHandler: openaiFailedResponseHandler,
- successfulResponseHandler: createJsonResponseHandler(
- openaiTextEmbeddingResponseSchema,
- ),
- abortSignal,
- fetch: this.config.fetch,
- });
-
- return {
- warnings: [],
- embeddings: response.data.map(item => item.embedding),
- usage: response.usage
- ? { tokens: response.usage.prompt_tokens }
- : undefined,
- response: { headers: responseHeaders, body: rawValue },
- };
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/embedding/openai-embedding-options.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/embedding/openai-embedding-options.ts
deleted file mode 100644
index 54d7ff077..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/embedding/openai-embedding-options.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export type OpenAIEmbeddingModelId =
- | 'text-embedding-3-small'
- | 'text-embedding-3-large'
- | 'text-embedding-ada-002'
- | (string & {});
-
-export const openaiEmbeddingModelOptions = lazySchema(() =>
- zodSchema(
- z.object({
- /**
- * The number of dimensions the resulting output embeddings should have.
- * Only supported in text-embedding-3 and later models.
- */
- dimensions: z.number().optional(),
-
- /**
- * A unique identifier representing your end-user, which can help OpenAI to
- * monitor and detect abuse. Learn more.
- */
- user: z.string().optional(),
- }),
- ),
-);
-
-export type OpenAIEmbeddingModelOptions = InferSchema<
- typeof openaiEmbeddingModelOptions
->;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/image/openai-image-api.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/image/openai-image-api.ts
deleted file mode 100644
index de779ca46..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/image/openai-image-api.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-// minimal version of the schema, focused on what is needed for the implementation
-// this approach limits breakages when the API changes and increases efficiency
-export const openaiImageResponseSchema = lazySchema(() =>
- zodSchema(
- z.object({
- created: z.number().nullish(),
- data: z.array(
- z.object({
- b64_json: z.string(),
- revised_prompt: z.string().nullish(),
- }),
- ),
- background: z.string().nullish(),
- output_format: z.string().nullish(),
- size: z.string().nullish(),
- quality: z.string().nullish(),
- usage: z
- .object({
- input_tokens: z.number().nullish(),
- output_tokens: z.number().nullish(),
- total_tokens: z.number().nullish(),
- input_tokens_details: z
- .object({
- image_tokens: z.number().nullish(),
- text_tokens: z.number().nullish(),
- })
- .nullish(),
- })
- .nullish(),
- }),
- ),
-);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/image/openai-image-model.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/image/openai-image-model.ts
deleted file mode 100644
index d456d6398..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/image/openai-image-model.ts
+++ /dev/null
@@ -1,349 +0,0 @@
-import {
- ImageModelV3,
- ImageModelV3File,
- SharedV3Warning,
-} from '@ai-sdk/provider';
-import {
- combineHeaders,
- convertBase64ToUint8Array,
- convertToFormData,
- createJsonResponseHandler,
- downloadBlob,
- postFormDataToApi,
- postJsonToApi,
-} from '@ai-sdk/provider-utils';
-import { OpenAIConfig } from '../openai-config';
-import { openaiFailedResponseHandler } from '../openai-error';
-import { openaiImageResponseSchema } from './openai-image-api';
-import {
- OpenAIImageModelId,
- hasDefaultResponseFormat,
- modelMaxImagesPerCall,
-} from './openai-image-options';
-
-interface OpenAIImageModelConfig extends OpenAIConfig {
- _internal?: {
- currentDate?: () => Date;
- };
-}
-
-export class OpenAIImageModel implements ImageModelV3 {
- readonly specificationVersion = 'v3';
-
- get maxImagesPerCall(): number {
- return modelMaxImagesPerCall[this.modelId] ?? 1;
- }
-
- get provider(): string {
- return this.config.provider;
- }
-
- constructor(
- readonly modelId: OpenAIImageModelId,
- private readonly config: OpenAIImageModelConfig,
- ) {}
-
- async doGenerate({
- prompt,
- files,
- mask,
- n,
- size,
- aspectRatio,
- seed,
- providerOptions,
- headers,
- abortSignal,
- }: Parameters[0]): Promise<
- Awaited>
- > {
- const warnings: Array = [];
-
- if (aspectRatio != null) {
- warnings.push({
- type: 'unsupported',
- feature: 'aspectRatio',
- details:
- 'This model does not support aspect ratio. Use `size` instead.',
- });
- }
-
- if (seed != null) {
- warnings.push({ type: 'unsupported', feature: 'seed' });
- }
-
- const currentDate = this.config._internal?.currentDate?.() ?? new Date();
-
- if (files != null) {
- const { value: response, responseHeaders } = await postFormDataToApi({
- url: this.config.url({
- path: '/images/edits',
- modelId: this.modelId,
- }),
- headers: combineHeaders(this.config.headers(), headers),
- formData: convertToFormData({
- model: this.modelId,
- prompt,
- image: await Promise.all(
- files.map(file =>
- file.type === 'file'
- ? new Blob(
- [
- file.data instanceof Uint8Array
- ? new Blob([file.data as BlobPart], {
- type: file.mediaType,
- })
- : new Blob([convertBase64ToUint8Array(file.data)], {
- type: file.mediaType,
- }),
- ],
- { type: file.mediaType },
- )
- : downloadBlob(file.url),
- ),
- ),
- mask: mask != null ? await fileToBlob(mask) : undefined,
- n,
- size,
- ...(providerOptions.openai ?? {}),
- }),
- failedResponseHandler: openaiFailedResponseHandler,
- successfulResponseHandler: createJsonResponseHandler(
- openaiImageResponseSchema,
- ),
- abortSignal,
- fetch: this.config.fetch,
- });
-
- return {
- images: response.data.map(item => item.b64_json),
- warnings,
- usage:
- response.usage != null
- ? {
- inputTokens: response.usage.input_tokens ?? undefined,
- outputTokens: response.usage.output_tokens ?? undefined,
- totalTokens: response.usage.total_tokens ?? undefined,
- }
- : undefined,
- response: {
- timestamp: currentDate,
- modelId: this.modelId,
- headers: responseHeaders,
- },
- providerMetadata: {
- openai: {
- images: response.data.map((item, index) => ({
- ...(item.revised_prompt
- ? { revisedPrompt: item.revised_prompt }
- : {}),
- created: response.created ?? undefined,
- size: response.size ?? undefined,
- quality: response.quality ?? undefined,
- background: response.background ?? undefined,
- outputFormat: response.output_format ?? undefined,
- ...distributeTokenDetails(
- response.usage?.input_tokens_details,
- index,
- response.data.length,
- ),
- })),
- },
- },
- };
- }
-
- const { value: response, responseHeaders } = await postJsonToApi({
- url: this.config.url({
- path: '/images/generations',
- modelId: this.modelId,
- }),
- headers: combineHeaders(this.config.headers(), headers),
- body: {
- model: this.modelId,
- prompt,
- n,
- size,
- ...(providerOptions.openai ?? {}),
- ...(!hasDefaultResponseFormat(this.modelId)
- ? { response_format: 'b64_json' }
- : {}),
- },
- failedResponseHandler: openaiFailedResponseHandler,
- successfulResponseHandler: createJsonResponseHandler(
- openaiImageResponseSchema,
- ),
- abortSignal,
- fetch: this.config.fetch,
- });
-
- return {
- images: response.data.map(item => item.b64_json),
- warnings,
- usage:
- response.usage != null
- ? {
- inputTokens: response.usage.input_tokens ?? undefined,
- outputTokens: response.usage.output_tokens ?? undefined,
- totalTokens: response.usage.total_tokens ?? undefined,
- }
- : undefined,
- response: {
- timestamp: currentDate,
- modelId: this.modelId,
- headers: responseHeaders,
- },
- providerMetadata: {
- openai: {
- images: response.data.map((item, index) => ({
- ...(item.revised_prompt
- ? { revisedPrompt: item.revised_prompt }
- : {}),
- created: response.created ?? undefined,
- size: response.size ?? undefined,
- quality: response.quality ?? undefined,
- background: response.background ?? undefined,
- outputFormat: response.output_format ?? undefined,
- ...distributeTokenDetails(
- response.usage?.input_tokens_details,
- index,
- response.data.length,
- ),
- })),
- },
- },
- };
- }
-}
-
-/**
- * Distributes input token details evenly across images, with the remainder
- * assigned to the last image so that summing across all entries gives the
- * exact total.
- */
-function distributeTokenDetails(
- details:
- | { image_tokens?: number | null; text_tokens?: number | null }
- | null
- | undefined,
- index: number,
- total: number,
-): { imageTokens?: number; textTokens?: number } {
- if (details == null) {
- return {};
- }
-
- const result: { imageTokens?: number; textTokens?: number } = {};
-
- if (details.image_tokens != null) {
- const base = Math.floor(details.image_tokens / total);
- const remainder = details.image_tokens - base * (total - 1);
- result.imageTokens = index === total - 1 ? remainder : base;
- }
-
- if (details.text_tokens != null) {
- const base = Math.floor(details.text_tokens / total);
- const remainder = details.text_tokens - base * (total - 1);
- result.textTokens = index === total - 1 ? remainder : base;
- }
-
- return result;
-}
-
-type OpenAIImageEditInput = {
- /**
- * Allows to set transparency for the background of the generated image(s).
- * This parameter is only supported for `gpt-image-1`. Must be one of
- * `transparent`, `opaque` or `auto` (default value). When `auto` is used, the
- * model will automatically determine the best background for the image.
- *
- * If `transparent`, the output format needs to support transparency, so it
- * should be set to either `png` (default value) or `webp`.
- *
- */
- background?: 'transparent' | 'opaque' | 'auto';
- /**
- * The image(s) to edit. Must be a supported image file or an array of images.
- *
- * For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less
- * than 50MB. You can provide up to 16 images.
- *
- * For `dall-e-2`, you can only provide one image, and it should be a square
- * `png` file less than 4MB.
- *
- */
- image: Blob | Blob[];
- input_fidelity?: ('high' | 'low') | null;
- /**
- * An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where `image` should be edited. If there are multiple images provided, the mask will be applied on the first image. Must be a valid PNG file, less than 4MB, and have the same dimensions as `image`.
- */
- mask?: Blob;
- /**
- * The model to use for image generation. Only `dall-e-2` and `gpt-image-1` are supported. Defaults to `dall-e-2` unless a parameter specific to `gpt-image-1` is used.
- */
- model?: 'dall-e-2' | 'gpt-image-1' | 'gpt-image-1-mini' | (string & {});
- /**
- * The number of images to generate. Must be between 1 and 10.
- */
- n?: number;
- /**
- * The compression level (0-100%) for the generated images. This parameter
- * is only supported for `gpt-image-1` with the `webp` or `jpeg` output
- * formats, and defaults to 100.
- *
- */
- output_compression?: number;
- /**
- * The format in which the generated images are returned. This parameter is
- * only supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`.
- * The default value is `png`.
- *
- */
- output_format?: 'png' | 'jpeg' | 'webp';
- partial_images?: number | null;
- /**
- * A text description of the desired image(s). The maximum length is 1000 characters for `dall-e-2`, and 32000 characters for `gpt-image-1`.
- */
- prompt?: string;
- /**
- * The quality of the image that will be generated. `high`, `medium` and `low` are only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality. Defaults to `auto`.
- *
- */
- quality?: 'standard' | 'low' | 'medium' | 'high' | 'auto';
- /**
- * The format in which the generated images are returned. Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the image has been generated. This parameter is only supported for `dall-e-2`, as `gpt-image-1` will always return base64-encoded images.
- */
- response_format?: 'url' | 'b64_json';
- /**
- * The size of the generated images. Must be one of `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto` (default value) for `gpt-image-1`, and one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`.
- */
- size?: `${number}x${number}`;
- /**
- * Edit the image in streaming mode. Defaults to `false`. See the
- * [Image generation guide](https://platform.openai.com/docs/guides/image-generation) for more information.
- *
- */
- stream?: boolean;
- /**
- * A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids).
- *
- */
- user?: string;
-};
-
-async function fileToBlob(
- file: ImageModelV3File | undefined,
-): Promise {
- if (!file) return undefined;
-
- if (file.type === 'url') {
- return downloadBlob(file.url);
- }
-
- const data =
- file.data instanceof Uint8Array
- ? file.data
- : convertBase64ToUint8Array(file.data);
-
- return new Blob([data as BlobPart], { type: file.mediaType });
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/image/openai-image-options.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/image/openai-image-options.ts
deleted file mode 100644
index 2ee92ea5e..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/image/openai-image-options.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-export type OpenAIImageModelId =
- | 'dall-e-3'
- | 'dall-e-2'
- | 'gpt-image-1'
- | 'gpt-image-1-mini'
- | 'gpt-image-1.5'
- | 'chatgpt-image-latest'
- | (string & {});
-
-// https://platform.openai.com/docs/guides/images
-export const modelMaxImagesPerCall: Record = {
- 'dall-e-3': 1,
- 'dall-e-2': 10,
- 'gpt-image-1': 10,
- 'gpt-image-1-mini': 10,
- 'gpt-image-1.5': 10,
- 'chatgpt-image-latest': 10,
-};
-
-const defaultResponseFormatPrefixes = [
- 'chatgpt-image-',
- 'gpt-image-1-mini',
- 'gpt-image-1.5',
- 'gpt-image-1',
-];
-
-export function hasDefaultResponseFormat(modelId: string): boolean {
- return defaultResponseFormatPrefixes.some(prefix =>
- modelId.startsWith(prefix),
- );
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/index.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/index.ts
deleted file mode 100644
index 22e3ceed8..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/index.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-export { createOpenAI, openai } from './openai-provider';
-export type { OpenAIProvider, OpenAIProviderSettings } from './openai-provider';
-export type {
- OpenAILanguageModelResponsesOptions,
- /** @deprecated Use `OpenAILanguageModelResponsesOptions` instead. */
- OpenAILanguageModelResponsesOptions as OpenAIResponsesProviderOptions,
-} from './responses/openai-responses-options';
-export type {
- OpenAILanguageModelChatOptions,
- /** @deprecated Use `OpenAILanguageModelChatOptions` instead. */
- OpenAILanguageModelChatOptions as OpenAIChatLanguageModelOptions,
-} from './chat/openai-chat-options';
-export type { OpenAILanguageModelCompletionOptions } from './completion/openai-completion-options';
-export type { OpenAIEmbeddingModelOptions } from './embedding/openai-embedding-options';
-export type { OpenAISpeechModelOptions } from './speech/openai-speech-options';
-export type { OpenAITranscriptionModelOptions } from './transcription/openai-transcription-options';
-export type {
- OpenaiResponsesProviderMetadata,
- OpenaiResponsesReasoningProviderMetadata,
- OpenaiResponsesTextProviderMetadata,
- OpenaiResponsesSourceDocumentProviderMetadata,
-} from './responses/openai-responses-provider-metadata';
-export { VERSION } from './version';
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/internal/index.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/internal/index.ts
deleted file mode 100644
index 0a79d3f71..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/internal/index.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-export * from '../chat/openai-chat-language-model';
-export * from '../chat/openai-chat-options';
-export * from '../completion/openai-completion-language-model';
-export * from '../completion/openai-completion-options';
-export * from '../embedding/openai-embedding-model';
-export * from '../embedding/openai-embedding-options';
-export * from '../image/openai-image-model';
-export * from '../image/openai-image-options';
-export * from '../transcription/openai-transcription-model';
-export * from '../transcription/openai-transcription-options';
-export * from '../speech/openai-speech-model';
-export * from '../speech/openai-speech-options';
-export * from '../responses/openai-responses-language-model';
-export * from '../responses/openai-responses-provider-metadata';
-export * from '../tool/apply-patch';
-export * from '../tool/code-interpreter';
-export * from '../tool/file-search';
-export * from '../tool/image-generation';
-export * from '../tool/web-search-preview';
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-config.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-config.ts
deleted file mode 100644
index 6f41ff698..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-config.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { FetchFunction } from '@ai-sdk/provider-utils';
-
-export type OpenAIConfig = {
- provider: string;
- url: (options: { modelId: string; path: string }) => string;
- headers: () => Record;
- fetch?: FetchFunction;
- generateId?: () => string;
- /**
- * File ID prefixes used to identify file IDs in Responses API.
- * When undefined, all file data is treated as base64 content.
- *
- * Examples:
- * - OpenAI: ['file-'] for IDs like 'file-abc123'
- * - Azure OpenAI: ['assistant-'] for IDs like 'assistant-abc123'
- */
- fileIdPrefixes?: readonly string[];
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-error.ts
deleted file mode 100644
index d8d59a515..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-error.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { z } from 'zod/v4';
-import { createJsonErrorResponseHandler } from '@ai-sdk/provider-utils';
-
-export const openaiErrorDataSchema = z.object({
- error: z.object({
- message: z.string(),
-
- // The additional information below is handled loosely to support
- // OpenAI-compatible providers that have slightly different error
- // responses:
- type: z.string().nullish(),
- param: z.any().nullish(),
- code: z.union([z.string(), z.number()]).nullish(),
- }),
-});
-
-export type OpenAIErrorData = z.infer;
-
-export const openaiFailedResponseHandler = createJsonErrorResponseHandler({
- errorSchema: openaiErrorDataSchema,
- errorToMessage: data => data.error.message,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-language-model-capabilities.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-language-model-capabilities.ts
deleted file mode 100644
index 3d926d6ca..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-language-model-capabilities.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-export type OpenAILanguageModelCapabilities = {
- isReasoningModel: boolean;
- systemMessageMode: 'remove' | 'system' | 'developer';
- supportsFlexProcessing: boolean;
- supportsPriorityProcessing: boolean;
-
- /**
- * Allow temperature, topP, logProbs when reasoningEffort is none.
- */
- supportsNonReasoningParameters: boolean;
-};
-
-export function getOpenAILanguageModelCapabilities(
- modelId: string,
-): OpenAILanguageModelCapabilities {
- const supportsFlexProcessing =
- modelId.startsWith('o3') ||
- modelId.startsWith('o4-mini') ||
- (modelId.startsWith('gpt-5') && !modelId.startsWith('gpt-5-chat'));
-
- const supportsPriorityProcessing =
- modelId.startsWith('gpt-4') ||
- (modelId.startsWith('gpt-5') &&
- !modelId.startsWith('gpt-5-nano') &&
- !modelId.startsWith('gpt-5-chat') &&
- !modelId.startsWith('gpt-5.4-nano')) ||
- modelId.startsWith('o3') ||
- modelId.startsWith('o4-mini');
-
- // Use allowlist approach: only known reasoning models should use 'developer' role
- // This prevents issues with fine-tuned models, third-party models, and custom models
- const isReasoningModel =
- modelId.startsWith('o1') ||
- modelId.startsWith('o3') ||
- modelId.startsWith('o4-mini') ||
- (modelId.startsWith('gpt-5') && !modelId.startsWith('gpt-5-chat'));
-
- // https://platform.openai.com/docs/guides/latest-model#gpt-5-1-parameter-compatibility
- // GPT-5.1, GPT-5.2, and GPT-5.4 support temperature, topP, logProbs when reasoningEffort is none
- const supportsNonReasoningParameters =
- modelId.startsWith('gpt-5.1') ||
- modelId.startsWith('gpt-5.2') ||
- modelId.startsWith('gpt-5.3') ||
- modelId.startsWith('gpt-5.4');
-
- const systemMessageMode = isReasoningModel ? 'developer' : 'system';
-
- return {
- supportsFlexProcessing,
- supportsPriorityProcessing,
- isReasoningModel,
- systemMessageMode,
- supportsNonReasoningParameters,
- };
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-provider.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-provider.ts
deleted file mode 100644
index 1dd6d7609..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-provider.ts
+++ /dev/null
@@ -1,270 +0,0 @@
-import {
- EmbeddingModelV3,
- ImageModelV3,
- LanguageModelV3,
- ProviderV3,
- SpeechModelV3,
- TranscriptionModelV3,
-} from '@ai-sdk/provider';
-import {
- FetchFunction,
- loadApiKey,
- loadOptionalSetting,
- withoutTrailingSlash,
- withUserAgentSuffix,
-} from '@ai-sdk/provider-utils';
-import { OpenAIChatLanguageModel } from './chat/openai-chat-language-model';
-import { OpenAIChatModelId } from './chat/openai-chat-options';
-import { OpenAICompletionLanguageModel } from './completion/openai-completion-language-model';
-import { OpenAICompletionModelId } from './completion/openai-completion-options';
-import { OpenAIEmbeddingModel } from './embedding/openai-embedding-model';
-import { OpenAIEmbeddingModelId } from './embedding/openai-embedding-options';
-import { OpenAIImageModel } from './image/openai-image-model';
-import { OpenAIImageModelId } from './image/openai-image-options';
-import { openaiTools } from './openai-tools';
-import { OpenAIResponsesLanguageModel } from './responses/openai-responses-language-model';
-import { OpenAIResponsesModelId } from './responses/openai-responses-options';
-import { OpenAISpeechModel } from './speech/openai-speech-model';
-import { OpenAISpeechModelId } from './speech/openai-speech-options';
-import { OpenAITranscriptionModel } from './transcription/openai-transcription-model';
-import { OpenAITranscriptionModelId } from './transcription/openai-transcription-options';
-import { VERSION } from './version';
-
-export interface OpenAIProvider extends ProviderV3 {
- (modelId: OpenAIResponsesModelId): LanguageModelV3;
-
- /**
- * Creates an OpenAI model for text generation.
- */
- languageModel(modelId: OpenAIResponsesModelId): LanguageModelV3;
-
- /**
- * Creates an OpenAI chat model for text generation.
- */
- chat(modelId: OpenAIChatModelId): LanguageModelV3;
-
- /**
- * Creates an OpenAI responses API model for text generation.
- */
- responses(modelId: OpenAIResponsesModelId): LanguageModelV3;
-
- /**
- * Creates an OpenAI completion model for text generation.
- */
- completion(modelId: OpenAICompletionModelId): LanguageModelV3;
-
- /**
- * Creates a model for text embeddings.
- */
- embedding(modelId: OpenAIEmbeddingModelId): EmbeddingModelV3;
-
- /**
- * Creates a model for text embeddings.
- */
- embeddingModel(modelId: OpenAIEmbeddingModelId): EmbeddingModelV3;
-
- /**
- * @deprecated Use `embedding` instead.
- */
- textEmbedding(modelId: OpenAIEmbeddingModelId): EmbeddingModelV3;
-
- /**
- * @deprecated Use `embeddingModel` instead.
- */
- textEmbeddingModel(modelId: OpenAIEmbeddingModelId): EmbeddingModelV3;
-
- /**
- * Creates a model for image generation.
- */
- image(modelId: OpenAIImageModelId): ImageModelV3;
-
- /**
- * Creates a model for image generation.
- */
- imageModel(modelId: OpenAIImageModelId): ImageModelV3;
-
- /**
- * Creates a model for transcription.
- */
- transcription(modelId: OpenAITranscriptionModelId): TranscriptionModelV3;
-
- /**
- * Creates a model for speech generation.
- */
- speech(modelId: OpenAISpeechModelId): SpeechModelV3;
-
- /**
- * OpenAI-specific tools.
- */
- tools: typeof openaiTools;
-}
-
-export interface OpenAIProviderSettings {
- /**
- * Base URL for the OpenAI API calls.
- */
- baseURL?: string;
-
- /**
- * API key for authenticating requests.
- */
- apiKey?: string;
-
- /**
- * OpenAI Organization.
- */
- organization?: string;
-
- /**
- * OpenAI project.
- */
- project?: string;
-
- /**
- * Custom headers to include in the requests.
- */
- headers?: Record;
-
- /**
- * Provider name. Overrides the `openai` default name for 3rd party providers.
- */
- name?: string;
-
- /**
- * Custom fetch implementation. You can use it as a middleware to intercept requests,
- * or to provide a custom fetch implementation for e.g. testing.
- */
- fetch?: FetchFunction;
-}
-
-/**
- * Create an OpenAI provider instance.
- */
-export function createOpenAI(
- options: OpenAIProviderSettings = {},
-): OpenAIProvider {
- const baseURL =
- withoutTrailingSlash(
- loadOptionalSetting({
- settingValue: options.baseURL,
- environmentVariableName: 'OPENAI_BASE_URL',
- }),
- ) ?? 'https://api.openai.com/v1';
-
- const providerName = options.name ?? 'openai';
-
- const getHeaders = () =>
- withUserAgentSuffix(
- {
- Authorization: `Bearer ${loadApiKey({
- apiKey: options.apiKey,
- environmentVariableName: 'OPENAI_API_KEY',
- description: 'OpenAI',
- })}`,
- 'OpenAI-Organization': options.organization,
- 'OpenAI-Project': options.project,
- ...options.headers,
- },
- `ai-sdk/openai/${VERSION}`,
- );
-
- const createChatModel = (modelId: OpenAIChatModelId) =>
- new OpenAIChatLanguageModel(modelId, {
- provider: `${providerName}.chat`,
- url: ({ path }) => `${baseURL}${path}`,
- headers: getHeaders,
- fetch: options.fetch,
- });
-
- const createCompletionModel = (modelId: OpenAICompletionModelId) =>
- new OpenAICompletionLanguageModel(modelId, {
- provider: `${providerName}.completion`,
- url: ({ path }) => `${baseURL}${path}`,
- headers: getHeaders,
- fetch: options.fetch,
- });
-
- const createEmbeddingModel = (modelId: OpenAIEmbeddingModelId) =>
- new OpenAIEmbeddingModel(modelId, {
- provider: `${providerName}.embedding`,
- url: ({ path }) => `${baseURL}${path}`,
- headers: getHeaders,
- fetch: options.fetch,
- });
-
- const createImageModel = (modelId: OpenAIImageModelId) =>
- new OpenAIImageModel(modelId, {
- provider: `${providerName}.image`,
- url: ({ path }) => `${baseURL}${path}`,
- headers: getHeaders,
- fetch: options.fetch,
- });
-
- const createTranscriptionModel = (modelId: OpenAITranscriptionModelId) =>
- new OpenAITranscriptionModel(modelId, {
- provider: `${providerName}.transcription`,
- url: ({ path }) => `${baseURL}${path}`,
- headers: getHeaders,
- fetch: options.fetch,
- });
-
- const createSpeechModel = (modelId: OpenAISpeechModelId) =>
- new OpenAISpeechModel(modelId, {
- provider: `${providerName}.speech`,
- url: ({ path }) => `${baseURL}${path}`,
- headers: getHeaders,
- fetch: options.fetch,
- });
-
- const createLanguageModel = (modelId: OpenAIResponsesModelId) => {
- if (new.target) {
- throw new Error(
- 'The OpenAI model function cannot be called with the new keyword.',
- );
- }
-
- return createResponsesModel(modelId);
- };
-
- const createResponsesModel = (modelId: OpenAIResponsesModelId) => {
- return new OpenAIResponsesLanguageModel(modelId, {
- provider: `${providerName}.responses`,
- url: ({ path }) => `${baseURL}${path}`,
- headers: getHeaders,
- fetch: options.fetch,
- fileIdPrefixes: ['file-'],
- });
- };
-
- const provider = function (modelId: OpenAIResponsesModelId) {
- return createLanguageModel(modelId);
- };
-
- provider.specificationVersion = 'v3' as const;
- provider.languageModel = createLanguageModel;
- provider.chat = createChatModel;
- provider.completion = createCompletionModel;
- provider.responses = createResponsesModel;
- provider.embedding = createEmbeddingModel;
- provider.embeddingModel = createEmbeddingModel;
- provider.textEmbedding = createEmbeddingModel;
- provider.textEmbeddingModel = createEmbeddingModel;
-
- provider.image = createImageModel;
- provider.imageModel = createImageModel;
-
- provider.transcription = createTranscriptionModel;
- provider.transcriptionModel = createTranscriptionModel;
-
- provider.speech = createSpeechModel;
- provider.speechModel = createSpeechModel;
-
- provider.tools = openaiTools;
-
- return provider as OpenAIProvider;
-}
-
-/**
- * Default OpenAI provider instance.
- */
-export const openai = createOpenAI();
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-tools.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-tools.ts
deleted file mode 100644
index c6192938b..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/openai-tools.ts
+++ /dev/null
@@ -1,138 +0,0 @@
-import { applyPatch } from './tool/apply-patch';
-import { codeInterpreter } from './tool/code-interpreter';
-import { customTool } from './tool/custom';
-import { fileSearch } from './tool/file-search';
-import { imageGeneration } from './tool/image-generation';
-import { localShell } from './tool/local-shell';
-import { shell } from './tool/shell';
-import { toolSearch } from './tool/tool-search';
-import { webSearch } from './tool/web-search';
-import { webSearchPreview } from './tool/web-search-preview';
-import { mcp } from './tool/mcp';
-
-export const openaiTools = {
- /**
- * The apply_patch tool lets GPT-5.1 create, update, and delete files in your
- * codebase using structured diffs. Instead of just suggesting edits, the model
- * emits patch operations that your application applies and then reports back on,
- * enabling iterative, multi-step code editing workflows.
- *
- */
- applyPatch,
-
- /**
- * Custom tools let callers constrain model output to a grammar (regex or
- * Lark syntax). The model returns a `custom_tool_call` output item whose
- * `input` field is a string matching the specified grammar.
- *
- * @param name - The name of the custom tool.
- * @param description - An optional description of the tool.
- * @param format - The output format constraint (grammar type, syntax, and definition).
- */
- customTool,
-
- /**
- * The Code Interpreter tool allows models to write and run Python code in a
- * sandboxed environment to solve complex problems in domains like data analysis,
- * coding, and math.
- *
- * @param container - The container to use for the code interpreter.
- */
- codeInterpreter,
-
- /**
- * File search is a tool available in the Responses API. It enables models to
- * retrieve information in a knowledge base of previously uploaded files through
- * semantic and keyword search.
- *
- * @param vectorStoreIds - The vector store IDs to use for the file search.
- * @param maxNumResults - The maximum number of results to return.
- * @param ranking - The ranking options to use for the file search.
- * @param filters - The filters to use for the file search.
- */
- fileSearch,
-
- /**
- * The image generation tool allows you to generate images using a text prompt,
- * and optionally image inputs. It leverages the GPT Image model,
- * and automatically optimizes text inputs for improved performance.
- *
- * @param background - Background type for the generated image. One of 'auto', 'opaque', or 'transparent'.
- * @param inputFidelity - Input fidelity for the generated image. One of 'low' or 'high'.
- * @param inputImageMask - Optional mask for inpainting. Contains fileId and/or imageUrl.
- * @param model - The image generation model to use. Default: gpt-image-1.
- * @param moderation - Moderation level for the generated image. Default: 'auto'.
- * @param outputCompression - Compression level for the output image (0-100).
- * @param outputFormat - The output format of the generated image. One of 'png', 'jpeg', or 'webp'.
- * @param partialImages - Number of partial images to generate in streaming mode (0-3).
- * @param quality - The quality of the generated image. One of 'auto', 'low', 'medium', or 'high'.
- * @param size - The size of the generated image. One of 'auto', '1024x1024', '1024x1536', or '1536x1024'.
- */
- imageGeneration,
-
- /**
- * Local shell is a tool that allows agents to run shell commands locally
- * on a machine you or the user provides.
- *
- * Supported models: `gpt-5-codex`
- */
- localShell,
-
- /**
- * The shell tool allows the model to interact with your local computer through
- * a controlled command-line interface. The model proposes shell commands; your
- * integration executes them and returns the outputs.
- *
- * Available through the Responses API for use with GPT-5.1.
- *
- * WARNING: Running arbitrary shell commands can be dangerous. Always sandbox
- * execution or add strict allow-/deny-lists before forwarding a command to
- * the system shell.
- */
- shell,
-
- /**
- * Web search allows models to access up-to-date information from the internet
- * and provide answers with sourced citations.
- *
- * @param searchContextSize - The search context size to use for the web search.
- * @param userLocation - The user location to use for the web search.
- */
- webSearchPreview,
-
- /**
- * Web search allows models to access up-to-date information from the internet
- * and provide answers with sourced citations.
- *
- * @param filters - The filters to use for the web search.
- * @param searchContextSize - The search context size to use for the web search.
- * @param userLocation - The user location to use for the web search.
- */
- webSearch,
-
- /**
- * MCP (Model Context Protocol) allows models to call tools exposed by
- * remote MCP servers or service connectors.
- *
- * @param serverLabel - Label to identify the MCP server.
- * @param allowedTools - Allowed tool names or filter object.
- * @param authorization - OAuth access token for the MCP server/connector.
- * @param connectorId - Identifier for a service connector.
- * @param headers - Optional headers to include in MCP requests.
- * // param requireApproval - Approval policy ('always'|'never'|filter object). (Removed - always 'never')
- * @param serverDescription - Optional description of the server.
- * @param serverUrl - URL for the MCP server.
- */
- mcp,
-
- /**
- * Tool search allows the model to dynamically search for and load deferred
- * tools into the model's context as needed. This helps reduce overall token
- * usage, cost, and latency by only loading tools when the model needs them.
- *
- * To use tool search, mark functions or namespaces with `defer_loading: true`
- * in the tools array. The model will use tool search to load these tools
- * when it determines they are needed.
- */
- toolSearch,
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/convert-openai-responses-usage.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/convert-openai-responses-usage.ts
deleted file mode 100644
index b40b9dec6..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/convert-openai-responses-usage.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { LanguageModelV3Usage } from '@ai-sdk/provider';
-
-export type OpenAIResponsesUsage = {
- input_tokens: number;
- output_tokens: number;
- input_tokens_details?: {
- cached_tokens?: number | null;
- } | null;
- output_tokens_details?: {
- reasoning_tokens?: number | null;
- } | null;
-};
-
-export function convertOpenAIResponsesUsage(
- usage: OpenAIResponsesUsage | undefined | null,
-): LanguageModelV3Usage {
- if (usage == null) {
- return {
- inputTokens: {
- total: undefined,
- noCache: undefined,
- cacheRead: undefined,
- cacheWrite: undefined,
- },
- outputTokens: {
- total: undefined,
- text: undefined,
- reasoning: undefined,
- },
- raw: undefined,
- };
- }
-
- const inputTokens = usage.input_tokens;
- const outputTokens = usage.output_tokens;
- const cachedTokens = usage.input_tokens_details?.cached_tokens ?? 0;
- const reasoningTokens = usage.output_tokens_details?.reasoning_tokens ?? 0;
-
- return {
- inputTokens: {
- total: inputTokens,
- noCache: inputTokens - cachedTokens,
- cacheRead: cachedTokens,
- cacheWrite: undefined,
- },
- outputTokens: {
- total: outputTokens,
- text: outputTokens - reasoningTokens,
- reasoning: reasoningTokens,
- },
- raw: usage,
- };
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/convert-to-openai-responses-input.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/convert-to-openai-responses-input.ts
deleted file mode 100644
index 712a403bd..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/convert-to-openai-responses-input.ts
+++ /dev/null
@@ -1,839 +0,0 @@
-import {
- LanguageModelV3Prompt,
- LanguageModelV3ToolApprovalResponsePart,
- SharedV3Warning,
- UnsupportedFunctionalityError,
-} from '@ai-sdk/provider';
-import {
- convertToBase64,
- isNonNullable,
- parseJSON,
- parseProviderOptions,
- ToolNameMapping,
- validateTypes,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-import {
- applyPatchInputSchema,
- applyPatchOutputSchema,
-} from '../tool/apply-patch';
-import {
- localShellInputSchema,
- localShellOutputSchema,
-} from '../tool/local-shell';
-import { shellInputSchema, shellOutputSchema } from '../tool/shell';
-import {
- toolSearchInputSchema,
- toolSearchOutputSchema,
-} from '../tool/tool-search';
-import {
- OpenAIResponsesCustomToolCallOutput,
- OpenAIResponsesFunctionCallOutput,
- OpenAIResponsesInput,
- OpenAIResponsesReasoning,
-} from './openai-responses-api';
-
-/**
- * Check if a string is a file ID based on the given prefixes
- * Returns false if prefixes is undefined (disables file ID detection)
- */
-function isFileId(data: string, prefixes?: readonly string[]): boolean {
- if (!prefixes) return false;
- return prefixes.some(prefix => data.startsWith(prefix));
-}
-
-export async function convertToOpenAIResponsesInput({
- prompt,
- toolNameMapping,
- systemMessageMode,
- providerOptionsName,
- fileIdPrefixes,
- store,
- hasConversation = false,
- hasLocalShellTool = false,
- hasShellTool = false,
- hasApplyPatchTool = false,
- customProviderToolNames,
-}: {
- prompt: LanguageModelV3Prompt;
- toolNameMapping: ToolNameMapping;
- systemMessageMode: 'system' | 'developer' | 'remove';
- providerOptionsName: string;
- fileIdPrefixes?: readonly string[];
- store: boolean;
- hasConversation?: boolean; // when true, skip assistant messages that already have item IDs
- hasLocalShellTool?: boolean;
- hasShellTool?: boolean;
- hasApplyPatchTool?: boolean;
- customProviderToolNames?: Set;
-}): Promise<{
- input: OpenAIResponsesInput;
- warnings: Array;
-}> {
- let input: OpenAIResponsesInput = [];
- const warnings: Array = [];
- const processedApprovalIds = new Set();
-
- for (const { role, content } of prompt) {
- switch (role) {
- case 'system': {
- switch (systemMessageMode) {
- case 'system': {
- input.push({ role: 'system', content });
- break;
- }
- case 'developer': {
- input.push({ role: 'developer', content });
- break;
- }
- case 'remove': {
- warnings.push({
- type: 'other',
- message: 'system messages are removed for this model',
- });
- break;
- }
- default: {
- const _exhaustiveCheck: never = systemMessageMode;
- throw new Error(
- `Unsupported system message mode: ${_exhaustiveCheck}`,
- );
- }
- }
- break;
- }
-
- case 'user': {
- input.push({
- role: 'user',
- content: content.map((part, index) => {
- switch (part.type) {
- case 'text': {
- return { type: 'input_text', text: part.text };
- }
- case 'file': {
- if (part.mediaType.startsWith('image/')) {
- const mediaType =
- part.mediaType === 'image/*'
- ? 'image/jpeg'
- : part.mediaType;
-
- return {
- type: 'input_image',
- ...(part.data instanceof URL
- ? { image_url: part.data.toString() }
- : typeof part.data === 'string' &&
- isFileId(part.data, fileIdPrefixes)
- ? { file_id: part.data }
- : {
- image_url: `data:${mediaType};base64,${convertToBase64(part.data)}`,
- }),
- detail:
- part.providerOptions?.[providerOptionsName]?.imageDetail,
- };
- } else if (part.mediaType === 'application/pdf') {
- if (part.data instanceof URL) {
- return {
- type: 'input_file',
- file_url: part.data.toString(),
- };
- }
- return {
- type: 'input_file',
- ...(typeof part.data === 'string' &&
- isFileId(part.data, fileIdPrefixes)
- ? { file_id: part.data }
- : {
- filename: part.filename ?? `part-${index}.pdf`,
- file_data: `data:application/pdf;base64,${convertToBase64(part.data)}`,
- }),
- };
- } else {
- throw new UnsupportedFunctionalityError({
- functionality: `file part media type ${part.mediaType}`,
- });
- }
- }
- }
- }),
- });
-
- break;
- }
-
- case 'assistant': {
- const reasoningMessages: Record = {};
-
- for (const part of content) {
- switch (part.type) {
- case 'text': {
- const providerOpts = part.providerOptions?.[providerOptionsName];
- const id = providerOpts?.itemId as string | undefined;
- const phase = providerOpts?.phase as
- | 'commentary'
- | 'final_answer'
- | null
- | undefined;
-
- // when using conversation, skip items that already exist in the conversation context to avoid "Duplicate item found" errors
- if (hasConversation && id != null) {
- break;
- }
-
- // item references reduce the payload size
- if (store && id != null) {
- input.push({ type: 'item_reference', id });
- break;
- }
-
- input.push({
- role: 'assistant',
- content: [{ type: 'output_text', text: part.text }],
- id,
- ...(phase != null && { phase }),
- });
-
- break;
- }
- case 'tool-call': {
- const id = (part.providerOptions?.[providerOptionsName]?.itemId ??
- (
- part as {
- providerMetadata?: {
- [providerOptionsName]?: { itemId?: string };
- };
- }
- ).providerMetadata?.[providerOptionsName]?.itemId) as
- | string
- | undefined;
-
- if (hasConversation && id != null) {
- break;
- }
-
- const resolvedToolName = toolNameMapping.toProviderToolName(
- part.toolName,
- );
-
- if (resolvedToolName === 'tool_search') {
- if (store && id != null) {
- input.push({ type: 'item_reference', id });
- break;
- }
-
- const parsedInput =
- typeof part.input === 'string'
- ? await parseJSON({
- text: part.input,
- schema: toolSearchInputSchema,
- })
- : await validateTypes({
- value: part.input,
- schema: toolSearchInputSchema,
- });
-
- const execution =
- parsedInput.call_id != null ? 'client' : 'server';
-
- input.push({
- type: 'tool_search_call',
- id: id ?? part.toolCallId,
- execution,
- call_id: parsedInput.call_id ?? null,
- status: 'completed',
- arguments: parsedInput.arguments,
- });
- break;
- }
-
- if (part.providerExecuted) {
- if (store && id != null) {
- input.push({ type: 'item_reference', id });
- }
- break;
- }
-
- if (store && id != null) {
- input.push({ type: 'item_reference', id });
- break;
- }
-
- if (hasLocalShellTool && resolvedToolName === 'local_shell') {
- const parsedInput = await validateTypes({
- value: part.input,
- schema: localShellInputSchema,
- });
- input.push({
- type: 'local_shell_call',
- call_id: part.toolCallId,
- id: id!,
- action: {
- type: 'exec',
- command: parsedInput.action.command,
- timeout_ms: parsedInput.action.timeoutMs,
- user: parsedInput.action.user,
- working_directory: parsedInput.action.workingDirectory,
- env: parsedInput.action.env,
- },
- });
-
- break;
- }
-
- if (hasShellTool && resolvedToolName === 'shell') {
- const parsedInput = await validateTypes({
- value: part.input,
- schema: shellInputSchema,
- });
- input.push({
- type: 'shell_call',
- call_id: part.toolCallId,
- id: id!,
- status: 'completed',
- action: {
- commands: parsedInput.action.commands,
- timeout_ms: parsedInput.action.timeoutMs,
- max_output_length: parsedInput.action.maxOutputLength,
- },
- });
-
- break;
- }
-
- if (hasApplyPatchTool && resolvedToolName === 'apply_patch') {
- const parsedInput = await validateTypes({
- value: part.input,
- schema: applyPatchInputSchema,
- });
- input.push({
- type: 'apply_patch_call',
- call_id: parsedInput.callId,
- id: id!,
- status: 'completed',
- operation: parsedInput.operation,
- });
-
- break;
- }
-
- if (customProviderToolNames?.has(resolvedToolName)) {
- input.push({
- type: 'custom_tool_call',
- call_id: part.toolCallId,
- name: resolvedToolName,
- input:
- typeof part.input === 'string'
- ? part.input
- : JSON.stringify(part.input),
- id,
- });
- break;
- }
-
- input.push({
- type: 'function_call',
- call_id: part.toolCallId,
- name: resolvedToolName,
- arguments: JSON.stringify(part.input),
- id,
- });
- break;
- }
-
- // assistant tool result parts are from provider-executed tools:
- case 'tool-result': {
- // Skip execution-denied results - these are synthetic results from denied
- // approvals and have no corresponding item in OpenAI's store.
- // Check both the direct type and if it was transformed to json with execution-denied inside
- if (
- part.output.type === 'execution-denied' ||
- (part.output.type === 'json' &&
- typeof part.output.value === 'object' &&
- part.output.value != null &&
- 'type' in part.output.value &&
- part.output.value.type === 'execution-denied')
- ) {
- break;
- }
-
- if (hasConversation) {
- break;
- }
-
- const resolvedResultToolName = toolNameMapping.toProviderToolName(
- part.toolName,
- );
-
- if (resolvedResultToolName === 'tool_search') {
- const itemId =
- (
- part.providerOptions?.[providerOptionsName] as
- | { itemId?: string }
- | undefined
- )?.itemId ?? part.toolCallId;
-
- if (store) {
- input.push({ type: 'item_reference', id: itemId });
- } else if (part.output.type === 'json') {
- const parsedOutput = await validateTypes({
- value: part.output.value,
- schema: toolSearchOutputSchema,
- });
-
- input.push({
- type: 'tool_search_output',
- id: itemId,
- execution: 'server',
- call_id: null,
- status: 'completed',
- tools: parsedOutput.tools,
- });
- }
-
- break;
- }
-
- /*
- * Shell tool results are separate output items (shell_call_output)
- * with their own item IDs distinct from the shell_call's item ID.
- * Since the pipeline only preserves the shell_call's item ID in
- * callProviderMetadata, we reconstruct the full shell_call_output
- * instead of using an item_reference with the wrong ID.
- */
- if (hasShellTool && resolvedResultToolName === 'shell') {
- if (part.output.type === 'json') {
- const parsedOutput = await validateTypes({
- value: part.output.value,
- schema: shellOutputSchema,
- });
- input.push({
- type: 'shell_call_output',
- call_id: part.toolCallId,
- output: parsedOutput.output.map(item => ({
- stdout: item.stdout,
- stderr: item.stderr,
- outcome:
- item.outcome.type === 'timeout'
- ? { type: 'timeout' as const }
- : {
- type: 'exit' as const,
- exit_code: item.outcome.exitCode,
- },
- })),
- });
- }
- break;
- }
-
- if (store) {
- const itemId =
- (
- part.providerOptions?.[providerOptionsName] as
- | { itemId?: string }
- | undefined
- )?.itemId ?? part.toolCallId;
- input.push({ type: 'item_reference', id: itemId });
- } else {
- warnings.push({
- type: 'other',
- message: `Results for OpenAI tool ${part.toolName} are not sent to the API when store is false`,
- });
- }
-
- break;
- }
-
- case 'reasoning': {
- const providerOptions = await parseProviderOptions({
- provider: providerOptionsName,
- providerOptions: part.providerOptions,
- schema: openaiResponsesReasoningProviderOptionsSchema,
- });
-
- const reasoningId = providerOptions?.itemId;
-
- if (hasConversation && reasoningId != null) {
- break;
- }
-
- if (reasoningId != null) {
- const reasoningMessage = reasoningMessages[reasoningId];
-
- if (store) {
- // use item references to refer to reasoning (single reference)
- // when the first part is encountered
- if (reasoningMessage === undefined) {
- input.push({ type: 'item_reference', id: reasoningId });
-
- // store unused reasoning message to mark id as used
- reasoningMessages[reasoningId] = {
- type: 'reasoning',
- id: reasoningId,
- summary: [],
- };
- }
- } else {
- const summaryParts: Array<{
- type: 'summary_text';
- text: string;
- }> = [];
-
- if (part.text.length > 0) {
- summaryParts.push({
- type: 'summary_text',
- text: part.text,
- });
- } else if (reasoningMessage !== undefined) {
- warnings.push({
- type: 'other',
- message: `Cannot append empty reasoning part to existing reasoning sequence. Skipping reasoning part: ${JSON.stringify(part)}.`,
- });
- }
-
- if (reasoningMessage === undefined) {
- reasoningMessages[reasoningId] = {
- type: 'reasoning',
- id: reasoningId,
- encrypted_content:
- providerOptions?.reasoningEncryptedContent,
- summary: summaryParts,
- };
- input.push(reasoningMessages[reasoningId]);
- } else {
- reasoningMessage.summary.push(...summaryParts);
-
- // updated encrypted content to enable setting it in the last summary part:
- if (providerOptions?.reasoningEncryptedContent != null) {
- reasoningMessage.encrypted_content =
- providerOptions.reasoningEncryptedContent;
- }
- }
- }
- } else {
- // No itemId — fall back to encrypted_content if available.
- // The OpenAI Responses API accepts reasoning items without an
- // id when encrypted_content is provided, enabling multi-turn
- // reasoning even when server-side item persistence is not used
- // or when itemId has been stripped from providerOptions.
- const encryptedContent =
- providerOptions?.reasoningEncryptedContent;
-
- if (encryptedContent != null) {
- const summaryParts: Array<{
- type: 'summary_text';
- text: string;
- }> = [];
- if (part.text.length > 0) {
- summaryParts.push({
- type: 'summary_text',
- text: part.text,
- });
- }
- input.push({
- type: 'reasoning',
- encrypted_content: encryptedContent,
- summary: summaryParts,
- });
- } else {
- warnings.push({
- type: 'other',
- message: `Non-OpenAI reasoning parts are not supported. Skipping reasoning part: ${JSON.stringify(part)}.`,
- });
- }
- }
- break;
- }
- }
- }
-
- break;
- }
-
- case 'tool': {
- for (const part of content) {
- if (part.type === 'tool-approval-response') {
- const approvalResponse =
- part as LanguageModelV3ToolApprovalResponsePart;
-
- if (processedApprovalIds.has(approvalResponse.approvalId)) {
- continue;
- }
- processedApprovalIds.add(approvalResponse.approvalId);
-
- if (store) {
- input.push({
- type: 'item_reference',
- id: approvalResponse.approvalId,
- });
- }
-
- input.push({
- type: 'mcp_approval_response',
- approval_request_id: approvalResponse.approvalId,
- approve: approvalResponse.approved,
- });
- continue;
- }
-
- const output = part.output;
-
- // Skip execution-denied with approvalId - already handled via tool-approval-response
- if (output.type === 'execution-denied') {
- const approvalId = (
- output.providerOptions?.openai as { approvalId?: string }
- )?.approvalId;
-
- if (approvalId) {
- continue;
- }
- }
-
- const resolvedToolName = toolNameMapping.toProviderToolName(
- part.toolName,
- );
-
- if (resolvedToolName === 'tool_search' && output.type === 'json') {
- const parsedOutput = await validateTypes({
- value: output.value,
- schema: toolSearchOutputSchema,
- });
-
- input.push({
- type: 'tool_search_output',
- execution: 'client',
- call_id: part.toolCallId,
- status: 'completed',
- tools: parsedOutput.tools,
- });
- continue;
- }
-
- if (
- hasLocalShellTool &&
- resolvedToolName === 'local_shell' &&
- output.type === 'json'
- ) {
- const parsedOutput = await validateTypes({
- value: output.value,
- schema: localShellOutputSchema,
- });
-
- input.push({
- type: 'local_shell_call_output',
- call_id: part.toolCallId,
- output: parsedOutput.output,
- });
- continue;
- }
-
- if (
- hasShellTool &&
- resolvedToolName === 'shell' &&
- output.type === 'json'
- ) {
- const parsedOutput = await validateTypes({
- value: output.value,
- schema: shellOutputSchema,
- });
-
- input.push({
- type: 'shell_call_output',
- call_id: part.toolCallId,
- output: parsedOutput.output.map(item => ({
- stdout: item.stdout,
- stderr: item.stderr,
- outcome:
- item.outcome.type === 'timeout'
- ? { type: 'timeout' as const }
- : {
- type: 'exit' as const,
- exit_code: item.outcome.exitCode,
- },
- })),
- });
- continue;
- }
-
- if (
- hasApplyPatchTool &&
- part.toolName === 'apply_patch' &&
- output.type === 'json'
- ) {
- const parsedOutput = await validateTypes({
- value: output.value,
- schema: applyPatchOutputSchema,
- });
-
- input.push({
- type: 'apply_patch_call_output',
- call_id: part.toolCallId,
- status: parsedOutput.status,
- output: parsedOutput.output,
- });
- continue;
- }
-
- if (customProviderToolNames?.has(resolvedToolName)) {
- let outputValue: OpenAIResponsesCustomToolCallOutput['output'];
- switch (output.type) {
- case 'text':
- case 'error-text':
- outputValue = output.value;
- break;
- case 'execution-denied':
- outputValue = output.reason ?? 'Tool execution denied.';
- break;
- case 'json':
- case 'error-json':
- outputValue = JSON.stringify(output.value);
- break;
- case 'content':
- outputValue = output.value
- .map(item => {
- switch (item.type) {
- case 'text':
- return { type: 'input_text' as const, text: item.text };
- case 'image-data':
- return {
- type: 'input_image' as const,
- image_url: `data:${item.mediaType};base64,${item.data}`,
- };
- case 'image-url':
- return {
- type: 'input_image' as const,
- image_url: item.url,
- };
- case 'file-data':
- return {
- type: 'input_file' as const,
- filename: item.filename ?? 'data',
- file_data: `data:${item.mediaType};base64,${item.data}`,
- };
- default:
- warnings.push({
- type: 'other',
- message: `unsupported custom tool content part type: ${item.type}`,
- });
- return undefined;
- }
- })
- .filter(isNonNullable);
- break;
- default:
- outputValue = '';
- }
- input.push({
- type: 'custom_tool_call_output',
- call_id: part.toolCallId,
- output: outputValue,
- } satisfies OpenAIResponsesCustomToolCallOutput);
- continue;
- }
-
- let contentValue: OpenAIResponsesFunctionCallOutput['output'];
- switch (output.type) {
- case 'text':
- case 'error-text':
- contentValue = output.value;
- break;
- case 'execution-denied':
- contentValue = output.reason ?? 'Tool execution denied.';
- break;
- case 'json':
- case 'error-json':
- contentValue = JSON.stringify(output.value);
- break;
- case 'content':
- contentValue = output.value
- .map(item => {
- switch (item.type) {
- case 'text': {
- return { type: 'input_text' as const, text: item.text };
- }
-
- case 'image-data': {
- return {
- type: 'input_image' as const,
- image_url: `data:${item.mediaType};base64,${item.data}`,
- };
- }
-
- case 'image-url': {
- return {
- type: 'input_image' as const,
- image_url: item.url,
- };
- }
-
- case 'file-data': {
- return {
- type: 'input_file' as const,
- filename: item.filename ?? 'data',
- file_data: `data:${item.mediaType};base64,${item.data}`,
- };
- }
-
- default: {
- warnings.push({
- type: 'other',
- message: `unsupported tool content part type: ${item.type}`,
- });
- return undefined;
- }
- }
- })
- .filter(isNonNullable);
- break;
- }
-
- input.push({
- type: 'function_call_output',
- call_id: part.toolCallId,
- output: contentValue,
- });
- }
-
- break;
- }
-
- default: {
- const _exhaustiveCheck: never = role;
- throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
- }
- }
- }
-
- // when store is false, remove reasoning parts without encrypted content
- if (
- !store &&
- input.some(
- item =>
- 'type' in item &&
- item.type === 'reasoning' &&
- item.encrypted_content == null,
- )
- ) {
- warnings.push({
- type: 'other',
- message:
- 'Reasoning parts without encrypted content are not supported when store is false. Skipping reasoning parts.',
- });
- input = input.filter(
- item =>
- !('type' in item) ||
- item.type !== 'reasoning' ||
- item.encrypted_content != null,
- );
- }
-
- return { input, warnings };
-}
-
-const openaiResponsesReasoningProviderOptionsSchema = z.object({
- itemId: z.string().nullish(),
- reasoningEncryptedContent: z.string().nullish(),
-});
-
-export type OpenAIResponsesReasoningProviderOptions = z.infer<
- typeof openaiResponsesReasoningProviderOptionsSchema
->;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/map-openai-responses-finish-reason.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/map-openai-responses-finish-reason.ts
deleted file mode 100644
index f925d4992..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/map-openai-responses-finish-reason.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { LanguageModelV3FinishReason } from '@ai-sdk/provider';
-
-export function mapOpenAIResponseFinishReason({
- finishReason,
- hasFunctionCall,
-}: {
- finishReason: string | null | undefined;
- // flag that checks if there have been client-side tool calls (not executed by openai)
- hasFunctionCall: boolean;
-}): LanguageModelV3FinishReason['unified'] {
- switch (finishReason) {
- case undefined:
- case null:
- return hasFunctionCall ? 'tool-calls' : 'stop';
- case 'max_output_tokens':
- return 'length';
- case 'content_filter':
- return 'content-filter';
- default:
- return hasFunctionCall ? 'tool-calls' : 'other';
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-api.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-api.ts
deleted file mode 100644
index 511b000ff..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-api.ts
+++ /dev/null
@@ -1,1371 +0,0 @@
-import { JSONObject, JSONSchema7, JSONValue } from '@ai-sdk/provider';
-import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-const jsonValueSchema: z.ZodType = z.lazy(() =>
- z.union([
- z.string(),
- z.number(),
- z.boolean(),
- z.null(),
- z.array(jsonValueSchema),
- z.record(z.string(), jsonValueSchema.optional()),
- ]),
-);
-
-export type OpenAIResponsesInput = Array;
-
-export type OpenAIResponsesInputItem =
- | OpenAIResponsesSystemMessage
- | OpenAIResponsesUserMessage
- | OpenAIResponsesAssistantMessage
- | OpenAIResponsesFunctionCall
- | OpenAIResponsesFunctionCallOutput
- | OpenAIResponsesCustomToolCall
- | OpenAIResponsesCustomToolCallOutput
- | OpenAIResponsesMcpApprovalResponse
- | OpenAIResponsesComputerCall
- | OpenAIResponsesLocalShellCall
- | OpenAIResponsesLocalShellCallOutput
- | OpenAIResponsesShellCall
- | OpenAIResponsesShellCallOutput
- | OpenAIResponsesApplyPatchCall
- | OpenAIResponsesApplyPatchCallOutput
- | OpenAIResponsesToolSearchCall
- | OpenAIResponsesToolSearchOutput
- | OpenAIResponsesReasoning
- | OpenAIResponsesItemReference;
-
-export type OpenAIResponsesIncludeValue =
- | 'web_search_call.action.sources'
- | 'code_interpreter_call.outputs'
- | 'computer_call_output.output.image_url'
- | 'file_search_call.results'
- | 'message.input_image.image_url'
- | 'message.output_text.logprobs'
- | 'reasoning.encrypted_content';
-
-export type OpenAIResponsesIncludeOptions =
- | Array
- | undefined
- | null;
-
-export type OpenAIResponsesApplyPatchOperationDiffDeltaChunk = {
- type: 'response.apply_patch_call_operation_diff.delta';
- item_id: string;
- output_index: number;
- delta: string;
- obfuscation?: string | null;
-};
-
-export type OpenAIResponsesApplyPatchOperationDiffDoneChunk = {
- type: 'response.apply_patch_call_operation_diff.done';
- item_id: string;
- output_index: number;
- diff: string;
-};
-
-export type OpenAIResponsesSystemMessage = {
- role: 'system' | 'developer';
- content: string;
-};
-
-export type OpenAIResponsesUserMessage = {
- role: 'user';
- content: Array<
- | { type: 'input_text'; text: string }
- | { type: 'input_image'; image_url: string }
- | { type: 'input_image'; file_id: string }
- | { type: 'input_file'; file_url: string }
- | { type: 'input_file'; filename: string; file_data: string }
- | { type: 'input_file'; file_id: string }
- >;
-};
-
-export type OpenAIResponsesAssistantMessage = {
- role: 'assistant';
- content: Array<{ type: 'output_text'; text: string }>;
- id?: string;
- phase?: 'commentary' | 'final_answer' | null;
-};
-
-export type OpenAIResponsesFunctionCall = {
- type: 'function_call';
- call_id: string;
- name: string;
- arguments: string;
- id?: string;
-};
-
-export type OpenAIResponsesFunctionCallOutput = {
- type: 'function_call_output';
- call_id: string;
- output:
- | string
- | Array<
- | { type: 'input_text'; text: string }
- | { type: 'input_image'; image_url: string }
- | { type: 'input_file'; filename: string; file_data: string }
- >;
-};
-
-export type OpenAIResponsesCustomToolCall = {
- type: 'custom_tool_call';
- id?: string;
- call_id: string;
- name: string;
- input: string;
-};
-
-export type OpenAIResponsesCustomToolCallOutput = {
- type: 'custom_tool_call_output';
- call_id: string;
- output: OpenAIResponsesFunctionCallOutput['output'];
-};
-
-export type OpenAIResponsesMcpApprovalResponse = {
- type: 'mcp_approval_response';
- approval_request_id: string;
- approve: boolean;
-};
-
-export type OpenAIResponsesComputerCall = {
- type: 'computer_call';
- id: string;
- status?: string;
-};
-
-export type OpenAIResponsesLocalShellCall = {
- type: 'local_shell_call';
- id: string;
- call_id: string;
- action: {
- type: 'exec';
- command: string[];
- timeout_ms?: number;
- user?: string;
- working_directory?: string;
- env?: Record;
- };
-};
-
-export type OpenAIResponsesLocalShellCallOutput = {
- type: 'local_shell_call_output';
- call_id: string;
- output: string;
-};
-
-/**
- * Official OpenAI API Specifications: https://platform.openai.com/docs/api-reference/responses/object#responses-object-output-shell_tool_call
- */
-export type OpenAIResponsesShellCall = {
- type: 'shell_call';
- id: string;
- call_id: string;
- status: 'in_progress' | 'completed' | 'incomplete';
- action: {
- commands: string[];
- timeout_ms?: number;
- max_output_length?: number;
- };
-};
-
-export type OpenAIResponsesShellCallOutput = {
- type: 'shell_call_output';
- id?: string;
- call_id: string;
- status?: 'in_progress' | 'completed' | 'incomplete';
- max_output_length?: number | null;
- output: Array<{
- stdout: string;
- stderr: string;
- outcome: { type: 'timeout' } | { type: 'exit'; exit_code: number };
- }>;
-};
-
-export type OpenAIResponsesApplyPatchCall = {
- type: 'apply_patch_call';
- id?: string;
- call_id: string;
- status: 'in_progress' | 'completed';
- operation:
- | {
- type: 'create_file';
- path: string;
- diff: string;
- }
- | {
- type: 'delete_file';
- path: string;
- }
- | {
- type: 'update_file';
- path: string;
- diff: string;
- };
-};
-
-export type OpenAIResponsesApplyPatchCallOutput = {
- type: 'apply_patch_call_output';
- call_id: string;
- status: 'completed' | 'failed';
- output?: string;
-};
-
-export type OpenAIResponsesToolSearchCall = {
- type: 'tool_search_call';
- id: string;
- execution: 'server' | 'client';
- call_id: string | null;
- status: 'in_progress' | 'completed' | 'incomplete';
- arguments: unknown;
-};
-
-export type OpenAIResponsesToolSearchOutput = {
- type: 'tool_search_output';
- id?: string;
- execution: 'server' | 'client';
- call_id: string | null;
- status: 'in_progress' | 'completed' | 'incomplete';
- tools: Array;
-};
-
-export type OpenAIResponsesItemReference = {
- type: 'item_reference';
- id: string;
-};
-
-/**
- * A filter used to compare a specified attribute key to a given value using a defined comparison operation.
- */
-export type OpenAIResponsesFileSearchToolComparisonFilter = {
- /**
- * The key to compare against the value.
- */
- key: string;
-
- /**
- * Specifies the comparison operator: eq, ne, gt, gte, lt, lte, in, nin.
- */
- type: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'nin';
-
- /**
- * The value to compare against the attribute key; supports string, number, boolean, or array of string types.
- */
- value: string | number | boolean | string[];
-};
-
-/**
- * Combine multiple filters using and or or.
- */
-export type OpenAIResponsesFileSearchToolCompoundFilter = {
- /**
- * Type of operation: and or or.
- */
- type: 'and' | 'or';
-
- /**
- * Array of filters to combine. Items can be ComparisonFilter or CompoundFilter.
- */
- filters: Array<
- | OpenAIResponsesFileSearchToolComparisonFilter
- | OpenAIResponsesFileSearchToolCompoundFilter
- >;
-};
-
-export type OpenAIResponsesTool =
- | {
- type: 'function';
- name: string;
- description: string | undefined;
- parameters: JSONSchema7;
- strict?: boolean;
- defer_loading?: boolean;
- }
- | {
- type: 'apply_patch';
- }
- | {
- type: 'web_search';
- external_web_access: boolean | undefined;
- filters: { allowed_domains: string[] | undefined } | undefined;
- search_context_size: 'low' | 'medium' | 'high' | undefined;
- user_location:
- | {
- type: 'approximate';
- city?: string;
- country?: string;
- region?: string;
- timezone?: string;
- }
- | undefined;
- }
- | {
- type: 'web_search_preview';
- search_context_size: 'low' | 'medium' | 'high' | undefined;
- user_location:
- | {
- type: 'approximate';
- city?: string;
- country?: string;
- region?: string;
- timezone?: string;
- }
- | undefined;
- }
- | {
- type: 'code_interpreter';
- container: string | { type: 'auto'; file_ids: string[] | undefined };
- }
- | {
- type: 'file_search';
- vector_store_ids: string[];
- max_num_results: number | undefined;
- ranking_options:
- | { ranker?: string; score_threshold?: number }
- | undefined;
- filters:
- | OpenAIResponsesFileSearchToolComparisonFilter
- | OpenAIResponsesFileSearchToolCompoundFilter
- | undefined;
- }
- | {
- type: 'image_generation';
- background: 'auto' | 'opaque' | 'transparent' | undefined;
- input_fidelity: 'low' | 'high' | undefined;
- input_image_mask:
- | {
- file_id: string | undefined;
- image_url: string | undefined;
- }
- | undefined;
- model: string | undefined;
- moderation: 'auto' | undefined;
- output_compression: number | undefined;
- output_format: 'png' | 'jpeg' | 'webp' | undefined;
- partial_images: number | undefined;
- quality: 'auto' | 'low' | 'medium' | 'high' | undefined;
- size: 'auto' | '1024x1024' | '1024x1536' | '1536x1024' | undefined;
- }
-
- /**
- * Official OpenAI API Specifications: https://platform.openai.com/docs/api-reference/responses/create#responses_create-tools-mcp_tool
- */
- | {
- type: 'mcp';
- server_label: string;
- allowed_tools:
- | string[]
- | {
- read_only?: boolean;
- tool_names?: string[];
- }
- | undefined;
- authorization: string | undefined;
- connector_id: string | undefined;
- headers: Record | undefined;
- require_approval:
- | 'always'
- | 'never'
- | {
- never?: { tool_names?: string[] };
- }
- | undefined;
- server_description: string | undefined;
- server_url: string | undefined;
- }
- | {
- type: 'custom';
- name: string;
- description?: string;
- format?:
- | {
- type: 'grammar';
- syntax: 'regex' | 'lark';
- definition: string;
- }
- | {
- type: 'text';
- };
- }
- | {
- type: 'local_shell';
- }
- | {
- type: 'shell';
- environment?:
- | {
- type: 'container_auto';
- file_ids?: string[];
- memory_limit?: '1g' | '4g' | '16g' | '64g';
- network_policy?:
- | { type: 'disabled' }
- | {
- type: 'allowlist';
- allowed_domains: string[];
- domain_secrets?: Array<{
- domain: string;
- name: string;
- value: string;
- }>;
- };
- skills?: Array<
- | {
- type: 'skill_reference';
- skill_id: string;
- version?: string;
- }
- | {
- type: 'inline';
- name: string;
- description: string;
- source: {
- type: 'base64';
- media_type: 'application/zip';
- data: string;
- };
- }
- >;
- }
- | {
- type: 'container_reference';
- container_id: string;
- }
- | {
- type: 'local';
- skills?: Array<{
- name: string;
- description: string;
- path: string;
- }>;
- };
- }
- | {
- type: 'tool_search';
- execution?: 'server' | 'client';
- description?: string;
- parameters?: Record;
- };
-
-export type OpenAIResponsesReasoning = {
- type: 'reasoning';
- id?: string;
- encrypted_content?: string | null;
- summary: Array<{
- type: 'summary_text';
- text: string;
- }>;
-};
-
-export const openaiResponsesChunkSchema = lazySchema(() =>
- zodSchema(
- z.union([
- z.object({
- type: z.literal('response.output_text.delta'),
- item_id: z.string(),
- delta: z.string(),
- logprobs: z
- .array(
- z.object({
- token: z.string(),
- logprob: z.number(),
- top_logprobs: z.array(
- z.object({
- token: z.string(),
- logprob: z.number(),
- }),
- ),
- }),
- )
- .nullish(),
- }),
- z.object({
- type: z.enum(['response.completed', 'response.incomplete']),
- response: z.object({
- incomplete_details: z.object({ reason: z.string() }).nullish(),
- usage: z.object({
- input_tokens: z.number(),
- input_tokens_details: z
- .object({ cached_tokens: z.number().nullish() })
- .nullish(),
- output_tokens: z.number(),
- output_tokens_details: z
- .object({ reasoning_tokens: z.number().nullish() })
- .nullish(),
- }),
- service_tier: z.string().nullish(),
- }),
- }),
- z.object({
- type: z.literal('response.failed'),
- response: z.object({
- error: z
- .object({
- code: z.string().nullish(),
- message: z.string(),
- })
- .nullish(),
- incomplete_details: z.object({ reason: z.string() }).nullish(),
- usage: z
- .object({
- input_tokens: z.number(),
- input_tokens_details: z
- .object({ cached_tokens: z.number().nullish() })
- .nullish(),
- output_tokens: z.number(),
- output_tokens_details: z
- .object({ reasoning_tokens: z.number().nullish() })
- .nullish(),
- })
- .nullish(),
- service_tier: z.string().nullish(),
- }),
- }),
- z.object({
- type: z.literal('response.created'),
- response: z.object({
- id: z.string(),
- created_at: z.number(),
- model: z.string(),
- service_tier: z.string().nullish(),
- }),
- }),
- z.object({
- type: z.literal('response.output_item.added'),
- output_index: z.number(),
- item: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('message'),
- id: z.string(),
- phase: z.enum(['commentary', 'final_answer']).nullish(),
- }),
- z.object({
- type: z.literal('reasoning'),
- id: z.string(),
- encrypted_content: z.string().nullish(),
- }),
- z.object({
- type: z.literal('function_call'),
- id: z.string(),
- call_id: z.string(),
- name: z.string(),
- arguments: z.string(),
- }),
- z.object({
- type: z.literal('web_search_call'),
- id: z.string(),
- status: z.string(),
- }),
- z.object({
- type: z.literal('computer_call'),
- id: z.string(),
- status: z.string(),
- }),
- z.object({
- type: z.literal('file_search_call'),
- id: z.string(),
- }),
- z.object({
- type: z.literal('image_generation_call'),
- id: z.string(),
- }),
- z.object({
- type: z.literal('code_interpreter_call'),
- id: z.string(),
- container_id: z.string(),
- code: z.string().nullable(),
- outputs: z
- .array(
- z.discriminatedUnion('type', [
- z.object({ type: z.literal('logs'), logs: z.string() }),
- z.object({ type: z.literal('image'), url: z.string() }),
- ]),
- )
- .nullable(),
- status: z.string(),
- }),
- z.object({
- type: z.literal('mcp_call'),
- id: z.string(),
- status: z.string(),
- approval_request_id: z.string().nullish(),
- }),
- z.object({
- type: z.literal('mcp_list_tools'),
- id: z.string(),
- }),
- z.object({
- type: z.literal('mcp_approval_request'),
- id: z.string(),
- }),
- z.object({
- type: z.literal('apply_patch_call'),
- id: z.string(),
- call_id: z.string(),
- status: z.enum(['in_progress', 'completed']),
- operation: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('create_file'),
- path: z.string(),
- diff: z.string(),
- }),
- z.object({
- type: z.literal('delete_file'),
- path: z.string(),
- }),
- z.object({
- type: z.literal('update_file'),
- path: z.string(),
- diff: z.string(),
- }),
- ]),
- }),
- z.object({
- type: z.literal('custom_tool_call'),
- id: z.string(),
- call_id: z.string(),
- name: z.string(),
- input: z.string(),
- }),
- z.object({
- type: z.literal('shell_call'),
- id: z.string(),
- call_id: z.string(),
- status: z.enum(['in_progress', 'completed', 'incomplete']),
- action: z.object({
- commands: z.array(z.string()),
- }),
- }),
- z.object({
- type: z.literal('shell_call_output'),
- id: z.string(),
- call_id: z.string(),
- status: z.enum(['in_progress', 'completed', 'incomplete']),
- output: z.array(
- z.object({
- stdout: z.string(),
- stderr: z.string(),
- outcome: z.discriminatedUnion('type', [
- z.object({ type: z.literal('timeout') }),
- z.object({
- type: z.literal('exit'),
- exit_code: z.number(),
- }),
- ]),
- }),
- ),
- }),
- z.object({
- type: z.literal('tool_search_call'),
- id: z.string(),
- execution: z.enum(['server', 'client']),
- call_id: z.string().nullable(),
- status: z.enum(['in_progress', 'completed', 'incomplete']),
- arguments: z.unknown(),
- }),
- z.object({
- type: z.literal('tool_search_output'),
- id: z.string(),
- execution: z.enum(['server', 'client']),
- call_id: z.string().nullable(),
- status: z.enum(['in_progress', 'completed', 'incomplete']),
- tools: z.array(z.record(z.string(), jsonValueSchema.optional())),
- }),
- ]),
- }),
- z.object({
- type: z.literal('response.output_item.done'),
- output_index: z.number(),
- item: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('message'),
- id: z.string(),
- phase: z.enum(['commentary', 'final_answer']).nullish(),
- }),
- z.object({
- type: z.literal('reasoning'),
- id: z.string(),
- encrypted_content: z.string().nullish(),
- }),
- z.object({
- type: z.literal('function_call'),
- id: z.string(),
- call_id: z.string(),
- name: z.string(),
- arguments: z.string(),
- status: z.literal('completed'),
- }),
- z.object({
- type: z.literal('custom_tool_call'),
- id: z.string(),
- call_id: z.string(),
- name: z.string(),
- input: z.string(),
- status: z.literal('completed'),
- }),
- z.object({
- type: z.literal('code_interpreter_call'),
- id: z.string(),
- code: z.string().nullable(),
- container_id: z.string(),
- outputs: z
- .array(
- z.discriminatedUnion('type', [
- z.object({ type: z.literal('logs'), logs: z.string() }),
- z.object({ type: z.literal('image'), url: z.string() }),
- ]),
- )
- .nullable(),
- }),
- z.object({
- type: z.literal('image_generation_call'),
- id: z.string(),
- result: z.string(),
- }),
- z.object({
- type: z.literal('web_search_call'),
- id: z.string(),
- status: z.string(),
- action: z
- .discriminatedUnion('type', [
- z.object({
- type: z.literal('search'),
- query: z.string().nullish(),
- sources: z
- .array(
- z.discriminatedUnion('type', [
- z.object({ type: z.literal('url'), url: z.string() }),
- z.object({ type: z.literal('api'), name: z.string() }),
- ]),
- )
- .nullish(),
- }),
- z.object({
- type: z.literal('open_page'),
- url: z.string().nullish(),
- }),
- z.object({
- type: z.literal('find_in_page'),
- url: z.string().nullish(),
- pattern: z.string().nullish(),
- }),
- ])
- .nullish(),
- }),
- z.object({
- type: z.literal('file_search_call'),
- id: z.string(),
- queries: z.array(z.string()),
- results: z
- .array(
- z.object({
- attributes: z.record(
- z.string(),
- z.union([z.string(), z.number(), z.boolean()]),
- ),
- file_id: z.string(),
- filename: z.string(),
- score: z.number(),
- text: z.string(),
- }),
- )
- .nullish(),
- }),
- z.object({
- type: z.literal('local_shell_call'),
- id: z.string(),
- call_id: z.string(),
- action: z.object({
- type: z.literal('exec'),
- command: z.array(z.string()),
- timeout_ms: z.number().optional(),
- user: z.string().optional(),
- working_directory: z.string().optional(),
- env: z.record(z.string(), z.string()).optional(),
- }),
- }),
- z.object({
- type: z.literal('computer_call'),
- id: z.string(),
- status: z.literal('completed'),
- }),
- z.object({
- type: z.literal('mcp_call'),
- id: z.string(),
- status: z.string(),
- arguments: z.string(),
- name: z.string(),
- server_label: z.string(),
- output: z.string().nullish(),
- error: z
- .union([
- z.string(),
- z
- .object({
- type: z.string().optional(),
- code: z.union([z.number(), z.string()]).optional(),
- message: z.string().optional(),
- })
- .loose(),
- ])
- .nullish(),
- approval_request_id: z.string().nullish(),
- }),
- z.object({
- type: z.literal('mcp_list_tools'),
- id: z.string(),
- server_label: z.string(),
- tools: z.array(
- z.object({
- name: z.string(),
- description: z.string().optional(),
- input_schema: z.any(),
- annotations: z.record(z.string(), z.unknown()).optional(),
- }),
- ),
- error: z
- .union([
- z.string(),
- z
- .object({
- type: z.string().optional(),
- code: z.union([z.number(), z.string()]).optional(),
- message: z.string().optional(),
- })
- .loose(),
- ])
- .optional(),
- }),
- z.object({
- type: z.literal('mcp_approval_request'),
- id: z.string(),
- server_label: z.string(),
- name: z.string(),
- arguments: z.string(),
- approval_request_id: z.string().optional(),
- }),
- z.object({
- type: z.literal('apply_patch_call'),
- id: z.string(),
- call_id: z.string(),
- status: z.enum(['in_progress', 'completed']),
- operation: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('create_file'),
- path: z.string(),
- diff: z.string(),
- }),
- z.object({
- type: z.literal('delete_file'),
- path: z.string(),
- }),
- z.object({
- type: z.literal('update_file'),
- path: z.string(),
- diff: z.string(),
- }),
- ]),
- }),
- z.object({
- type: z.literal('shell_call'),
- id: z.string(),
- call_id: z.string(),
- status: z.enum(['in_progress', 'completed', 'incomplete']),
- action: z.object({
- commands: z.array(z.string()),
- }),
- }),
- z.object({
- type: z.literal('shell_call_output'),
- id: z.string(),
- call_id: z.string(),
- status: z.enum(['in_progress', 'completed', 'incomplete']),
- output: z.array(
- z.object({
- stdout: z.string(),
- stderr: z.string(),
- outcome: z.discriminatedUnion('type', [
- z.object({ type: z.literal('timeout') }),
- z.object({
- type: z.literal('exit'),
- exit_code: z.number(),
- }),
- ]),
- }),
- ),
- }),
- z.object({
- type: z.literal('tool_search_call'),
- id: z.string(),
- execution: z.enum(['server', 'client']),
- call_id: z.string().nullable(),
- status: z.enum(['in_progress', 'completed', 'incomplete']),
- arguments: z.unknown(),
- }),
- z.object({
- type: z.literal('tool_search_output'),
- id: z.string(),
- execution: z.enum(['server', 'client']),
- call_id: z.string().nullable(),
- status: z.enum(['in_progress', 'completed', 'incomplete']),
- tools: z.array(z.record(z.string(), jsonValueSchema.optional())),
- }),
- ]),
- }),
- z.object({
- type: z.literal('response.function_call_arguments.delta'),
- item_id: z.string(),
- output_index: z.number(),
- delta: z.string(),
- }),
- z.object({
- type: z.literal('response.custom_tool_call_input.delta'),
- item_id: z.string(),
- output_index: z.number(),
- delta: z.string(),
- }),
- z.object({
- type: z.literal('response.image_generation_call.partial_image'),
- item_id: z.string(),
- output_index: z.number(),
- partial_image_b64: z.string(),
- }),
- z.object({
- type: z.literal('response.code_interpreter_call_code.delta'),
- item_id: z.string(),
- output_index: z.number(),
- delta: z.string(),
- }),
- z.object({
- type: z.literal('response.code_interpreter_call_code.done'),
- item_id: z.string(),
- output_index: z.number(),
- code: z.string(),
- }),
- z.object({
- type: z.literal('response.output_text.annotation.added'),
- annotation: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('url_citation'),
- start_index: z.number(),
- end_index: z.number(),
- url: z.string(),
- title: z.string(),
- }),
- z.object({
- type: z.literal('file_citation'),
- file_id: z.string(),
- filename: z.string(),
- index: z.number(),
- }),
- z.object({
- type: z.literal('container_file_citation'),
- container_id: z.string(),
- file_id: z.string(),
- filename: z.string(),
- start_index: z.number(),
- end_index: z.number(),
- }),
- z.object({
- type: z.literal('file_path'),
- file_id: z.string(),
- index: z.number(),
- }),
- ]),
- }),
- z.object({
- type: z.literal('response.reasoning_summary_part.added'),
- item_id: z.string(),
- summary_index: z.number(),
- }),
- z.object({
- type: z.literal('response.reasoning_summary_text.delta'),
- item_id: z.string(),
- summary_index: z.number(),
- delta: z.string(),
- }),
- z.object({
- type: z.literal('response.reasoning_summary_part.done'),
- item_id: z.string(),
- summary_index: z.number(),
- }),
- z.object({
- type: z.literal('response.apply_patch_call_operation_diff.delta'),
- item_id: z.string(),
- output_index: z.number(),
- delta: z.string(),
- obfuscation: z.string().nullish(),
- }),
- z.object({
- type: z.literal('response.apply_patch_call_operation_diff.done'),
- item_id: z.string(),
- output_index: z.number(),
- diff: z.string(),
- }),
- z.object({
- type: z.literal('error'),
- sequence_number: z.number(),
- error: z.object({
- type: z.string(),
- code: z.string(),
- message: z.string(),
- param: z.string().nullish(),
- }),
- }),
- z
- .object({ type: z.string() })
- .loose()
- .transform(value => ({
- type: 'unknown_chunk' as const,
- message: value.type,
- })), // fallback for unknown chunks
- ]),
- ),
-);
-
-export type OpenAIResponsesChunk = InferSchema<
- typeof openaiResponsesChunkSchema
->;
-
-export type OpenAIResponsesLogprobs = NonNullable<
- (OpenAIResponsesChunk & {
- type: 'response.output_text.delta';
- })['logprobs']
-> | null;
-
-export type OpenAIResponsesWebSearchAction = NonNullable<
- ((OpenAIResponsesChunk & {
- type: 'response.output_item.done';
- })['item'] & {
- type: 'web_search_call';
- })['action']
->;
-
-export const openaiResponsesResponseSchema = lazySchema(() =>
- zodSchema(
- z.object({
- id: z.string().optional(),
- created_at: z.number().optional(),
- error: z
- .object({
- message: z.string(),
- type: z.string(),
- param: z.string().nullish(),
- code: z.string(),
- })
- .nullish(),
- model: z.string().optional(),
- output: z
- .array(
- z.discriminatedUnion('type', [
- z.object({
- type: z.literal('message'),
- role: z.literal('assistant'),
- id: z.string(),
- phase: z.enum(['commentary', 'final_answer']).nullish(),
- content: z.array(
- z.object({
- type: z.literal('output_text'),
- text: z.string(),
- logprobs: z
- .array(
- z.object({
- token: z.string(),
- logprob: z.number(),
- top_logprobs: z.array(
- z.object({
- token: z.string(),
- logprob: z.number(),
- }),
- ),
- }),
- )
- .nullish(),
- annotations: z.array(
- z.discriminatedUnion('type', [
- z.object({
- type: z.literal('url_citation'),
- start_index: z.number(),
- end_index: z.number(),
- url: z.string(),
- title: z.string(),
- }),
- z.object({
- type: z.literal('file_citation'),
- file_id: z.string(),
- filename: z.string(),
- index: z.number(),
- }),
- z.object({
- type: z.literal('container_file_citation'),
- container_id: z.string(),
- file_id: z.string(),
- filename: z.string(),
- start_index: z.number(),
- end_index: z.number(),
- }),
- z.object({
- type: z.literal('file_path'),
- file_id: z.string(),
- index: z.number(),
- }),
- ]),
- ),
- }),
- ),
- }),
- z.object({
- type: z.literal('web_search_call'),
- id: z.string(),
- status: z.string(),
- action: z
- .discriminatedUnion('type', [
- z.object({
- type: z.literal('search'),
- query: z.string().nullish(),
- sources: z
- .array(
- z.discriminatedUnion('type', [
- z.object({ type: z.literal('url'), url: z.string() }),
- z.object({
- type: z.literal('api'),
- name: z.string(),
- }),
- ]),
- )
- .nullish(),
- }),
- z.object({
- type: z.literal('open_page'),
- url: z.string().nullish(),
- }),
- z.object({
- type: z.literal('find_in_page'),
- url: z.string().nullish(),
- pattern: z.string().nullish(),
- }),
- ])
- .nullish(),
- }),
- z.object({
- type: z.literal('file_search_call'),
- id: z.string(),
- queries: z.array(z.string()),
- results: z
- .array(
- z.object({
- attributes: z.record(
- z.string(),
- z.union([z.string(), z.number(), z.boolean()]),
- ),
- file_id: z.string(),
- filename: z.string(),
- score: z.number(),
- text: z.string(),
- }),
- )
- .nullish(),
- }),
- z.object({
- type: z.literal('code_interpreter_call'),
- id: z.string(),
- code: z.string().nullable(),
- container_id: z.string(),
- outputs: z
- .array(
- z.discriminatedUnion('type', [
- z.object({ type: z.literal('logs'), logs: z.string() }),
- z.object({ type: z.literal('image'), url: z.string() }),
- ]),
- )
- .nullable(),
- }),
- z.object({
- type: z.literal('image_generation_call'),
- id: z.string(),
- result: z.string(),
- }),
- z.object({
- type: z.literal('local_shell_call'),
- id: z.string(),
- call_id: z.string(),
- action: z.object({
- type: z.literal('exec'),
- command: z.array(z.string()),
- timeout_ms: z.number().optional(),
- user: z.string().optional(),
- working_directory: z.string().optional(),
- env: z.record(z.string(), z.string()).optional(),
- }),
- }),
- z.object({
- type: z.literal('function_call'),
- call_id: z.string(),
- name: z.string(),
- arguments: z.string(),
- id: z.string(),
- }),
- z.object({
- type: z.literal('custom_tool_call'),
- call_id: z.string(),
- name: z.string(),
- input: z.string(),
- id: z.string(),
- }),
- z.object({
- type: z.literal('computer_call'),
- id: z.string(),
- status: z.string().optional(),
- }),
- z.object({
- type: z.literal('reasoning'),
- id: z.string(),
- encrypted_content: z.string().nullish(),
- summary: z.array(
- z.object({
- type: z.literal('summary_text'),
- text: z.string(),
- }),
- ),
- }),
- z.object({
- type: z.literal('mcp_call'),
- id: z.string(),
- status: z.string(),
- arguments: z.string(),
- name: z.string(),
- server_label: z.string(),
- output: z.string().nullish(),
- error: z
- .union([
- z.string(),
- z
- .object({
- type: z.string().optional(),
- code: z.union([z.number(), z.string()]).optional(),
- message: z.string().optional(),
- })
- .loose(),
- ])
- .nullish(),
- approval_request_id: z.string().nullish(),
- }),
- z.object({
- type: z.literal('mcp_list_tools'),
- id: z.string(),
- server_label: z.string(),
- tools: z.array(
- z.object({
- name: z.string(),
- description: z.string().optional(),
- input_schema: z.any(),
- annotations: z.record(z.string(), z.unknown()).optional(),
- }),
- ),
- error: z
- .union([
- z.string(),
- z
- .object({
- type: z.string().optional(),
- code: z.union([z.number(), z.string()]).optional(),
- message: z.string().optional(),
- })
- .loose(),
- ])
- .optional(),
- }),
- z.object({
- type: z.literal('mcp_approval_request'),
- id: z.string(),
- server_label: z.string(),
- name: z.string(),
- arguments: z.string(),
- approval_request_id: z.string().optional(),
- }),
- z.object({
- type: z.literal('apply_patch_call'),
- id: z.string(),
- call_id: z.string(),
- status: z.enum(['in_progress', 'completed']),
- operation: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('create_file'),
- path: z.string(),
- diff: z.string(),
- }),
- z.object({
- type: z.literal('delete_file'),
- path: z.string(),
- }),
- z.object({
- type: z.literal('update_file'),
- path: z.string(),
- diff: z.string(),
- }),
- ]),
- }),
- z.object({
- type: z.literal('shell_call'),
- id: z.string(),
- call_id: z.string(),
- status: z.enum(['in_progress', 'completed', 'incomplete']),
- action: z.object({
- commands: z.array(z.string()),
- }),
- }),
- z.object({
- type: z.literal('shell_call_output'),
- id: z.string(),
- call_id: z.string(),
- status: z.enum(['in_progress', 'completed', 'incomplete']),
- output: z.array(
- z.object({
- stdout: z.string(),
- stderr: z.string(),
- outcome: z.discriminatedUnion('type', [
- z.object({ type: z.literal('timeout') }),
- z.object({
- type: z.literal('exit'),
- exit_code: z.number(),
- }),
- ]),
- }),
- ),
- }),
- z.object({
- type: z.literal('tool_search_call'),
- id: z.string(),
- execution: z.enum(['server', 'client']),
- call_id: z.string().nullable(),
- status: z.enum(['in_progress', 'completed', 'incomplete']),
- arguments: z.unknown(),
- }),
- z.object({
- type: z.literal('tool_search_output'),
- id: z.string(),
- execution: z.enum(['server', 'client']),
- call_id: z.string().nullable(),
- status: z.enum(['in_progress', 'completed', 'incomplete']),
- tools: z.array(z.record(z.string(), jsonValueSchema.optional())),
- }),
- ]),
- )
- .optional(),
- service_tier: z.string().nullish(),
- incomplete_details: z.object({ reason: z.string() }).nullish(),
- usage: z
- .object({
- input_tokens: z.number(),
- input_tokens_details: z
- .object({ cached_tokens: z.number().nullish() })
- .nullish(),
- output_tokens: z.number(),
- output_tokens_details: z
- .object({ reasoning_tokens: z.number().nullish() })
- .nullish(),
- })
- .optional(),
- }),
- ),
-);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-language-model.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-language-model.ts
deleted file mode 100644
index fe9616c81..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-language-model.ts
+++ /dev/null
@@ -1,2256 +0,0 @@
-import {
- APICallError,
- JSONValue,
- LanguageModelV3,
- LanguageModelV3Prompt,
- LanguageModelV3CallOptions,
- LanguageModelV3Content,
- LanguageModelV3FinishReason,
- LanguageModelV3GenerateResult,
- LanguageModelV3ProviderTool,
- LanguageModelV3StreamPart,
- LanguageModelV3StreamResult,
- LanguageModelV3ToolApprovalRequest,
- SharedV3ProviderMetadata,
- SharedV3Warning,
-} from '@ai-sdk/provider';
-import {
- combineHeaders,
- createEventSourceResponseHandler,
- createJsonResponseHandler,
- createToolNameMapping,
- generateId,
- InferSchema,
- parseProviderOptions,
- ParseResult,
- postJsonToApi,
-} from '@ai-sdk/provider-utils';
-import { OpenAIConfig } from '../openai-config';
-import { openaiFailedResponseHandler } from '../openai-error';
-import { getOpenAILanguageModelCapabilities } from '../openai-language-model-capabilities';
-import { applyPatchInputSchema } from '../tool/apply-patch';
-import {
- codeInterpreterInputSchema,
- codeInterpreterOutputSchema,
-} from '../tool/code-interpreter';
-import { fileSearchOutputSchema } from '../tool/file-search';
-import { imageGenerationOutputSchema } from '../tool/image-generation';
-import { localShellInputSchema } from '../tool/local-shell';
-import { mcpOutputSchema } from '../tool/mcp';
-import { shellInputSchema, shellOutputSchema } from '../tool/shell';
-import {
- toolSearchInputSchema,
- toolSearchOutputSchema,
-} from '../tool/tool-search';
-import { webSearchOutputSchema } from '../tool/web-search';
-import {
- convertOpenAIResponsesUsage,
- OpenAIResponsesUsage,
-} from './convert-openai-responses-usage';
-import { convertToOpenAIResponsesInput } from './convert-to-openai-responses-input';
-import { mapOpenAIResponseFinishReason } from './map-openai-responses-finish-reason';
-import {
- OpenAIResponsesChunk,
- openaiResponsesChunkSchema,
- OpenAIResponsesIncludeOptions,
- OpenAIResponsesIncludeValue,
- OpenAIResponsesLogprobs,
- openaiResponsesResponseSchema,
- OpenAIResponsesWebSearchAction,
- OpenAIResponsesApplyPatchOperationDiffDeltaChunk,
- OpenAIResponsesApplyPatchOperationDiffDoneChunk,
-} from './openai-responses-api';
-import {
- OpenAIResponsesModelId,
- openaiLanguageModelResponsesOptionsSchema,
- TOP_LOGPROBS_MAX,
-} from './openai-responses-options';
-import { prepareResponsesTools } from './openai-responses-prepare-tools';
-import {
- ResponsesProviderMetadata,
- ResponsesReasoningProviderMetadata,
- ResponsesSourceDocumentProviderMetadata,
- ResponsesTextProviderMetadata,
-} from './openai-responses-provider-metadata';
-
-/**
- * Extracts a mapping from MCP approval request IDs to their corresponding tool call IDs
- * from the prompt. When an MCP tool requires approval, we generate a tool call ID to track
- * the pending approval in our system. When the user responds to the approval (and we
- * continue the conversation), we need to map the approval request ID back to our tool call ID
- * so that tool results reference the correct tool call.
- */
-function extractApprovalRequestIdToToolCallIdMapping(
- prompt: LanguageModelV3Prompt,
-): Record {
- const mapping: Record = {};
- for (const message of prompt) {
- if (message.role !== 'assistant') continue;
- for (const part of message.content) {
- if (part.type !== 'tool-call') continue;
- const approvalRequestId = part.providerOptions?.openai
- ?.approvalRequestId as string | undefined;
- if (approvalRequestId != null) {
- mapping[approvalRequestId] = part.toolCallId;
- }
- }
- }
- return mapping;
-}
-
-export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
- readonly specificationVersion = 'v3';
-
- readonly modelId: OpenAIResponsesModelId;
-
- private readonly config: OpenAIConfig;
-
- constructor(modelId: OpenAIResponsesModelId, config: OpenAIConfig) {
- this.modelId = modelId;
- this.config = config;
- }
-
- readonly supportedUrls: Record = {
- 'image/*': [/^https?:\/\/.*$/],
- 'application/pdf': [/^https?:\/\/.*$/],
- };
-
- get provider(): string {
- return this.config.provider;
- }
-
- private async getArgs({
- maxOutputTokens,
- temperature,
- stopSequences,
- topP,
- topK,
- presencePenalty,
- frequencyPenalty,
- seed,
- prompt,
- providerOptions,
- tools,
- toolChoice,
- responseFormat,
- }: LanguageModelV3CallOptions) {
- const warnings: SharedV3Warning[] = [];
- const modelCapabilities = getOpenAILanguageModelCapabilities(this.modelId);
-
- if (topK != null) {
- warnings.push({ type: 'unsupported', feature: 'topK' });
- }
-
- if (seed != null) {
- warnings.push({ type: 'unsupported', feature: 'seed' });
- }
-
- if (presencePenalty != null) {
- warnings.push({ type: 'unsupported', feature: 'presencePenalty' });
- }
-
- if (frequencyPenalty != null) {
- warnings.push({ type: 'unsupported', feature: 'frequencyPenalty' });
- }
-
- if (stopSequences != null) {
- warnings.push({ type: 'unsupported', feature: 'stopSequences' });
- }
-
- const providerOptionsName = this.config.provider.includes('azure')
- ? 'azure'
- : 'openai';
- let openaiOptions = await parseProviderOptions({
- provider: providerOptionsName,
- providerOptions,
- schema: openaiLanguageModelResponsesOptionsSchema,
- });
-
- if (openaiOptions == null && providerOptionsName !== 'openai') {
- openaiOptions = await parseProviderOptions({
- provider: 'openai',
- providerOptions,
- schema: openaiLanguageModelResponsesOptionsSchema,
- });
- }
-
- const isReasoningModel =
- openaiOptions?.forceReasoning ?? modelCapabilities.isReasoningModel;
-
- if (openaiOptions?.conversation && openaiOptions?.previousResponseId) {
- warnings.push({
- type: 'unsupported',
- feature: 'conversation',
- details: 'conversation and previousResponseId cannot be used together',
- });
- }
-
- const toolNameMapping = createToolNameMapping({
- tools,
- providerToolNames: {
- 'openai.code_interpreter': 'code_interpreter',
- 'openai.file_search': 'file_search',
- 'openai.image_generation': 'image_generation',
- 'openai.local_shell': 'local_shell',
- 'openai.shell': 'shell',
- 'openai.web_search': 'web_search',
- 'openai.web_search_preview': 'web_search_preview',
- 'openai.mcp': 'mcp',
- 'openai.apply_patch': 'apply_patch',
- 'openai.tool_search': 'tool_search',
- },
- resolveProviderToolName: tool =>
- tool.id === 'openai.custom'
- ? (tool.args as { name?: string }).name
- : undefined,
- });
-
- const customProviderToolNames = new Set();
- const {
- tools: openaiTools,
- toolChoice: openaiToolChoice,
- toolWarnings,
- } = await prepareResponsesTools({
- tools,
- toolChoice,
- toolNameMapping,
- customProviderToolNames,
- });
-
- const { input, warnings: inputWarnings } =
- await convertToOpenAIResponsesInput({
- prompt,
- toolNameMapping,
- systemMessageMode:
- openaiOptions?.systemMessageMode ??
- (isReasoningModel
- ? 'developer'
- : modelCapabilities.systemMessageMode),
- providerOptionsName,
- fileIdPrefixes: this.config.fileIdPrefixes,
- store: openaiOptions?.store ?? true,
- hasConversation: openaiOptions?.conversation != null,
- hasLocalShellTool: hasOpenAITool('openai.local_shell'),
- hasShellTool: hasOpenAITool('openai.shell'),
- hasApplyPatchTool: hasOpenAITool('openai.apply_patch'),
- customProviderToolNames:
- customProviderToolNames.size > 0
- ? customProviderToolNames
- : undefined,
- });
-
- warnings.push(...inputWarnings);
-
- const strictJsonSchema = openaiOptions?.strictJsonSchema ?? true;
-
- let include: OpenAIResponsesIncludeOptions = openaiOptions?.include;
-
- function addInclude(key: OpenAIResponsesIncludeValue) {
- if (include == null) {
- include = [key];
- } else if (!include.includes(key)) {
- include = [...include, key];
- }
- }
-
- function hasOpenAITool(id: string) {
- return (
- tools?.find(tool => tool.type === 'provider' && tool.id === id) != null
- );
- }
-
- // when logprobs are requested, automatically include them:
- const topLogprobs =
- typeof openaiOptions?.logprobs === 'number'
- ? openaiOptions?.logprobs
- : openaiOptions?.logprobs === true
- ? TOP_LOGPROBS_MAX
- : undefined;
-
- if (topLogprobs) {
- addInclude('message.output_text.logprobs');
- }
-
- // when a web search tool is present, automatically include the sources:
- const webSearchToolName = (
- tools?.find(
- tool =>
- tool.type === 'provider' &&
- (tool.id === 'openai.web_search' ||
- tool.id === 'openai.web_search_preview'),
- ) as LanguageModelV3ProviderTool | undefined
- )?.name;
-
- if (webSearchToolName) {
- addInclude('web_search_call.action.sources');
- }
-
- // when a code interpreter tool is present, automatically include the outputs:
- if (hasOpenAITool('openai.code_interpreter')) {
- addInclude('code_interpreter_call.outputs');
- }
-
- const store = openaiOptions?.store;
-
- // store defaults to true in the OpenAI responses API, so check for false exactly:
- if (store === false && isReasoningModel) {
- addInclude('reasoning.encrypted_content');
- }
-
- const baseArgs = {
- model: this.modelId,
- input,
- temperature,
- top_p: topP,
- max_output_tokens: maxOutputTokens,
-
- ...((responseFormat?.type === 'json' || openaiOptions?.textVerbosity) && {
- text: {
- ...(responseFormat?.type === 'json' && {
- format:
- responseFormat.schema != null
- ? {
- type: 'json_schema',
- strict: strictJsonSchema,
- name: responseFormat.name ?? 'response',
- description: responseFormat.description,
- schema: responseFormat.schema,
- }
- : { type: 'json_object' },
- }),
- ...(openaiOptions?.textVerbosity && {
- verbosity: openaiOptions.textVerbosity,
- }),
- },
- }),
-
- // provider options:
- conversation: openaiOptions?.conversation,
- max_tool_calls: openaiOptions?.maxToolCalls,
- metadata: openaiOptions?.metadata,
- parallel_tool_calls: openaiOptions?.parallelToolCalls,
- previous_response_id: openaiOptions?.previousResponseId,
- store,
- user: openaiOptions?.user,
- instructions: openaiOptions?.instructions,
- service_tier: openaiOptions?.serviceTier,
- include,
- prompt_cache_key: openaiOptions?.promptCacheKey,
- prompt_cache_retention: openaiOptions?.promptCacheRetention,
- safety_identifier: openaiOptions?.safetyIdentifier,
- top_logprobs: topLogprobs,
- truncation: openaiOptions?.truncation,
-
- // model-specific settings:
- ...(isReasoningModel &&
- (openaiOptions?.reasoningEffort != null ||
- openaiOptions?.reasoningSummary != null) && {
- reasoning: {
- ...(openaiOptions?.reasoningEffort != null && {
- effort: openaiOptions.reasoningEffort,
- }),
- ...(openaiOptions?.reasoningSummary != null && {
- summary: openaiOptions.reasoningSummary,
- }),
- },
- }),
- };
-
- // remove unsupported settings for reasoning models
- // see https://platform.openai.com/docs/guides/reasoning#limitations
- if (isReasoningModel) {
- // when reasoning effort is none, gpt-5.1 models allow temperature, topP, logprobs
- // https://platform.openai.com/docs/guides/latest-model#gpt-5-1-parameter-compatibility
- if (
- !(
- openaiOptions?.reasoningEffort === 'none' &&
- modelCapabilities.supportsNonReasoningParameters
- )
- ) {
- if (baseArgs.temperature != null) {
- baseArgs.temperature = undefined;
- warnings.push({
- type: 'unsupported',
- feature: 'temperature',
- details: 'temperature is not supported for reasoning models',
- });
- }
-
- if (baseArgs.top_p != null) {
- baseArgs.top_p = undefined;
- warnings.push({
- type: 'unsupported',
- feature: 'topP',
- details: 'topP is not supported for reasoning models',
- });
- }
- }
- } else {
- if (openaiOptions?.reasoningEffort != null) {
- warnings.push({
- type: 'unsupported',
- feature: 'reasoningEffort',
- details: 'reasoningEffort is not supported for non-reasoning models',
- });
- }
-
- if (openaiOptions?.reasoningSummary != null) {
- warnings.push({
- type: 'unsupported',
- feature: 'reasoningSummary',
- details: 'reasoningSummary is not supported for non-reasoning models',
- });
- }
- }
-
- // Validate flex processing support
- if (
- openaiOptions?.serviceTier === 'flex' &&
- !modelCapabilities.supportsFlexProcessing
- ) {
- warnings.push({
- type: 'unsupported',
- feature: 'serviceTier',
- details:
- 'flex processing is only available for o3, o4-mini, and gpt-5 models',
- });
- // Remove from args if not supported
- delete (baseArgs as any).service_tier;
- }
-
- // Validate priority processing support
- if (
- openaiOptions?.serviceTier === 'priority' &&
- !modelCapabilities.supportsPriorityProcessing
- ) {
- warnings.push({
- type: 'unsupported',
- feature: 'serviceTier',
- details:
- 'priority processing is only available for supported models (gpt-4, gpt-5, gpt-5-mini, o3, o4-mini) and requires Enterprise access. gpt-5-nano is not supported',
- });
- // Remove from args if not supported
- delete (baseArgs as any).service_tier;
- }
-
- const shellToolEnvType = (
- tools?.find(
- tool => tool.type === 'provider' && tool.id === 'openai.shell',
- ) as { args?: { environment?: { type?: string } } } | undefined
- )?.args?.environment?.type;
-
- const isShellProviderExecuted =
- shellToolEnvType === 'containerAuto' ||
- shellToolEnvType === 'containerReference';
-
- return {
- webSearchToolName,
- args: {
- ...baseArgs,
- tools: openaiTools,
- tool_choice: openaiToolChoice,
- },
- warnings: [...warnings, ...toolWarnings],
- store,
- toolNameMapping,
- providerOptionsName,
- isShellProviderExecuted,
- };
- }
-
- async doGenerate(
- options: LanguageModelV3CallOptions,
- ): Promise {
- const {
- args: body,
- warnings,
- webSearchToolName,
- toolNameMapping,
- providerOptionsName,
- isShellProviderExecuted,
- } = await this.getArgs(options);
- const url = this.config.url({
- path: '/responses',
- modelId: this.modelId,
- });
-
- const approvalRequestIdToDummyToolCallIdFromPrompt =
- extractApprovalRequestIdToToolCallIdMapping(options.prompt);
-
- const {
- responseHeaders,
- value: response,
- rawValue: rawResponse,
- } = await postJsonToApi({
- url,
- headers: combineHeaders(this.config.headers(), options.headers),
- body,
- failedResponseHandler: openaiFailedResponseHandler,
- successfulResponseHandler: createJsonResponseHandler(
- openaiResponsesResponseSchema,
- ),
- abortSignal: options.abortSignal,
- fetch: this.config.fetch,
- });
-
- if (response.error) {
- throw new APICallError({
- message: response.error.message,
- url,
- requestBodyValues: body,
- statusCode: 400,
- responseHeaders,
- responseBody: rawResponse as string,
- isRetryable: false,
- });
- }
-
- const content: Array = [];
- const logprobs: Array = [];
-
- // flag that checks if there have been client-side tool calls (not executed by openai)
- let hasFunctionCall = false;
- const hostedToolSearchCallIds: string[] = [];
-
- // map response content to content array (defined when there is no error)
- for (const part of response.output!) {
- switch (part.type) {
- case 'reasoning': {
- // when there are no summary parts, we need to add an empty reasoning part:
- if (part.summary.length === 0) {
- part.summary.push({ type: 'summary_text', text: '' });
- }
-
- for (const summary of part.summary) {
- content.push({
- type: 'reasoning' as const,
- text: summary.text,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: part.id,
- reasoningEncryptedContent: part.encrypted_content ?? null,
- } satisfies ResponsesReasoningProviderMetadata,
- },
- });
- }
- break;
- }
-
- case 'image_generation_call': {
- content.push({
- type: 'tool-call',
- toolCallId: part.id,
- toolName: toolNameMapping.toCustomToolName('image_generation'),
- input: '{}',
- providerExecuted: true,
- });
-
- content.push({
- type: 'tool-result',
- toolCallId: part.id,
- toolName: toolNameMapping.toCustomToolName('image_generation'),
- result: {
- result: part.result,
- } satisfies InferSchema,
- });
-
- break;
- }
-
- case 'tool_search_call': {
- const toolCallId = part.call_id ?? part.id;
- const isHosted = part.execution === 'server';
-
- if (isHosted) {
- hostedToolSearchCallIds.push(toolCallId);
- }
-
- content.push({
- type: 'tool-call',
- toolCallId,
- toolName: toolNameMapping.toCustomToolName('tool_search'),
- input: JSON.stringify({
- arguments: part.arguments,
- call_id: part.call_id,
- } satisfies InferSchema),
- ...(isHosted ? { providerExecuted: true } : {}),
- providerMetadata: {
- [providerOptionsName]: {
- itemId: part.id,
- },
- },
- });
-
- break;
- }
-
- case 'tool_search_output': {
- const toolCallId =
- part.call_id ?? hostedToolSearchCallIds.shift() ?? part.id;
-
- content.push({
- type: 'tool-result',
- toolCallId,
- toolName: toolNameMapping.toCustomToolName('tool_search'),
- result: {
- tools: part.tools,
- } satisfies InferSchema,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: part.id,
- },
- },
- });
-
- break;
- }
-
- case 'local_shell_call': {
- content.push({
- type: 'tool-call',
- toolCallId: part.call_id,
- toolName: toolNameMapping.toCustomToolName('local_shell'),
- input: JSON.stringify({
- action: part.action,
- } satisfies InferSchema),
- providerMetadata: {
- [providerOptionsName]: {
- itemId: part.id,
- },
- },
- });
-
- break;
- }
-
- case 'shell_call': {
- content.push({
- type: 'tool-call',
- toolCallId: part.call_id,
- toolName: toolNameMapping.toCustomToolName('shell'),
- input: JSON.stringify({
- action: {
- commands: part.action.commands,
- },
- } satisfies InferSchema),
- ...(isShellProviderExecuted && { providerExecuted: true }),
- providerMetadata: {
- [providerOptionsName]: {
- itemId: part.id,
- },
- },
- });
-
- break;
- }
-
- case 'shell_call_output': {
- content.push({
- type: 'tool-result',
- toolCallId: part.call_id,
- toolName: toolNameMapping.toCustomToolName('shell'),
- result: {
- output: part.output.map(item => ({
- stdout: item.stdout,
- stderr: item.stderr,
- outcome:
- item.outcome.type === 'exit'
- ? {
- type: 'exit' as const,
- exitCode: item.outcome.exit_code,
- }
- : { type: 'timeout' as const },
- })),
- } satisfies InferSchema,
- });
- break;
- }
-
- case 'message': {
- for (const contentPart of part.content) {
- if (
- options.providerOptions?.[providerOptionsName]?.logprobs &&
- contentPart.logprobs
- ) {
- logprobs.push(contentPart.logprobs);
- }
-
- const providerMetadata: SharedV3ProviderMetadata[string] = {
- itemId: part.id,
- ...(part.phase != null && { phase: part.phase }),
- ...(contentPart.annotations.length > 0 && {
- annotations: contentPart.annotations,
- }),
- } satisfies ResponsesTextProviderMetadata;
-
- content.push({
- type: 'text',
- text: contentPart.text,
- providerMetadata: {
- [providerOptionsName]: providerMetadata,
- },
- });
-
- for (const annotation of contentPart.annotations) {
- if (annotation.type === 'url_citation') {
- content.push({
- type: 'source',
- sourceType: 'url',
- id: this.config.generateId?.() ?? generateId(),
- url: annotation.url,
- title: annotation.title,
- });
- } else if (annotation.type === 'file_citation') {
- content.push({
- type: 'source',
- sourceType: 'document',
- id: this.config.generateId?.() ?? generateId(),
- mediaType: 'text/plain',
- title: annotation.filename,
- filename: annotation.filename,
- providerMetadata: {
- [providerOptionsName]: {
- type: annotation.type,
- fileId: annotation.file_id,
- index: annotation.index,
- } satisfies Extract<
- ResponsesSourceDocumentProviderMetadata,
- { type: 'file_citation' }
- >,
- },
- });
- } else if (annotation.type === 'container_file_citation') {
- content.push({
- type: 'source',
- sourceType: 'document',
- id: this.config.generateId?.() ?? generateId(),
- mediaType: 'text/plain',
- title: annotation.filename,
- filename: annotation.filename,
- providerMetadata: {
- [providerOptionsName]: {
- type: annotation.type,
- fileId: annotation.file_id,
- containerId: annotation.container_id,
- } satisfies Extract<
- ResponsesSourceDocumentProviderMetadata,
- { type: 'container_file_citation' }
- >,
- },
- });
- } else if (annotation.type === 'file_path') {
- content.push({
- type: 'source',
- sourceType: 'document',
- id: this.config.generateId?.() ?? generateId(),
- mediaType: 'application/octet-stream',
- title: annotation.file_id,
- filename: annotation.file_id,
- providerMetadata: {
- [providerOptionsName]: {
- type: annotation.type,
- fileId: annotation.file_id,
- index: annotation.index,
- } satisfies Extract<
- ResponsesSourceDocumentProviderMetadata,
- { type: 'file_path' }
- >,
- },
- });
- }
- }
- }
-
- break;
- }
-
- case 'function_call': {
- hasFunctionCall = true;
-
- content.push({
- type: 'tool-call',
- toolCallId: part.call_id,
- toolName: part.name,
- input: part.arguments,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: part.id,
- },
- },
- });
- break;
- }
-
- case 'custom_tool_call': {
- hasFunctionCall = true;
- const toolName = toolNameMapping.toCustomToolName(part.name);
-
- content.push({
- type: 'tool-call',
- toolCallId: part.call_id,
- toolName,
- input: JSON.stringify(part.input),
- providerMetadata: {
- [providerOptionsName]: {
- itemId: part.id,
- },
- },
- });
- break;
- }
-
- case 'web_search_call': {
- content.push({
- type: 'tool-call',
- toolCallId: part.id,
- toolName: toolNameMapping.toCustomToolName(
- webSearchToolName ?? 'web_search',
- ),
- input: JSON.stringify({}),
- providerExecuted: true,
- });
-
- content.push({
- type: 'tool-result',
- toolCallId: part.id,
- toolName: toolNameMapping.toCustomToolName(
- webSearchToolName ?? 'web_search',
- ),
- result: mapWebSearchOutput(part.action),
- });
-
- break;
- }
-
- case 'mcp_call': {
- const toolCallId =
- part.approval_request_id != null
- ? (approvalRequestIdToDummyToolCallIdFromPrompt[
- part.approval_request_id
- ] ?? part.id)
- : part.id;
-
- const toolName = `mcp.${part.name}`;
-
- content.push({
- type: 'tool-call',
- toolCallId,
- toolName,
- input: part.arguments,
- providerExecuted: true,
- dynamic: true,
- });
-
- content.push({
- type: 'tool-result',
- toolCallId,
- toolName,
- result: {
- type: 'call',
- serverLabel: part.server_label,
- name: part.name,
- arguments: part.arguments,
- ...(part.output != null ? { output: part.output } : {}),
- ...(part.error != null
- ? { error: part.error as unknown as JSONValue }
- : {}),
- } satisfies InferSchema,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: part.id,
- },
- },
- });
- break;
- }
-
- case 'mcp_list_tools': {
- // skip
- break;
- }
-
- case 'mcp_approval_request': {
- const approvalRequestId = part.approval_request_id ?? part.id;
- const dummyToolCallId = this.config.generateId?.() ?? generateId();
- const toolName = `mcp.${part.name}`;
-
- content.push({
- type: 'tool-call',
- toolCallId: dummyToolCallId,
- toolName,
- input: part.arguments,
- providerExecuted: true,
- dynamic: true,
- });
-
- content.push({
- type: 'tool-approval-request',
- approvalId: approvalRequestId,
- toolCallId: dummyToolCallId,
- } satisfies LanguageModelV3ToolApprovalRequest);
- break;
- }
-
- case 'computer_call': {
- content.push({
- type: 'tool-call',
- toolCallId: part.id,
- toolName: toolNameMapping.toCustomToolName('computer_use'),
- input: '',
- providerExecuted: true,
- });
-
- content.push({
- type: 'tool-result',
- toolCallId: part.id,
- toolName: toolNameMapping.toCustomToolName('computer_use'),
- result: {
- type: 'computer_use_tool_result',
- status: part.status || 'completed',
- },
- });
- break;
- }
-
- case 'file_search_call': {
- content.push({
- type: 'tool-call',
- toolCallId: part.id,
- toolName: toolNameMapping.toCustomToolName('file_search'),
- input: '{}',
- providerExecuted: true,
- });
-
- content.push({
- type: 'tool-result',
- toolCallId: part.id,
- toolName: toolNameMapping.toCustomToolName('file_search'),
- result: {
- queries: part.queries,
- results:
- part.results?.map(result => ({
- attributes: result.attributes,
- fileId: result.file_id,
- filename: result.filename,
- score: result.score,
- text: result.text,
- })) ?? null,
- } satisfies InferSchema,
- });
- break;
- }
-
- case 'code_interpreter_call': {
- content.push({
- type: 'tool-call',
- toolCallId: part.id,
- toolName: toolNameMapping.toCustomToolName('code_interpreter'),
- input: JSON.stringify({
- code: part.code,
- containerId: part.container_id,
- } satisfies InferSchema),
- providerExecuted: true,
- });
-
- content.push({
- type: 'tool-result',
- toolCallId: part.id,
- toolName: toolNameMapping.toCustomToolName('code_interpreter'),
- result: {
- outputs: part.outputs,
- } satisfies InferSchema,
- });
- break;
- }
-
- case 'apply_patch_call': {
- content.push({
- type: 'tool-call',
- toolCallId: part.call_id,
- toolName: toolNameMapping.toCustomToolName('apply_patch'),
- input: JSON.stringify({
- callId: part.call_id,
- operation: part.operation,
- } satisfies InferSchema),
- providerMetadata: {
- [providerOptionsName]: {
- itemId: part.id,
- },
- },
- });
-
- break;
- }
- }
- }
-
- const providerMetadata: SharedV3ProviderMetadata = {
- [providerOptionsName]: {
- responseId: response.id,
- ...(logprobs.length > 0 ? { logprobs } : {}),
- ...(typeof response.service_tier === 'string'
- ? { serviceTier: response.service_tier }
- : {}),
- } satisfies ResponsesProviderMetadata,
- };
-
- const usage = response.usage!; // defined when there is no error
-
- return {
- content,
- finishReason: {
- unified: mapOpenAIResponseFinishReason({
- finishReason: response.incomplete_details?.reason,
- hasFunctionCall,
- }),
- raw: response.incomplete_details?.reason ?? undefined,
- },
- usage: convertOpenAIResponsesUsage(usage),
- request: { body },
- response: {
- id: response.id,
- timestamp: new Date(response.created_at! * 1000),
- modelId: response.model,
- headers: responseHeaders,
- body: rawResponse,
- },
- providerMetadata,
- warnings,
- };
- }
-
- async doStream(
- options: LanguageModelV3CallOptions,
- ): Promise {
- const {
- args: body,
- warnings,
- webSearchToolName,
- toolNameMapping,
- store,
- providerOptionsName,
- isShellProviderExecuted,
- } = await this.getArgs(options);
-
- const { responseHeaders, value: response } = await postJsonToApi({
- url: this.config.url({
- path: '/responses',
- modelId: this.modelId,
- }),
- headers: combineHeaders(this.config.headers(), options.headers),
- body: {
- ...body,
- stream: true,
- },
- failedResponseHandler: openaiFailedResponseHandler,
- successfulResponseHandler: createEventSourceResponseHandler(
- openaiResponsesChunkSchema,
- ),
- abortSignal: options.abortSignal,
- fetch: this.config.fetch,
- });
-
- const self = this;
-
- const approvalRequestIdToDummyToolCallIdFromPrompt =
- extractApprovalRequestIdToToolCallIdMapping(options.prompt);
-
- const approvalRequestIdToDummyToolCallIdFromStream = new Map<
- string,
- string
- >();
-
- let finishReason: LanguageModelV3FinishReason = {
- unified: 'other',
- raw: undefined,
- };
- let usage: OpenAIResponsesUsage | undefined = undefined;
- const logprobs: Array = [];
- let responseId: string | null = null;
-
- const ongoingToolCalls: Record<
- number,
- | {
- toolName: string;
- toolCallId: string;
- codeInterpreter?: {
- containerId: string;
- };
- applyPatch?: {
- hasDiff: boolean;
- endEmitted: boolean;
- };
- toolSearchExecution?: 'server' | 'client';
- }
- | undefined
- > = {};
-
- // set annotations in 'text-end' part providerMetadata.
- const ongoingAnnotations: Array<
- Extract<
- OpenAIResponsesChunk,
- { type: 'response.output_text.annotation.added' }
- >['annotation']
- > = [];
-
- // track the phase of the current message being streamed
- let activeMessagePhase: 'commentary' | 'final_answer' | undefined;
-
- // flag that checks if there have been client-side tool calls (not executed by openai)
- let hasFunctionCall = false;
-
- const activeReasoning: Record<
- string,
- {
- encryptedContent?: string | null;
- // summary index as string to reasoning part state:
- summaryParts: Record;
- }
- > = {};
-
- let serviceTier: string | undefined;
- const hostedToolSearchCallIds: string[] = [];
-
- return {
- stream: response.pipeThrough(
- new TransformStream<
- ParseResult,
- LanguageModelV3StreamPart
- >({
- start(controller) {
- controller.enqueue({ type: 'stream-start', warnings });
- },
-
- transform(chunk, controller) {
- if (options.includeRawChunks) {
- controller.enqueue({ type: 'raw', rawValue: chunk.rawValue });
- }
-
- // handle failed chunk parsing / validation:
- if (!chunk.success) {
- finishReason = { unified: 'error', raw: undefined };
- controller.enqueue({ type: 'error', error: chunk.error });
- return;
- }
-
- const value = chunk.value;
-
- if (isResponseOutputItemAddedChunk(value)) {
- if (value.item.type === 'function_call') {
- ongoingToolCalls[value.output_index] = {
- toolName: value.item.name,
- toolCallId: value.item.call_id,
- };
-
- controller.enqueue({
- type: 'tool-input-start',
- id: value.item.call_id,
- toolName: value.item.name,
- });
- } else if (value.item.type === 'custom_tool_call') {
- const toolName = toolNameMapping.toCustomToolName(
- value.item.name,
- );
- ongoingToolCalls[value.output_index] = {
- toolName,
- toolCallId: value.item.call_id,
- };
-
- controller.enqueue({
- type: 'tool-input-start',
- id: value.item.call_id,
- toolName,
- });
- } else if (value.item.type === 'web_search_call') {
- ongoingToolCalls[value.output_index] = {
- toolName: toolNameMapping.toCustomToolName(
- webSearchToolName ?? 'web_search',
- ),
- toolCallId: value.item.id,
- };
-
- controller.enqueue({
- type: 'tool-input-start',
- id: value.item.id,
- toolName: toolNameMapping.toCustomToolName(
- webSearchToolName ?? 'web_search',
- ),
- providerExecuted: true,
- });
-
- controller.enqueue({
- type: 'tool-input-end',
- id: value.item.id,
- });
-
- controller.enqueue({
- type: 'tool-call',
- toolCallId: value.item.id,
- toolName: toolNameMapping.toCustomToolName(
- webSearchToolName ?? 'web_search',
- ),
- input: JSON.stringify({}),
- providerExecuted: true,
- });
- } else if (value.item.type === 'computer_call') {
- ongoingToolCalls[value.output_index] = {
- toolName: toolNameMapping.toCustomToolName('computer_use'),
- toolCallId: value.item.id,
- };
-
- controller.enqueue({
- type: 'tool-input-start',
- id: value.item.id,
- toolName: toolNameMapping.toCustomToolName('computer_use'),
- providerExecuted: true,
- });
- } else if (value.item.type === 'code_interpreter_call') {
- ongoingToolCalls[value.output_index] = {
- toolName:
- toolNameMapping.toCustomToolName('code_interpreter'),
- toolCallId: value.item.id,
- codeInterpreter: {
- containerId: value.item.container_id,
- },
- };
-
- controller.enqueue({
- type: 'tool-input-start',
- id: value.item.id,
- toolName:
- toolNameMapping.toCustomToolName('code_interpreter'),
- providerExecuted: true,
- });
-
- controller.enqueue({
- type: 'tool-input-delta',
- id: value.item.id,
- delta: `{"containerId":"${value.item.container_id}","code":"`,
- });
- } else if (value.item.type === 'file_search_call') {
- controller.enqueue({
- type: 'tool-call',
- toolCallId: value.item.id,
- toolName: toolNameMapping.toCustomToolName('file_search'),
- input: '{}',
- providerExecuted: true,
- });
- } else if (value.item.type === 'image_generation_call') {
- controller.enqueue({
- type: 'tool-call',
- toolCallId: value.item.id,
- toolName:
- toolNameMapping.toCustomToolName('image_generation'),
- input: '{}',
- providerExecuted: true,
- });
- } else if (value.item.type === 'tool_search_call') {
- const toolCallId = value.item.id;
- const toolName =
- toolNameMapping.toCustomToolName('tool_search');
- const isHosted = value.item.execution === 'server';
-
- ongoingToolCalls[value.output_index] = {
- toolName,
- toolCallId,
- toolSearchExecution: value.item.execution ?? 'server',
- };
-
- if (isHosted) {
- controller.enqueue({
- type: 'tool-input-start',
- id: toolCallId,
- toolName,
- providerExecuted: true,
- });
- }
- } else if (value.item.type === 'tool_search_output') {
- // handled on output_item.done so we can pair it with the call
- } else if (
- value.item.type === 'mcp_call' ||
- value.item.type === 'mcp_list_tools' ||
- value.item.type === 'mcp_approval_request'
- ) {
- // Emit MCP tool-call/approval parts on output_item.done instead, so we can:
- // - alias mcp_call IDs when an approval_request_id is present
- // - emit a proper tool-approval-request part for MCP approvals
- } else if (value.item.type === 'apply_patch_call') {
- const { call_id: callId, operation } = value.item;
-
- ongoingToolCalls[value.output_index] = {
- toolName: toolNameMapping.toCustomToolName('apply_patch'),
- toolCallId: callId,
- applyPatch: {
- // delete_file doesn't have diff
- hasDiff: operation.type === 'delete_file',
- endEmitted: operation.type === 'delete_file',
- },
- };
-
- controller.enqueue({
- type: 'tool-input-start',
- id: callId,
- toolName: toolNameMapping.toCustomToolName('apply_patch'),
- });
-
- if (operation.type === 'delete_file') {
- const inputString = JSON.stringify({
- callId,
- operation,
- } satisfies InferSchema);
-
- controller.enqueue({
- type: 'tool-input-delta',
- id: callId,
- delta: inputString,
- });
-
- controller.enqueue({
- type: 'tool-input-end',
- id: callId,
- });
- } else {
- controller.enqueue({
- type: 'tool-input-delta',
- id: callId,
- delta: `{"callId":"${escapeJSONDelta(callId)}","operation":{"type":"${escapeJSONDelta(operation.type)}","path":"${escapeJSONDelta(operation.path)}","diff":"`,
- });
- }
- } else if (value.item.type === 'shell_call') {
- ongoingToolCalls[value.output_index] = {
- toolName: toolNameMapping.toCustomToolName('shell'),
- toolCallId: value.item.call_id,
- };
- } else if (value.item.type === 'shell_call_output') {
- // shell_call_output is handled in output_item.done
- } else if (value.item.type === 'message') {
- ongoingAnnotations.splice(0, ongoingAnnotations.length);
- activeMessagePhase = value.item.phase ?? undefined;
- controller.enqueue({
- type: 'text-start',
- id: value.item.id,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item.id,
- ...(value.item.phase != null && {
- phase: value.item.phase,
- }),
- },
- },
- });
- } else if (
- isResponseOutputItemAddedChunk(value) &&
- value.item.type === 'reasoning'
- ) {
- activeReasoning[value.item.id] = {
- encryptedContent: value.item.encrypted_content,
- summaryParts: { 0: 'active' },
- };
-
- controller.enqueue({
- type: 'reasoning-start',
- id: `${value.item.id}:0`,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item.id,
- reasoningEncryptedContent:
- value.item.encrypted_content ?? null,
- } satisfies ResponsesReasoningProviderMetadata,
- },
- });
- }
- } else if (isResponseOutputItemDoneChunk(value)) {
- if (value.item.type === 'message') {
- const phase = value.item.phase ?? activeMessagePhase;
- activeMessagePhase = undefined;
- controller.enqueue({
- type: 'text-end',
- id: value.item.id,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item.id,
- ...(phase != null && { phase }),
- ...(ongoingAnnotations.length > 0 && {
- annotations: ongoingAnnotations,
- }),
- } satisfies ResponsesTextProviderMetadata,
- },
- });
- } else if (value.item.type === 'function_call') {
- ongoingToolCalls[value.output_index] = undefined;
- hasFunctionCall = true;
-
- controller.enqueue({
- type: 'tool-input-end',
- id: value.item.call_id,
- });
-
- controller.enqueue({
- type: 'tool-call',
- toolCallId: value.item.call_id,
- toolName: value.item.name,
- input: value.item.arguments,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item.id,
- },
- },
- });
- } else if (value.item.type === 'custom_tool_call') {
- ongoingToolCalls[value.output_index] = undefined;
- hasFunctionCall = true;
- const toolName = toolNameMapping.toCustomToolName(
- value.item.name,
- );
-
- controller.enqueue({
- type: 'tool-input-end',
- id: value.item.call_id,
- });
-
- controller.enqueue({
- type: 'tool-call',
- toolCallId: value.item.call_id,
- toolName,
- input: JSON.stringify(value.item.input),
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item.id,
- },
- },
- });
- } else if (value.item.type === 'web_search_call') {
- ongoingToolCalls[value.output_index] = undefined;
-
- controller.enqueue({
- type: 'tool-result',
- toolCallId: value.item.id,
- toolName: toolNameMapping.toCustomToolName(
- webSearchToolName ?? 'web_search',
- ),
- result: mapWebSearchOutput(value.item.action),
- });
- } else if (value.item.type === 'computer_call') {
- ongoingToolCalls[value.output_index] = undefined;
-
- controller.enqueue({
- type: 'tool-input-end',
- id: value.item.id,
- });
-
- controller.enqueue({
- type: 'tool-call',
- toolCallId: value.item.id,
- toolName: toolNameMapping.toCustomToolName('computer_use'),
- input: '',
- providerExecuted: true,
- });
-
- controller.enqueue({
- type: 'tool-result',
- toolCallId: value.item.id,
- toolName: toolNameMapping.toCustomToolName('computer_use'),
- result: {
- type: 'computer_use_tool_result',
- status: value.item.status || 'completed',
- },
- });
- } else if (value.item.type === 'file_search_call') {
- ongoingToolCalls[value.output_index] = undefined;
-
- controller.enqueue({
- type: 'tool-result',
- toolCallId: value.item.id,
- toolName: toolNameMapping.toCustomToolName('file_search'),
- result: {
- queries: value.item.queries,
- results:
- value.item.results?.map(result => ({
- attributes: result.attributes,
- fileId: result.file_id,
- filename: result.filename,
- score: result.score,
- text: result.text,
- })) ?? null,
- } satisfies InferSchema,
- });
- } else if (value.item.type === 'code_interpreter_call') {
- ongoingToolCalls[value.output_index] = undefined;
-
- controller.enqueue({
- type: 'tool-result',
- toolCallId: value.item.id,
- toolName:
- toolNameMapping.toCustomToolName('code_interpreter'),
- result: {
- outputs: value.item.outputs,
- } satisfies InferSchema,
- });
- } else if (value.item.type === 'image_generation_call') {
- controller.enqueue({
- type: 'tool-result',
- toolCallId: value.item.id,
- toolName:
- toolNameMapping.toCustomToolName('image_generation'),
- result: {
- result: value.item.result,
- } satisfies InferSchema,
- });
- } else if (value.item.type === 'tool_search_call') {
- const toolCall = ongoingToolCalls[value.output_index];
- const isHosted = value.item.execution === 'server';
-
- if (toolCall != null) {
- const toolCallId = isHosted
- ? toolCall.toolCallId
- : (value.item.call_id ?? value.item.id);
-
- if (isHosted) {
- hostedToolSearchCallIds.push(toolCallId);
- } else {
- controller.enqueue({
- type: 'tool-input-start',
- id: toolCallId,
- toolName: toolCall.toolName,
- });
- }
-
- controller.enqueue({
- type: 'tool-input-end',
- id: toolCallId,
- });
-
- controller.enqueue({
- type: 'tool-call',
- toolCallId,
- toolName: toolCall.toolName,
- input: JSON.stringify({
- arguments: value.item.arguments,
- call_id: isHosted ? null : toolCallId,
- } satisfies InferSchema),
- ...(isHosted ? { providerExecuted: true } : {}),
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item.id,
- },
- },
- });
- }
-
- ongoingToolCalls[value.output_index] = undefined;
- } else if (value.item.type === 'tool_search_output') {
- const toolCallId =
- value.item.call_id ??
- hostedToolSearchCallIds.shift() ??
- value.item.id;
-
- controller.enqueue({
- type: 'tool-result',
- toolCallId,
- toolName: toolNameMapping.toCustomToolName('tool_search'),
- result: {
- tools: value.item.tools,
- } satisfies InferSchema,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item.id,
- },
- },
- });
- } else if (value.item.type === 'mcp_call') {
- ongoingToolCalls[value.output_index] = undefined;
-
- const approvalRequestId =
- value.item.approval_request_id ?? undefined;
-
- // when MCP tools require approval, we track them with our own
- // tool call IDs and then map OpenAI's approval_request_id back to our ID so results match.
- const aliasedToolCallId =
- approvalRequestId != null
- ? (approvalRequestIdToDummyToolCallIdFromStream.get(
- approvalRequestId,
- ) ??
- approvalRequestIdToDummyToolCallIdFromPrompt[
- approvalRequestId
- ] ??
- value.item.id)
- : value.item.id;
-
- const toolName = `mcp.${value.item.name}`;
-
- controller.enqueue({
- type: 'tool-call',
- toolCallId: aliasedToolCallId,
- toolName,
- input: value.item.arguments,
- providerExecuted: true,
- dynamic: true,
- });
-
- controller.enqueue({
- type: 'tool-result',
- toolCallId: aliasedToolCallId,
- toolName,
- result: {
- type: 'call',
- serverLabel: value.item.server_label,
- name: value.item.name,
- arguments: value.item.arguments,
- ...(value.item.output != null
- ? { output: value.item.output }
- : {}),
- ...(value.item.error != null
- ? { error: value.item.error as unknown as JSONValue }
- : {}),
- } satisfies InferSchema,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item.id,
- },
- },
- });
- } else if (value.item.type === 'mcp_list_tools') {
- // Skip listTools - we don't expose this to the UI or send it back
- ongoingToolCalls[value.output_index] = undefined;
-
- // skip
- } else if (value.item.type === 'apply_patch_call') {
- const toolCall = ongoingToolCalls[value.output_index];
- if (
- toolCall?.applyPatch &&
- !toolCall.applyPatch.endEmitted &&
- value.item.operation.type !== 'delete_file'
- ) {
- if (!toolCall.applyPatch.hasDiff) {
- controller.enqueue({
- type: 'tool-input-delta',
- id: toolCall.toolCallId,
- delta: escapeJSONDelta(value.item.operation.diff),
- });
- }
-
- controller.enqueue({
- type: 'tool-input-delta',
- id: toolCall.toolCallId,
- delta: '"}}',
- });
-
- controller.enqueue({
- type: 'tool-input-end',
- id: toolCall.toolCallId,
- });
-
- toolCall.applyPatch.endEmitted = true;
- }
-
- // Emit the final tool-call with complete diff when status is 'completed'
- if (toolCall && value.item.status === 'completed') {
- controller.enqueue({
- type: 'tool-call',
- toolCallId: toolCall.toolCallId,
- toolName: toolNameMapping.toCustomToolName('apply_patch'),
- input: JSON.stringify({
- callId: value.item.call_id,
- operation: value.item.operation,
- } satisfies InferSchema),
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item.id,
- },
- },
- });
- }
-
- ongoingToolCalls[value.output_index] = undefined;
- } else if (value.item.type === 'mcp_approval_request') {
- ongoingToolCalls[value.output_index] = undefined;
-
- const dummyToolCallId =
- self.config.generateId?.() ?? generateId();
- const approvalRequestId =
- value.item.approval_request_id ?? value.item.id;
- approvalRequestIdToDummyToolCallIdFromStream.set(
- approvalRequestId,
- dummyToolCallId,
- );
-
- const toolName = `mcp.${value.item.name}`;
-
- controller.enqueue({
- type: 'tool-call',
- toolCallId: dummyToolCallId,
- toolName,
- input: value.item.arguments,
- providerExecuted: true,
- dynamic: true,
- });
-
- controller.enqueue({
- type: 'tool-approval-request',
- approvalId: approvalRequestId,
- toolCallId: dummyToolCallId,
- });
- } else if (value.item.type === 'local_shell_call') {
- ongoingToolCalls[value.output_index] = undefined;
-
- controller.enqueue({
- type: 'tool-call',
- toolCallId: value.item.call_id,
- toolName: toolNameMapping.toCustomToolName('local_shell'),
- input: JSON.stringify({
- action: {
- type: 'exec',
- command: value.item.action.command,
- timeoutMs: value.item.action.timeout_ms,
- user: value.item.action.user,
- workingDirectory: value.item.action.working_directory,
- env: value.item.action.env,
- },
- } satisfies InferSchema),
- providerMetadata: {
- [providerOptionsName]: { itemId: value.item.id },
- },
- });
- } else if (value.item.type === 'shell_call') {
- ongoingToolCalls[value.output_index] = undefined;
-
- controller.enqueue({
- type: 'tool-call',
- toolCallId: value.item.call_id,
- toolName: toolNameMapping.toCustomToolName('shell'),
- input: JSON.stringify({
- action: {
- commands: value.item.action.commands,
- },
- } satisfies InferSchema),
- ...(isShellProviderExecuted && {
- providerExecuted: true,
- }),
- providerMetadata: {
- [providerOptionsName]: { itemId: value.item.id },
- },
- });
- } else if (value.item.type === 'shell_call_output') {
- controller.enqueue({
- type: 'tool-result',
- toolCallId: value.item.call_id,
- toolName: toolNameMapping.toCustomToolName('shell'),
- result: {
- output: value.item.output.map(
- (item: {
- stdout: string;
- stderr: string;
- outcome:
- | { type: 'exit'; exit_code: number }
- | { type: 'timeout' };
- }) => ({
- stdout: item.stdout,
- stderr: item.stderr,
- outcome:
- item.outcome.type === 'exit'
- ? {
- type: 'exit' as const,
- exitCode: item.outcome.exit_code,
- }
- : { type: 'timeout' as const },
- }),
- ),
- } satisfies InferSchema,
- });
- } else if (value.item.type === 'reasoning') {
- const activeReasoningPart = activeReasoning[value.item.id];
-
- // get all active or can-conclude summary parts' ids
- // to conclude ongoing reasoning parts:
- const summaryPartIndices = Object.entries(
- activeReasoningPart.summaryParts,
- )
- .filter(
- ([_, status]) =>
- status === 'active' || status === 'can-conclude',
- )
- .map(([summaryIndex]) => summaryIndex);
-
- for (const summaryIndex of summaryPartIndices) {
- controller.enqueue({
- type: 'reasoning-end',
- id: `${value.item.id}:${summaryIndex}`,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item.id,
- reasoningEncryptedContent:
- value.item.encrypted_content ?? null,
- } satisfies ResponsesReasoningProviderMetadata,
- },
- });
- }
-
- delete activeReasoning[value.item.id];
- }
- } else if (isResponseFunctionCallArgumentsDeltaChunk(value)) {
- const toolCall = ongoingToolCalls[value.output_index];
-
- if (toolCall != null) {
- controller.enqueue({
- type: 'tool-input-delta',
- id: toolCall.toolCallId,
- delta: value.delta,
- });
- }
- } else if (isResponseCustomToolCallInputDeltaChunk(value)) {
- const toolCall = ongoingToolCalls[value.output_index];
-
- if (toolCall != null) {
- controller.enqueue({
- type: 'tool-input-delta',
- id: toolCall.toolCallId,
- delta: value.delta,
- });
- }
- } else if (isResponseApplyPatchCallOperationDiffDeltaChunk(value)) {
- const toolCall = ongoingToolCalls[value.output_index];
-
- if (toolCall?.applyPatch) {
- controller.enqueue({
- type: 'tool-input-delta',
- id: toolCall.toolCallId,
- delta: escapeJSONDelta(value.delta),
- });
-
- toolCall.applyPatch.hasDiff = true;
- }
- } else if (isResponseApplyPatchCallOperationDiffDoneChunk(value)) {
- const toolCall = ongoingToolCalls[value.output_index];
-
- if (toolCall?.applyPatch && !toolCall.applyPatch.endEmitted) {
- if (!toolCall.applyPatch.hasDiff) {
- controller.enqueue({
- type: 'tool-input-delta',
- id: toolCall.toolCallId,
- delta: escapeJSONDelta(value.diff),
- });
-
- toolCall.applyPatch.hasDiff = true;
- }
-
- controller.enqueue({
- type: 'tool-input-delta',
- id: toolCall.toolCallId,
- delta: '"}}',
- });
-
- controller.enqueue({
- type: 'tool-input-end',
- id: toolCall.toolCallId,
- });
-
- toolCall.applyPatch.endEmitted = true;
- }
- } else if (isResponseImageGenerationCallPartialImageChunk(value)) {
- controller.enqueue({
- type: 'tool-result',
- toolCallId: value.item_id,
- toolName: toolNameMapping.toCustomToolName('image_generation'),
- result: {
- result: value.partial_image_b64,
- } satisfies InferSchema,
- preliminary: true,
- });
- } else if (isResponseCodeInterpreterCallCodeDeltaChunk(value)) {
- const toolCall = ongoingToolCalls[value.output_index];
-
- if (toolCall != null) {
- controller.enqueue({
- type: 'tool-input-delta',
- id: toolCall.toolCallId,
- delta: escapeJSONDelta(value.delta),
- });
- }
- } else if (isResponseCodeInterpreterCallCodeDoneChunk(value)) {
- const toolCall = ongoingToolCalls[value.output_index];
-
- if (toolCall != null) {
- controller.enqueue({
- type: 'tool-input-delta',
- id: toolCall.toolCallId,
- delta: '"}',
- });
-
- controller.enqueue({
- type: 'tool-input-end',
- id: toolCall.toolCallId,
- });
-
- // immediately send the tool call after the input end:
- controller.enqueue({
- type: 'tool-call',
- toolCallId: toolCall.toolCallId,
- toolName:
- toolNameMapping.toCustomToolName('code_interpreter'),
- input: JSON.stringify({
- code: value.code,
- containerId: toolCall.codeInterpreter!.containerId,
- } satisfies InferSchema),
- providerExecuted: true,
- });
- }
- } else if (isResponseCreatedChunk(value)) {
- responseId = value.response.id;
- controller.enqueue({
- type: 'response-metadata',
- id: value.response.id,
- timestamp: new Date(value.response.created_at * 1000),
- modelId: value.response.model,
- });
- } else if (isTextDeltaChunk(value)) {
- controller.enqueue({
- type: 'text-delta',
- id: value.item_id,
- delta: value.delta,
- });
-
- if (
- options.providerOptions?.[providerOptionsName]?.logprobs &&
- value.logprobs
- ) {
- logprobs.push(value.logprobs);
- }
- } else if (value.type === 'response.reasoning_summary_part.added') {
- // the first reasoning start is pushed in isResponseOutputItemAddedReasoningChunk
- if (value.summary_index > 0) {
- const activeReasoningPart = activeReasoning[value.item_id]!;
-
- activeReasoningPart.summaryParts[value.summary_index] =
- 'active';
-
- // since there is a new active summary part, we can conclude all can-conclude summary parts
- for (const summaryIndex of Object.keys(
- activeReasoningPart.summaryParts,
- )) {
- if (
- activeReasoningPart.summaryParts[summaryIndex] ===
- 'can-conclude'
- ) {
- controller.enqueue({
- type: 'reasoning-end',
- id: `${value.item_id}:${summaryIndex}`,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item_id,
- } satisfies ResponsesReasoningProviderMetadata,
- },
- });
- activeReasoningPart.summaryParts[summaryIndex] =
- 'concluded';
- }
- }
-
- controller.enqueue({
- type: 'reasoning-start',
- id: `${value.item_id}:${value.summary_index}`,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item_id,
- reasoningEncryptedContent:
- activeReasoning[value.item_id]?.encryptedContent ??
- null,
- } satisfies ResponsesReasoningProviderMetadata,
- },
- });
- }
- } else if (value.type === 'response.reasoning_summary_text.delta') {
- controller.enqueue({
- type: 'reasoning-delta',
- id: `${value.item_id}:${value.summary_index}`,
- delta: value.delta,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item_id,
- } satisfies ResponsesReasoningProviderMetadata,
- },
- });
- } else if (value.type === 'response.reasoning_summary_part.done') {
- // when OpenAI stores the message data, we can immediately conclude the reasoning part
- // since we do not need to send the encrypted content.
- if (store) {
- controller.enqueue({
- type: 'reasoning-end',
- id: `${value.item_id}:${value.summary_index}`,
- providerMetadata: {
- [providerOptionsName]: {
- itemId: value.item_id,
- } satisfies ResponsesReasoningProviderMetadata,
- },
- });
-
- // mark the summary part as concluded
- activeReasoning[value.item_id]!.summaryParts[
- value.summary_index
- ] = 'concluded';
- } else {
- // mark the summary part as can-conclude only
- // because we need to have a final summary part with the encrypted content
- activeReasoning[value.item_id]!.summaryParts[
- value.summary_index
- ] = 'can-conclude';
- }
- } else if (isResponseFinishedChunk(value)) {
- finishReason = {
- unified: mapOpenAIResponseFinishReason({
- finishReason: value.response.incomplete_details?.reason,
- hasFunctionCall,
- }),
- raw: value.response.incomplete_details?.reason ?? undefined,
- };
- usage = value.response.usage;
- if (typeof value.response.service_tier === 'string') {
- serviceTier = value.response.service_tier;
- }
- } else if (isResponseFailedChunk(value)) {
- const incompleteReason =
- value.response.incomplete_details?.reason;
- finishReason = {
- unified: incompleteReason
- ? mapOpenAIResponseFinishReason({
- finishReason: incompleteReason,
- hasFunctionCall,
- })
- : 'error',
- raw: incompleteReason ?? 'error',
- };
- usage = value.response.usage ?? undefined;
- } else if (isResponseAnnotationAddedChunk(value)) {
- ongoingAnnotations.push(value.annotation);
- if (value.annotation.type === 'url_citation') {
- controller.enqueue({
- type: 'source',
- sourceType: 'url',
- id: self.config.generateId?.() ?? generateId(),
- url: value.annotation.url,
- title: value.annotation.title,
- });
- } else if (value.annotation.type === 'file_citation') {
- controller.enqueue({
- type: 'source',
- sourceType: 'document',
- id: self.config.generateId?.() ?? generateId(),
- mediaType: 'text/plain',
- title: value.annotation.filename,
- filename: value.annotation.filename,
- providerMetadata: {
- [providerOptionsName]: {
- type: value.annotation.type,
- fileId: value.annotation.file_id,
- index: value.annotation.index,
- } satisfies Extract<
- ResponsesSourceDocumentProviderMetadata,
- { type: 'file_citation' }
- >,
- },
- });
- } else if (value.annotation.type === 'container_file_citation') {
- controller.enqueue({
- type: 'source',
- sourceType: 'document',
- id: self.config.generateId?.() ?? generateId(),
- mediaType: 'text/plain',
- title: value.annotation.filename,
- filename: value.annotation.filename,
- providerMetadata: {
- [providerOptionsName]: {
- type: value.annotation.type,
- fileId: value.annotation.file_id,
- containerId: value.annotation.container_id,
- } satisfies Extract<
- ResponsesSourceDocumentProviderMetadata,
- { type: 'container_file_citation' }
- >,
- },
- });
- } else if (value.annotation.type === 'file_path') {
- controller.enqueue({
- type: 'source',
- sourceType: 'document',
- id: self.config.generateId?.() ?? generateId(),
- mediaType: 'application/octet-stream',
- title: value.annotation.file_id,
- filename: value.annotation.file_id,
- providerMetadata: {
- [providerOptionsName]: {
- type: value.annotation.type,
- fileId: value.annotation.file_id,
- index: value.annotation.index,
- } satisfies Extract<
- ResponsesSourceDocumentProviderMetadata,
- { type: 'file_path' }
- >,
- },
- });
- }
- } else if (isErrorChunk(value)) {
- controller.enqueue({ type: 'error', error: value });
- }
- },
-
- flush(controller) {
- const providerMetadata: SharedV3ProviderMetadata = {
- [providerOptionsName]: {
- responseId: responseId,
- ...(logprobs.length > 0 ? { logprobs } : {}),
- ...(serviceTier !== undefined ? { serviceTier } : {}),
- } satisfies ResponsesProviderMetadata,
- };
-
- controller.enqueue({
- type: 'finish',
- finishReason,
- usage: convertOpenAIResponsesUsage(usage),
- providerMetadata,
- });
- },
- }),
- ),
- request: { body },
- response: { headers: responseHeaders },
- };
- }
-}
-
-function isTextDeltaChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesChunk & { type: 'response.output_text.delta' } {
- return chunk.type === 'response.output_text.delta';
-}
-
-function isResponseOutputItemDoneChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesChunk & { type: 'response.output_item.done' } {
- return chunk.type === 'response.output_item.done';
-}
-
-function isResponseFinishedChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesChunk & {
- type: 'response.completed' | 'response.incomplete';
-} {
- return (
- chunk.type === 'response.completed' || chunk.type === 'response.incomplete'
- );
-}
-
-function isResponseFailedChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesChunk & { type: 'response.failed' } {
- return chunk.type === 'response.failed';
-}
-
-function isResponseCreatedChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesChunk & { type: 'response.created' } {
- return chunk.type === 'response.created';
-}
-
-function isResponseFunctionCallArgumentsDeltaChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesChunk & {
- type: 'response.function_call_arguments.delta';
-} {
- return chunk.type === 'response.function_call_arguments.delta';
-}
-
-function isResponseCustomToolCallInputDeltaChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesChunk & {
- type: 'response.custom_tool_call_input.delta';
-} {
- return chunk.type === 'response.custom_tool_call_input.delta';
-}
-
-function isResponseImageGenerationCallPartialImageChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesChunk & {
- type: 'response.image_generation_call.partial_image';
-} {
- return chunk.type === 'response.image_generation_call.partial_image';
-}
-
-function isResponseCodeInterpreterCallCodeDeltaChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesChunk & {
- type: 'response.code_interpreter_call_code.delta';
-} {
- return chunk.type === 'response.code_interpreter_call_code.delta';
-}
-
-function isResponseCodeInterpreterCallCodeDoneChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesChunk & {
- type: 'response.code_interpreter_call_code.done';
-} {
- return chunk.type === 'response.code_interpreter_call_code.done';
-}
-
-function isResponseApplyPatchCallOperationDiffDeltaChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesApplyPatchOperationDiffDeltaChunk {
- return chunk.type === 'response.apply_patch_call_operation_diff.delta';
-}
-
-function isResponseApplyPatchCallOperationDiffDoneChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesApplyPatchOperationDiffDoneChunk {
- return chunk.type === 'response.apply_patch_call_operation_diff.done';
-}
-
-function isResponseOutputItemAddedChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesChunk & { type: 'response.output_item.added' } {
- return chunk.type === 'response.output_item.added';
-}
-
-function isResponseAnnotationAddedChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesChunk & {
- type: 'response.output_text.annotation.added';
-} {
- return chunk.type === 'response.output_text.annotation.added';
-}
-
-function isErrorChunk(
- chunk: OpenAIResponsesChunk,
-): chunk is OpenAIResponsesChunk & { type: 'error' } {
- return chunk.type === 'error';
-}
-
-function mapWebSearchOutput(
- action: OpenAIResponsesWebSearchAction | null | undefined,
-): InferSchema {
- if (action == null) {
- return {};
- }
-
- switch (action.type) {
- case 'search':
- return {
- action: { type: 'search', query: action.query ?? undefined },
- // include sources when provided by the Responses API (behind include flag)
- ...(action.sources != null && { sources: action.sources }),
- };
- case 'open_page':
- return { action: { type: 'openPage', url: action.url } };
- case 'find_in_page':
- return {
- action: {
- type: 'findInPage',
- url: action.url,
- pattern: action.pattern,
- },
- };
- }
-}
-
-// The delta is embedded in a JSON string.
-// To escape it, we use JSON.stringify and slice to remove the outer quotes.
-function escapeJSONDelta(delta: string) {
- return JSON.stringify(delta).slice(1, -1);
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-options.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-options.ts
deleted file mode 100644
index 4477d7a12..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-options.ts
+++ /dev/null
@@ -1,317 +0,0 @@
-import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-/**
- * `top_logprobs` request body argument can be set to an integer between
- * 0 and 20 specifying the number of most likely tokens to return at each
- * token position, each with an associated log probability.
- *
- * @see https://platform.openai.com/docs/api-reference/responses/create#responses_create-top_logprobs
- */
-export const TOP_LOGPROBS_MAX = 20;
-
-export const openaiResponsesReasoningModelIds = [
- 'o1',
- 'o1-2024-12-17',
- 'o3',
- 'o3-2025-04-16',
- 'o3-mini',
- 'o3-mini-2025-01-31',
- 'o4-mini',
- 'o4-mini-2025-04-16',
- 'gpt-5',
- 'gpt-5-2025-08-07',
- 'gpt-5-codex',
- 'gpt-5-mini',
- 'gpt-5-mini-2025-08-07',
- 'gpt-5-nano',
- 'gpt-5-nano-2025-08-07',
- 'gpt-5-pro',
- 'gpt-5-pro-2025-10-06',
- 'gpt-5.1',
- 'gpt-5.1-chat-latest',
- 'gpt-5.1-codex-mini',
- 'gpt-5.1-codex',
- 'gpt-5.1-codex-max',
- 'gpt-5.2',
- 'gpt-5.2-chat-latest',
- 'gpt-5.2-pro',
- 'gpt-5.2-codex',
- 'gpt-5.3-chat-latest',
- 'gpt-5.3-codex',
- 'gpt-5.4',
- 'gpt-5.4-2026-03-05',
- 'gpt-5.4-mini',
- 'gpt-5.4-mini-2026-03-17',
- 'gpt-5.4-nano',
- 'gpt-5.4-nano-2026-03-17',
- 'gpt-5.4-pro',
- 'gpt-5.4-pro-2026-03-05',
-] as const;
-
-export const openaiResponsesModelIds = [
- 'gpt-4.1',
- 'gpt-4.1-2025-04-14',
- 'gpt-4.1-mini',
- 'gpt-4.1-mini-2025-04-14',
- 'gpt-4.1-nano',
- 'gpt-4.1-nano-2025-04-14',
- 'gpt-4o',
- 'gpt-4o-2024-05-13',
- 'gpt-4o-2024-08-06',
- 'gpt-4o-2024-11-20',
- 'gpt-4o-audio-preview',
- 'gpt-4o-audio-preview-2024-12-17',
- 'gpt-4o-search-preview',
- 'gpt-4o-search-preview-2025-03-11',
- 'gpt-4o-mini-search-preview',
- 'gpt-4o-mini-search-preview-2025-03-11',
- 'gpt-4o-mini',
- 'gpt-4o-mini-2024-07-18',
- 'gpt-3.5-turbo-0125',
- 'gpt-3.5-turbo',
- 'gpt-3.5-turbo-1106',
- 'gpt-5-chat-latest',
- ...openaiResponsesReasoningModelIds,
-] as const;
-
-export type OpenAIResponsesModelId =
- | 'gpt-3.5-turbo-0125'
- | 'gpt-3.5-turbo-1106'
- | 'gpt-3.5-turbo'
- | 'gpt-4.1-2025-04-14'
- | 'gpt-4.1-mini-2025-04-14'
- | 'gpt-4.1-mini'
- | 'gpt-4.1-nano-2025-04-14'
- | 'gpt-4.1-nano'
- | 'gpt-4.1'
- | 'gpt-4o-2024-05-13'
- | 'gpt-4o-2024-08-06'
- | 'gpt-4o-2024-11-20'
- | 'gpt-4o-mini-2024-07-18'
- | 'gpt-4o-mini'
- | 'gpt-4o'
- | 'gpt-5.1'
- | 'gpt-5.1-2025-11-13'
- | 'gpt-5.1-chat-latest'
- | 'gpt-5.1-codex-mini'
- | 'gpt-5.1-codex'
- | 'gpt-5.1-codex-max'
- | 'gpt-5.2'
- | 'gpt-5.2-2025-12-11'
- | 'gpt-5.2-chat-latest'
- | 'gpt-5.2-pro'
- | 'gpt-5.2-pro-2025-12-11'
- | 'gpt-5.2-codex'
- | 'gpt-5.3-chat-latest'
- | 'gpt-5.3-codex'
- | 'gpt-5.4'
- | 'gpt-5.4-2026-03-05'
- | 'gpt-5.4-mini'
- | 'gpt-5.4-mini-2026-03-17'
- | 'gpt-5.4-nano'
- | 'gpt-5.4-nano-2026-03-17'
- | 'gpt-5.4-pro'
- | 'gpt-5.4-pro-2026-03-05'
- | 'gpt-5-2025-08-07'
- | 'gpt-5-chat-latest'
- | 'gpt-5-codex'
- | 'gpt-5-mini-2025-08-07'
- | 'gpt-5-mini'
- | 'gpt-5-nano-2025-08-07'
- | 'gpt-5-nano'
- | 'gpt-5-pro-2025-10-06'
- | 'gpt-5-pro'
- | 'gpt-5'
- | 'o1-2024-12-17'
- | 'o1'
- | 'o3-2025-04-16'
- | 'o3-mini-2025-01-31'
- | 'o3-mini'
- | 'o3'
- | 'o4-mini'
- | 'o4-mini-2025-04-16'
- | (string & {});
-
-// TODO AI SDK 6: use optional here instead of nullish
-export const openaiLanguageModelResponsesOptionsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- /**
- * The ID of the OpenAI Conversation to continue.
- * You must create a conversation first via the OpenAI API.
- * Cannot be used in conjunction with `previousResponseId`.
- * Defaults to `undefined`.
- * @see https://platform.openai.com/docs/api-reference/conversations/create
- */
- conversation: z.string().nullish(),
-
- /**
- * The set of extra fields to include in the response (advanced, usually not needed).
- * Example values: 'reasoning.encrypted_content', 'file_search_call.results', 'message.output_text.logprobs'.
- */
- include: z
- .array(
- z.enum([
- 'reasoning.encrypted_content', // handled internally by default, only needed for unknown reasoning models
- 'file_search_call.results',
- 'message.output_text.logprobs',
- ]),
- )
- .nullish(),
-
- /**
- * Instructions for the model.
- * They can be used to change the system or developer message when continuing a conversation using the `previousResponseId` option.
- * Defaults to `undefined`.
- */
- instructions: z.string().nullish(),
-
- /**
- * Return the log probabilities of the tokens. Including logprobs will increase
- * the response size and can slow down response times. However, it can
- * be useful to better understand how the model is behaving.
- *
- * Setting to true will return the log probabilities of the tokens that
- * were generated.
- *
- * Setting to a number will return the log probabilities of the top n
- * tokens that were generated.
- *
- * @see https://platform.openai.com/docs/api-reference/responses/create
- * @see https://cookbook.openai.com/examples/using_logprobs
- */
- logprobs: z
- .union([z.boolean(), z.number().min(1).max(TOP_LOGPROBS_MAX)])
- .optional(),
-
- /**
- * The maximum number of total calls to built-in tools that can be processed in a response.
- * This maximum number applies across all built-in tool calls, not per individual tool.
- * Any further attempts to call a tool by the model will be ignored.
- */
- maxToolCalls: z.number().nullish(),
-
- /**
- * Additional metadata to store with the generation.
- */
- metadata: z.any().nullish(),
-
- /**
- * Whether to use parallel tool calls. Defaults to `true`.
- */
- parallelToolCalls: z.boolean().nullish(),
-
- /**
- * The ID of the previous response. You can use it to continue a conversation.
- * Defaults to `undefined`.
- */
- previousResponseId: z.string().nullish(),
-
- /**
- * Sets a cache key to tie this prompt to cached prefixes for better caching performance.
- */
- promptCacheKey: z.string().nullish(),
-
- /**
- * The retention policy for the prompt cache.
- * - 'in_memory': Default. Standard prompt caching behavior.
- * - '24h': Extended prompt caching that keeps cached prefixes active for up to 24 hours.
- * Currently only available for 5.1 series models.
- *
- * @default 'in_memory'
- */
- promptCacheRetention: z.enum(['in_memory', '24h']).nullish(),
-
- /**
- * Reasoning effort for reasoning models. Defaults to `medium`. If you use
- * `providerOptions` to set the `reasoningEffort` option, this model setting will be ignored.
- * Valid values: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'
- *
- * The 'none' type for `reasoningEffort` is only available for OpenAI's GPT-5.1
- * models. Also, the 'xhigh' type for `reasoningEffort` is only available for
- * OpenAI's GPT-5.1-Codex-Max model. Setting `reasoningEffort` to 'none' or 'xhigh' with unsupported models will result in
- * an error.
- */
- reasoningEffort: z.string().nullish(),
-
- /**
- * Controls reasoning summary output from the model.
- * Set to "auto" to automatically receive the richest level available,
- * or "detailed" for comprehensive summaries.
- */
- reasoningSummary: z.string().nullish(),
-
- /**
- * The identifier for safety monitoring and tracking.
- */
- safetyIdentifier: z.string().nullish(),
-
- /**
- * Service tier for the request.
- * Set to 'flex' for 50% cheaper processing at the cost of increased latency (available for o3, o4-mini, and gpt-5 models).
- * Set to 'priority' for faster processing with Enterprise access (available for gpt-4, gpt-5, gpt-5-mini, o3, o4-mini; gpt-5-nano is not supported).
- *
- * Defaults to 'auto'.
- */
- serviceTier: z.enum(['auto', 'flex', 'priority', 'default']).nullish(),
-
- /**
- * Whether to store the generation. Defaults to `true`.
- */
- store: z.boolean().nullish(),
-
- /**
- * Whether to use strict JSON schema validation.
- * Defaults to `true`.
- */
- strictJsonSchema: z.boolean().nullish(),
-
- /**
- * Controls the verbosity of the model's responses. Lower values ('low') will result
- * in more concise responses, while higher values ('high') will result in more verbose responses.
- * Valid values: 'low', 'medium', 'high'.
- */
- textVerbosity: z.enum(['low', 'medium', 'high']).nullish(),
-
- /**
- * Controls output truncation. 'auto' (default) performs truncation automatically;
- * 'disabled' turns truncation off.
- */
- truncation: z.enum(['auto', 'disabled']).nullish(),
-
- /**
- * A unique identifier representing your end-user, which can help OpenAI to
- * monitor and detect abuse.
- * Defaults to `undefined`.
- * @see https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids
- */
- user: z.string().nullish(),
-
- /**
- * Override the system message mode for this model.
- * - 'system': Use the 'system' role for system messages (default for most models)
- * - 'developer': Use the 'developer' role for system messages (used by reasoning models)
- * - 'remove': Remove system messages entirely
- *
- * If not specified, the mode is automatically determined based on the model.
- */
- systemMessageMode: z.enum(['system', 'developer', 'remove']).optional(),
-
- /**
- * Force treating this model as a reasoning model.
- *
- * This is useful for "stealth" reasoning models (e.g. via a custom baseURL)
- * where the model ID is not recognized by the SDK's allowlist.
- *
- * When enabled, the SDK applies reasoning-model parameter compatibility rules
- * and defaults `systemMessageMode` to `developer` unless overridden.
- */
- forceReasoning: z.boolean().optional(),
- }),
- ),
-);
-
-export type OpenAILanguageModelResponsesOptions = InferSchema<
- typeof openaiLanguageModelResponsesOptionsSchema
->;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-prepare-tools.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-prepare-tools.ts
deleted file mode 100644
index f96b5b667..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-prepare-tools.ts
+++ /dev/null
@@ -1,433 +0,0 @@
-import {
- LanguageModelV3CallOptions,
- SharedV3Warning,
- UnsupportedFunctionalityError,
-} from '@ai-sdk/provider';
-import { ToolNameMapping, validateTypes } from '@ai-sdk/provider-utils';
-import { codeInterpreterArgsSchema } from '../tool/code-interpreter';
-import { fileSearchArgsSchema } from '../tool/file-search';
-import { imageGenerationArgsSchema } from '../tool/image-generation';
-import { customArgsSchema } from '../tool/custom';
-import { mcpArgsSchema } from '../tool/mcp';
-import { shellArgsSchema } from '../tool/shell';
-import { toolSearchArgsSchema } from '../tool/tool-search';
-import { webSearchArgsSchema } from '../tool/web-search';
-import { webSearchPreviewArgsSchema } from '../tool/web-search-preview';
-import { OpenAIResponsesTool } from './openai-responses-api';
-
-export async function prepareResponsesTools({
- tools,
- toolChoice,
- toolNameMapping,
- customProviderToolNames,
-}: {
- tools: LanguageModelV3CallOptions['tools'];
- toolChoice: LanguageModelV3CallOptions['toolChoice'] | undefined;
- toolNameMapping?: ToolNameMapping;
- customProviderToolNames?: Set;
-}): Promise<{
- tools?: Array;
- toolChoice?:
- | 'auto'
- | 'none'
- | 'required'
- | { type: 'file_search' }
- | { type: 'web_search_preview' }
- | { type: 'web_search' }
- | { type: 'function'; name: string }
- | { type: 'custom'; name: string }
- | { type: 'code_interpreter' }
- | { type: 'mcp' }
- | { type: 'image_generation' }
- | { type: 'apply_patch' };
- toolWarnings: SharedV3Warning[];
-}> {
- // when the tools array is empty, change it to undefined to prevent errors:
- tools = tools?.length ? tools : undefined;
-
- const toolWarnings: SharedV3Warning[] = [];
-
- if (tools == null) {
- return { tools: undefined, toolChoice: undefined, toolWarnings };
- }
-
- const openaiTools: Array = [];
- const resolvedCustomProviderToolNames =
- customProviderToolNames ?? new Set();
-
- for (const tool of tools) {
- switch (tool.type) {
- case 'function': {
- const openaiOptions = tool.providerOptions?.openai as
- | { deferLoading?: boolean }
- | undefined;
- const deferLoading = openaiOptions?.deferLoading;
-
- openaiTools.push({
- type: 'function',
- name: tool.name,
- description: tool.description,
- parameters: tool.inputSchema,
- ...(tool.strict != null ? { strict: tool.strict } : {}),
- ...(deferLoading != null ? { defer_loading: deferLoading } : {}),
- });
- break;
- }
- case 'provider': {
- switch (tool.id) {
- case 'openai.file_search': {
- const args = await validateTypes({
- value: tool.args,
- schema: fileSearchArgsSchema,
- });
-
- openaiTools.push({
- type: 'file_search',
- vector_store_ids: args.vectorStoreIds,
- max_num_results: args.maxNumResults,
- ranking_options: args.ranking
- ? {
- ranker: args.ranking.ranker,
- score_threshold: args.ranking.scoreThreshold,
- }
- : undefined,
- filters: args.filters,
- });
-
- break;
- }
- case 'openai.local_shell': {
- openaiTools.push({
- type: 'local_shell',
- });
- break;
- }
- case 'openai.shell': {
- const args = await validateTypes({
- value: tool.args,
- schema: shellArgsSchema,
- });
-
- openaiTools.push({
- type: 'shell',
- ...(args.environment && {
- environment: mapShellEnvironment(args.environment),
- }),
- });
- break;
- }
- case 'openai.apply_patch': {
- openaiTools.push({
- type: 'apply_patch',
- });
- break;
- }
- case 'openai.web_search_preview': {
- const args = await validateTypes({
- value: tool.args,
- schema: webSearchPreviewArgsSchema,
- });
- openaiTools.push({
- type: 'web_search_preview',
- search_context_size: args.searchContextSize,
- user_location: args.userLocation,
- });
- break;
- }
- case 'openai.web_search': {
- const args = await validateTypes({
- value: tool.args,
- schema: webSearchArgsSchema,
- });
- openaiTools.push({
- type: 'web_search',
- filters:
- args.filters != null
- ? { allowed_domains: args.filters.allowedDomains }
- : undefined,
- external_web_access: args.externalWebAccess,
- search_context_size: args.searchContextSize,
- user_location: args.userLocation,
- });
- break;
- }
- case 'openai.code_interpreter': {
- const args = await validateTypes({
- value: tool.args,
- schema: codeInterpreterArgsSchema,
- });
-
- openaiTools.push({
- type: 'code_interpreter',
- container:
- args.container == null
- ? { type: 'auto', file_ids: undefined }
- : typeof args.container === 'string'
- ? args.container
- : { type: 'auto', file_ids: args.container.fileIds },
- });
- break;
- }
- case 'openai.image_generation': {
- const args = await validateTypes({
- value: tool.args,
- schema: imageGenerationArgsSchema,
- });
-
- openaiTools.push({
- type: 'image_generation',
- background: args.background,
- input_fidelity: args.inputFidelity,
- input_image_mask: args.inputImageMask
- ? {
- file_id: args.inputImageMask.fileId,
- image_url: args.inputImageMask.imageUrl,
- }
- : undefined,
- model: args.model,
- moderation: args.moderation,
- partial_images: args.partialImages,
- quality: args.quality,
- output_compression: args.outputCompression,
- output_format: args.outputFormat,
- size: args.size,
- });
- break;
- }
- case 'openai.mcp': {
- const args = await validateTypes({
- value: tool.args,
- schema: mcpArgsSchema,
- });
-
- const mapApprovalFilter = (filter: { toolNames?: string[] }) => ({
- tool_names: filter.toolNames,
- });
-
- const requireApproval = args.requireApproval;
- const requireApprovalParam:
- | 'always'
- | 'never'
- | {
- never?: { tool_names?: string[] };
- }
- | undefined =
- requireApproval == null
- ? undefined
- : typeof requireApproval === 'string'
- ? requireApproval
- : requireApproval.never != null
- ? { never: mapApprovalFilter(requireApproval.never) }
- : undefined;
-
- openaiTools.push({
- type: 'mcp',
- server_label: args.serverLabel,
- allowed_tools: Array.isArray(args.allowedTools)
- ? args.allowedTools
- : args.allowedTools
- ? {
- read_only: args.allowedTools.readOnly,
- tool_names: args.allowedTools.toolNames,
- }
- : undefined,
- authorization: args.authorization,
- connector_id: args.connectorId,
- headers: args.headers,
- require_approval: requireApprovalParam ?? 'never',
- server_description: args.serverDescription,
- server_url: args.serverUrl,
- });
-
- break;
- }
- case 'openai.custom': {
- const args = await validateTypes({
- value: tool.args,
- schema: customArgsSchema,
- });
-
- openaiTools.push({
- type: 'custom',
- name: args.name,
- description: args.description,
- format: args.format,
- });
- resolvedCustomProviderToolNames.add(args.name);
- break;
- }
- case 'openai.tool_search': {
- const args = await validateTypes({
- value: tool.args,
- schema: toolSearchArgsSchema,
- });
- openaiTools.push({
- type: 'tool_search',
- ...(args.execution != null ? { execution: args.execution } : {}),
- ...(args.description != null
- ? { description: args.description }
- : {}),
- ...(args.parameters != null
- ? { parameters: args.parameters }
- : {}),
- });
- break;
- }
- }
- break;
- }
- default:
- toolWarnings.push({
- type: 'unsupported',
- feature: `function tool ${tool}`,
- });
- break;
- }
- }
-
- if (toolChoice == null) {
- return { tools: openaiTools, toolChoice: undefined, toolWarnings };
- }
-
- const type = toolChoice.type;
-
- switch (type) {
- case 'auto':
- case 'none':
- case 'required':
- return { tools: openaiTools, toolChoice: type, toolWarnings };
- case 'tool': {
- const resolvedToolName =
- toolNameMapping?.toProviderToolName(toolChoice.toolName) ??
- toolChoice.toolName;
-
- return {
- tools: openaiTools,
- toolChoice:
- resolvedToolName === 'code_interpreter' ||
- resolvedToolName === 'file_search' ||
- resolvedToolName === 'image_generation' ||
- resolvedToolName === 'web_search_preview' ||
- resolvedToolName === 'web_search' ||
- resolvedToolName === 'mcp' ||
- resolvedToolName === 'apply_patch'
- ? { type: resolvedToolName }
- : resolvedCustomProviderToolNames.has(resolvedToolName)
- ? { type: 'custom', name: resolvedToolName }
- : { type: 'function', name: resolvedToolName },
- toolWarnings,
- };
- }
- default: {
- const _exhaustiveCheck: never = type;
- throw new UnsupportedFunctionalityError({
- functionality: `tool choice type: ${_exhaustiveCheck}`,
- });
- }
- }
-}
-
-function mapShellEnvironment(environment: {
- type?: string;
- [key: string]: unknown;
-}): NonNullable<
- Extract['environment']
-> {
- if (environment.type === 'containerReference') {
- const env = environment as {
- type: 'containerReference';
- containerId: string;
- };
- return {
- type: 'container_reference',
- container_id: env.containerId,
- };
- }
-
- if (environment.type === 'containerAuto') {
- const env = environment as {
- type: 'containerAuto';
- fileIds?: string[];
- memoryLimit?: '1g' | '4g' | '16g' | '64g';
- networkPolicy?: {
- type: string;
- allowedDomains?: string[];
- domainSecrets?: Array<{
- domain: string;
- name: string;
- value: string;
- }>;
- };
- skills?: Array<{
- type: string;
- skillId?: string;
- version?: string;
- name?: string;
- description?: string;
- source?: { type: string; mediaType: string; data: string };
- }>;
- };
-
- return {
- type: 'container_auto',
- file_ids: env.fileIds,
- memory_limit: env.memoryLimit,
- network_policy:
- env.networkPolicy == null
- ? undefined
- : env.networkPolicy.type === 'disabled'
- ? { type: 'disabled' as const }
- : {
- type: 'allowlist' as const,
- allowed_domains: env.networkPolicy.allowedDomains!,
- domain_secrets: env.networkPolicy.domainSecrets,
- },
- skills: mapShellSkills(env.skills),
- };
- }
-
- const env = environment as {
- type?: 'local';
- skills?: Array<{
- name: string;
- description: string;
- path: string;
- }>;
- };
- return {
- type: 'local',
- skills: env.skills,
- };
-}
-
-function mapShellSkills(
- skills:
- | Array<{
- type: string;
- skillId?: string;
- version?: string;
- name?: string;
- description?: string;
- source?: { type: string; mediaType: string; data: string };
- }>
- | undefined,
-) {
- return skills?.map(skill =>
- skill.type === 'skillReference'
- ? {
- type: 'skill_reference' as const,
- skill_id: skill.skillId!,
- version: skill.version,
- }
- : {
- type: 'inline' as const,
- name: skill.name!,
- description: skill.description!,
- source: {
- type: 'base64' as const,
- media_type: skill.source!.mediaType as 'application/zip',
- data: skill.source!.data,
- },
- },
- );
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-provider-metadata.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-provider-metadata.ts
deleted file mode 100644
index a0e245033..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/responses/openai-responses-provider-metadata.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import {
- openaiResponsesChunkSchema,
- OpenAIResponsesLogprobs,
-} from './openai-responses-api';
-import { InferSchema } from '@ai-sdk/provider-utils';
-
-type OpenaiResponsesChunk = InferSchema;
-
-type ResponsesOutputTextAnnotationProviderMetadata = Extract<
- OpenaiResponsesChunk,
- { type: 'response.output_text.annotation.added' }
->['annotation'];
-
-export type ResponsesProviderMetadata = {
- responseId: string | null | undefined;
- logprobs?: Array;
- serviceTier?: string;
-};
-
-export type ResponsesReasoningProviderMetadata = {
- itemId: string;
- reasoningEncryptedContent?: string | null;
-};
-
-export type OpenaiResponsesReasoningProviderMetadata = {
- openai: ResponsesReasoningProviderMetadata;
-};
-
-export type OpenaiResponsesProviderMetadata = {
- openai: ResponsesProviderMetadata;
-};
-
-export type ResponsesTextProviderMetadata = {
- itemId: string;
- phase?: 'commentary' | 'final_answer' | null;
- annotations?: Array;
-};
-
-export type OpenaiResponsesTextProviderMetadata = {
- openai: ResponsesTextProviderMetadata;
-};
-
-export type ResponsesSourceDocumentProviderMetadata =
- | {
- type: 'file_citation';
- fileId: string;
- index: number;
- }
- | {
- type: 'container_file_citation';
- fileId: string;
- containerId: string;
- }
- | {
- type: 'file_path';
- fileId: string;
- index: number;
- };
-
-export type OpenaiResponsesSourceDocumentProviderMetadata = {
- openai: ResponsesSourceDocumentProviderMetadata;
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/speech/openai-speech-api.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/speech/openai-speech-api.ts
deleted file mode 100644
index 6dd14415f..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/speech/openai-speech-api.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-export type OpenAISpeechAPITypes = {
- /**
- * The voice to use when generating the audio.
- * Supported voices are alloy, ash, ballad, coral, echo, fable, onyx, nova, sage, shimmer, and verse.
- * @default 'alloy'
- */
- voice?:
- | 'alloy'
- | 'ash'
- | 'ballad'
- | 'coral'
- | 'echo'
- | 'fable'
- | 'onyx'
- | 'nova'
- | 'sage'
- | 'shimmer'
- | 'verse';
-
- /**
- * The speed of the generated audio.
- * Select a value from 0.25 to 4.0.
- * @default 1.0
- */
- speed?: number;
-
- /**
- * The format of the generated audio.
- * @default 'mp3'
- */
- response_format?: 'mp3' | 'opus' | 'aac' | 'flac' | 'wav' | 'pcm';
-
- /**
- * Instructions for the speech generation e.g. "Speak in a slow and steady tone".
- * Does not work with tts-1 or tts-1-hd.
- */
- instructions?: string;
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/speech/openai-speech-model.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/speech/openai-speech-model.ts
deleted file mode 100644
index 05a2dea35..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/speech/openai-speech-model.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-import { SpeechModelV3, SharedV3Warning } from '@ai-sdk/provider';
-import {
- combineHeaders,
- createBinaryResponseHandler,
- parseProviderOptions,
- postJsonToApi,
-} from '@ai-sdk/provider-utils';
-import { OpenAIConfig } from '../openai-config';
-import { openaiFailedResponseHandler } from '../openai-error';
-import { OpenAISpeechAPITypes } from './openai-speech-api';
-import {
- openaiSpeechModelOptionsSchema,
- OpenAISpeechModelId,
-} from './openai-speech-options';
-
-interface OpenAISpeechModelConfig extends OpenAIConfig {
- _internal?: {
- currentDate?: () => Date;
- };
-}
-
-export class OpenAISpeechModel implements SpeechModelV3 {
- readonly specificationVersion = 'v3';
-
- get provider(): string {
- return this.config.provider;
- }
-
- constructor(
- readonly modelId: OpenAISpeechModelId,
- private readonly config: OpenAISpeechModelConfig,
- ) {}
-
- private async getArgs({
- text,
- voice = 'alloy',
- outputFormat = 'mp3',
- speed,
- instructions,
- language,
- providerOptions,
- }: Parameters[0]) {
- const warnings: SharedV3Warning[] = [];
-
- // Parse provider options
- const openAIOptions = await parseProviderOptions({
- provider: 'openai',
- providerOptions,
- schema: openaiSpeechModelOptionsSchema,
- });
-
- // Create request body
- const requestBody: Record = {
- model: this.modelId,
- input: text,
- voice,
- response_format: 'mp3',
- speed,
- instructions,
- };
-
- if (outputFormat) {
- if (['mp3', 'opus', 'aac', 'flac', 'wav', 'pcm'].includes(outputFormat)) {
- requestBody.response_format = outputFormat;
- } else {
- warnings.push({
- type: 'unsupported',
- feature: 'outputFormat',
- details: `Unsupported output format: ${outputFormat}. Using mp3 instead.`,
- });
- }
- }
-
- // Add provider-specific options
- if (openAIOptions) {
- const speechModelOptions: OpenAISpeechAPITypes = {};
-
- for (const key in speechModelOptions) {
- const value = speechModelOptions[key as keyof OpenAISpeechAPITypes];
- if (value !== undefined) {
- requestBody[key] = value;
- }
- }
- }
-
- if (language) {
- warnings.push({
- type: 'unsupported',
- feature: 'language',
- details: `OpenAI speech models do not support language selection. Language parameter "${language}" was ignored.`,
- });
- }
-
- return {
- requestBody,
- warnings,
- };
- }
-
- async doGenerate(
- options: Parameters[0],
- ): Promise>> {
- const currentDate = this.config._internal?.currentDate?.() ?? new Date();
- const { requestBody, warnings } = await this.getArgs(options);
-
- const {
- value: audio,
- responseHeaders,
- rawValue: rawResponse,
- } = await postJsonToApi({
- url: this.config.url({
- path: '/audio/speech',
- modelId: this.modelId,
- }),
- headers: combineHeaders(this.config.headers(), options.headers),
- body: requestBody,
- failedResponseHandler: openaiFailedResponseHandler,
- successfulResponseHandler: createBinaryResponseHandler(),
- abortSignal: options.abortSignal,
- fetch: this.config.fetch,
- });
-
- return {
- audio,
- warnings,
- request: {
- body: JSON.stringify(requestBody),
- },
- response: {
- timestamp: currentDate,
- modelId: this.modelId,
- headers: responseHeaders,
- body: rawResponse,
- },
- };
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/speech/openai-speech-options.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/speech/openai-speech-options.ts
deleted file mode 100644
index f2442c010..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/speech/openai-speech-options.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export type OpenAISpeechModelId =
- | 'tts-1'
- | 'tts-1-1106'
- | 'tts-1-hd'
- | 'tts-1-hd-1106'
- | 'gpt-4o-mini-tts'
- | 'gpt-4o-mini-tts-2025-03-20'
- | 'gpt-4o-mini-tts-2025-12-15'
- | (string & {});
-
-// https://platform.openai.com/docs/api-reference/audio/createSpeech
-export const openaiSpeechModelOptionsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- instructions: z.string().nullish(),
- speed: z.number().min(0.25).max(4.0).default(1.0).nullish(),
- }),
- ),
-);
-
-export type OpenAISpeechModelOptions = InferSchema<
- typeof openaiSpeechModelOptionsSchema
->;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/apply-patch.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/apply-patch.ts
deleted file mode 100644
index 50b888679..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/apply-patch.ts
+++ /dev/null
@@ -1,141 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-/**
- * Schema for the apply_patch input - what the model sends.
- *
- * Refer the official spec here: https://platform.openai.com/docs/api-reference/responses/create#responses_create-input-input_item_list-item-apply_patch_tool_call
- *
- */
-export const applyPatchInputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- callId: z.string(),
- operation: z.discriminatedUnion('type', [
- z.object({
- type: z.literal('create_file'),
- path: z.string(),
- diff: z.string(),
- }),
- z.object({
- type: z.literal('delete_file'),
- path: z.string(),
- }),
- z.object({
- type: z.literal('update_file'),
- path: z.string(),
- diff: z.string(),
- }),
- ]),
- }),
- ),
-);
-
-/**
- * Schema for the apply_patch output - what we send back.
- */
-export const applyPatchOutputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- status: z.enum(['completed', 'failed']),
- output: z.string().optional(),
- }),
- ),
-);
-
-/**
- * Schema for tool arguments (configuration options).
- * The apply_patch tool doesn't require any configuration options.
- */
-export const applyPatchArgsSchema = lazySchema(() => zodSchema(z.object({})));
-
-/**
- * Type definitions for the apply_patch operations.
- */
-export type ApplyPatchOperation =
- | {
- type: 'create_file';
- /**
- * Path of the file to create relative to the workspace root.
- */
- path: string;
- /**
- * Unified diff content to apply when creating the file.
- */
- diff: string;
- }
- | {
- type: 'delete_file';
- /**
- * Path of the file to delete relative to the workspace root.
- */
- path: string;
- }
- | {
- type: 'update_file';
- /**
- * Path of the file to update relative to the workspace root.
- */
- path: string;
- /**
- * Unified diff content to apply to the existing file.
- */
- diff: string;
- };
-
-/**
- * The apply_patch tool lets GPT-5.1 create, update, and delete files in your
- * codebase using structured diffs. Instead of just suggesting edits, the model
- * emits patch operations that your application applies and then reports back on,
- * enabling iterative, multi-step code editing workflows.
- *
- * The tool factory creates a provider-defined tool that:
- * - Receives patch operations from the model (create_file, update_file, delete_file)
- * - Returns the status of applying those patches (completed or failed)
- *
- */
-export const applyPatchToolFactory = createProviderToolFactoryWithOutputSchema<
- {
- /**
- * The unique ID of the apply patch tool call generated by the model.
- */
- callId: string;
-
- /**
- * The specific create, delete, or update instruction for the apply_patch tool call.
- */
- operation: ApplyPatchOperation;
- },
- {
- /**
- * The status of the apply patch tool call output.
- * - 'completed': The patch was applied successfully.
- * - 'failed': The patch failed to apply.
- */
- status: 'completed' | 'failed';
-
- /**
- * Optional human-readable log text from the apply patch tool
- * (e.g., patch results or errors).
- */
- output?: string;
- },
- // No configuration options for apply_patch
- {}
->({
- id: 'openai.apply_patch',
- inputSchema: applyPatchInputSchema,
- outputSchema: applyPatchOutputSchema,
-});
-
-/**
- * The apply_patch tool lets GPT-5.1 create, update, and delete files in your
- * codebase using structured diffs. Instead of just suggesting edits, the model
- * emits patch operations that your application applies and then reports back on,
- * enabling iterative, multi-step code editing workflows.
- */
-export const applyPatch = applyPatchToolFactory;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/code-interpreter.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/code-interpreter.ts
deleted file mode 100644
index d921444de..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/code-interpreter.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const codeInterpreterInputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- code: z.string().nullish(),
- containerId: z.string(),
- }),
- ),
-);
-
-export const codeInterpreterOutputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- outputs: z
- .array(
- z.discriminatedUnion('type', [
- z.object({ type: z.literal('logs'), logs: z.string() }),
- z.object({ type: z.literal('image'), url: z.string() }),
- ]),
- )
- .nullish(),
- }),
- ),
-);
-
-export const codeInterpreterArgsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- container: z
- .union([
- z.string(),
- z.object({
- fileIds: z.array(z.string()).optional(),
- }),
- ])
- .optional(),
- }),
- ),
-);
-
-type CodeInterpreterArgs = {
- /**
- * The code interpreter container.
- * Can be a container ID
- * or an object that specifies uploaded file IDs to make available to your code.
- */
- container?: string | { fileIds?: string[] };
-};
-
-export const codeInterpreterToolFactory =
- createProviderToolFactoryWithOutputSchema<
- {
- /**
- * The code to run, or null if not available.
- */
- code?: string | null;
-
- /**
- * The ID of the container used to run the code.
- */
- containerId: string;
- },
- {
- /**
- * The outputs generated by the code interpreter, such as logs or images.
- * Can be null if no outputs are available.
- */
- outputs?: Array<
- | {
- type: 'logs';
-
- /**
- * The logs output from the code interpreter.
- */
- logs: string;
- }
- | {
- type: 'image';
-
- /**
- * The URL of the image output from the code interpreter.
- */
- url: string;
- }
- > | null;
- },
- CodeInterpreterArgs
- >({
- id: 'openai.code_interpreter',
- inputSchema: codeInterpreterInputSchema,
- outputSchema: codeInterpreterOutputSchema,
- });
-
-export const codeInterpreter = (
- args: CodeInterpreterArgs = {}, // default
-) => {
- return codeInterpreterToolFactory(args);
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/custom.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/custom.ts
deleted file mode 100644
index 91c223852..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/custom.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import {
- createProviderToolFactory,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const customArgsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- name: z.string(),
- description: z.string().optional(),
- format: z
- .union([
- z.object({
- type: z.literal('grammar'),
- syntax: z.enum(['regex', 'lark']),
- definition: z.string(),
- }),
- z.object({
- type: z.literal('text'),
- }),
- ])
- .optional(),
- }),
- ),
-);
-
-const customInputSchema = lazySchema(() => zodSchema(z.string()));
-
-export const customToolFactory = createProviderToolFactory<
- string,
- {
- /**
- * The name of the custom tool, used to identify it in the API.
- */
- name: string;
-
- /**
- * An optional description of what the tool does.
- */
- description?: string;
-
- /**
- * The output format specification for the tool.
- * Omit for unconstrained text output.
- */
- format?:
- | {
- type: 'grammar';
- syntax: 'regex' | 'lark';
- definition: string;
- }
- | {
- type: 'text';
- };
- }
->({
- id: 'openai.custom',
- inputSchema: customInputSchema,
-});
-
-export const customTool = (args: Parameters[0]) =>
- customToolFactory(args);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/file-search.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/file-search.ts
deleted file mode 100644
index a82a11e12..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/file-search.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-import {
- OpenAIResponsesFileSearchToolComparisonFilter,
- OpenAIResponsesFileSearchToolCompoundFilter,
-} from '../responses/openai-responses-api';
-
-const comparisonFilterSchema = z.object({
- key: z.string(),
- type: z.enum(['eq', 'ne', 'gt', 'gte', 'lt', 'lte', 'in', 'nin']),
- value: z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]),
-});
-
-const compoundFilterSchema: z.ZodType = z.object({
- type: z.enum(['and', 'or']),
- filters: z.array(
- z.union([comparisonFilterSchema, z.lazy(() => compoundFilterSchema)]),
- ),
-});
-
-export const fileSearchArgsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- vectorStoreIds: z.array(z.string()),
- maxNumResults: z.number().optional(),
- ranking: z
- .object({
- ranker: z.string().optional(),
- scoreThreshold: z.number().optional(),
- })
- .optional(),
- filters: z
- .union([comparisonFilterSchema, compoundFilterSchema])
- .optional(),
- }),
- ),
-);
-
-export const fileSearchOutputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- queries: z.array(z.string()),
- results: z
- .array(
- z.object({
- attributes: z.record(z.string(), z.unknown()),
- fileId: z.string(),
- filename: z.string(),
- score: z.number(),
- text: z.string(),
- }),
- )
- .nullable(),
- }),
- ),
-);
-
-export const fileSearch = createProviderToolFactoryWithOutputSchema<
- {},
- {
- /**
- * The search query to execute.
- */
- queries: string[];
-
- /**
- * The results of the file search tool call.
- */
- results:
- | null
- | {
- /**
- * Set of 16 key-value pairs that can be attached to an object.
- * This can be useful for storing additional information about the object
- * in a structured format, and querying for objects via API or the dashboard.
- * Keys are strings with a maximum length of 64 characters.
- * Values are strings with a maximum length of 512 characters, booleans, or numbers.
- */
- attributes: Record;
-
- /**
- * The unique ID of the file.
- */
- fileId: string;
-
- /**
- * The name of the file.
- */
- filename: string;
-
- /**
- * The relevance score of the file - a value between 0 and 1.
- */
- score: number;
-
- /**
- * The text that was retrieved from the file.
- */
- text: string;
- }[];
- },
- {
- /**
- * List of vector store IDs to search through.
- */
- vectorStoreIds: string[];
-
- /**
- * Maximum number of search results to return. Defaults to 10.
- */
- maxNumResults?: number;
-
- /**
- * Ranking options for the search.
- */
- ranking?: {
- /**
- * The ranker to use for the file search.
- */
- ranker?: string;
-
- /**
- * The score threshold for the file search, a number between 0 and 1.
- * Numbers closer to 1 will attempt to return only the most relevant results,
- * but may return fewer results.
- */
- scoreThreshold?: number;
- };
-
- /**
- * A filter to apply.
- */
- filters?:
- | OpenAIResponsesFileSearchToolComparisonFilter
- | OpenAIResponsesFileSearchToolCompoundFilter;
- }
->({
- id: 'openai.file_search',
- inputSchema: z.object({}),
- outputSchema: fileSearchOutputSchema,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/image-generation.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/image-generation.ts
deleted file mode 100644
index b7d2eb051..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/image-generation.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const imageGenerationArgsSchema = lazySchema(() =>
- zodSchema(
- z
- .object({
- background: z.enum(['auto', 'opaque', 'transparent']).optional(),
- inputFidelity: z.enum(['low', 'high']).optional(),
- inputImageMask: z
- .object({
- fileId: z.string().optional(),
- imageUrl: z.string().optional(),
- })
- .optional(),
- model: z.string().optional(),
- moderation: z.enum(['auto']).optional(),
- outputCompression: z.number().int().min(0).max(100).optional(),
- outputFormat: z.enum(['png', 'jpeg', 'webp']).optional(),
- partialImages: z.number().int().min(0).max(3).optional(),
- quality: z.enum(['auto', 'low', 'medium', 'high']).optional(),
- size: z
- .enum(['1024x1024', '1024x1536', '1536x1024', 'auto'])
- .optional(),
- })
- .strict(),
- ),
-);
-
-const imageGenerationInputSchema = lazySchema(() => zodSchema(z.object({})));
-
-export const imageGenerationOutputSchema = lazySchema(() =>
- zodSchema(z.object({ result: z.string() })),
-);
-
-type ImageGenerationArgs = {
- /**
- * Background type for the generated image. Default is 'auto'.
- */
- background?: 'auto' | 'opaque' | 'transparent';
-
- /**
- * Input fidelity for the generated image. Default is 'low'.
- */
- inputFidelity?: 'low' | 'high';
-
- /**
- * Optional mask for inpainting.
- * Contains image_url (string, optional) and file_id (string, optional).
- */
- inputImageMask?: {
- /**
- * File ID for the mask image.
- */
- fileId?: string;
-
- /**
- * Base64-encoded mask image.
- */
- imageUrl?: string;
- };
-
- /**
- * The image generation model to use. Default: gpt-image-1.
- */
- model?: string;
-
- /**
- * Moderation level for the generated image. Default: auto.
- */
- moderation?: 'auto';
-
- /**
- * Compression level for the output image. Default: 100.
- */
- outputCompression?: number;
-
- /**
- * The output format of the generated image. One of png, webp, or jpeg.
- * Default: png
- */
- outputFormat?: 'png' | 'jpeg' | 'webp';
-
- /**
- * Number of partial images to generate in streaming mode, from 0 (default value) to 3.
- */
- partialImages?: number;
-
- /**
- * The quality of the generated image.
- * One of low, medium, high, or auto. Default: auto.
- */
- quality?: 'auto' | 'low' | 'medium' | 'high';
-
- /**
- * The size of the generated image.
- * One of 1024x1024, 1024x1536, 1536x1024, or auto.
- * Default: auto.
- */
- size?: 'auto' | '1024x1024' | '1024x1536' | '1536x1024';
-};
-
-const imageGenerationToolFactory = createProviderToolFactoryWithOutputSchema<
- {},
- {
- /**
- * The generated image encoded in base64.
- */
- result: string;
- },
- ImageGenerationArgs
->({
- id: 'openai.image_generation',
- inputSchema: imageGenerationInputSchema,
- outputSchema: imageGenerationOutputSchema,
-});
-
-export const imageGeneration = (
- args: ImageGenerationArgs = {}, // default
-) => {
- return imageGenerationToolFactory(args);
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/local-shell.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/local-shell.ts
deleted file mode 100644
index 96bdb5db2..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/local-shell.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const localShellInputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- action: z.object({
- type: z.literal('exec'),
- command: z.array(z.string()),
- timeoutMs: z.number().optional(),
- user: z.string().optional(),
- workingDirectory: z.string().optional(),
- env: z.record(z.string(), z.string()).optional(),
- }),
- }),
- ),
-);
-
-export const localShellOutputSchema = lazySchema(() =>
- zodSchema(z.object({ output: z.string() })),
-);
-
-export const localShell = createProviderToolFactoryWithOutputSchema<
- {
- /**
- * Execute a shell command on the server.
- */
- action: {
- type: 'exec';
-
- /**
- * The command to run.
- */
- command: string[];
-
- /**
- * Optional timeout in milliseconds for the command.
- */
- timeoutMs?: number;
-
- /**
- * Optional user to run the command as.
- */
- user?: string;
-
- /**
- * Optional working directory to run the command in.
- */
- workingDirectory?: string;
-
- /**
- * Environment variables to set for the command.
- */
- env?: Record;
- };
- },
- {
- /**
- * The output of local shell tool call.
- */
- output: string;
- },
- {}
->({
- id: 'openai.local_shell',
- inputSchema: localShellInputSchema,
- outputSchema: localShellOutputSchema,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/mcp.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/mcp.ts
deleted file mode 100644
index 57db1e99a..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/mcp.ts
+++ /dev/null
@@ -1,125 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { JSONValue } from '@ai-sdk/provider';
-import { z } from 'zod/v4';
-
-const jsonValueSchema: z.ZodType = z.lazy(() =>
- z.union([
- z.string(),
- z.number(),
- z.boolean(),
- z.null(),
- z.array(jsonValueSchema),
- z.record(z.string(), jsonValueSchema),
- ]),
-);
-
-export const mcpArgsSchema = lazySchema(() =>
- zodSchema(
- z
- .object({
- serverLabel: z.string(),
- allowedTools: z
- .union([
- z.array(z.string()),
- z.object({
- readOnly: z.boolean().optional(),
- toolNames: z.array(z.string()).optional(),
- }),
- ])
- .optional(),
- authorization: z.string().optional(),
- connectorId: z.string().optional(),
- headers: z.record(z.string(), z.string()).optional(),
-
- requireApproval: z
- .union([
- z.enum(['always', 'never']),
- z.object({
- never: z
- .object({
- toolNames: z.array(z.string()).optional(),
- })
- .optional(),
- }),
- ])
- .optional(),
- serverDescription: z.string().optional(),
- serverUrl: z.string().optional(),
- })
- .refine(
- v => v.serverUrl != null || v.connectorId != null,
- 'One of serverUrl or connectorId must be provided.',
- ),
- ),
-);
-
-const mcpInputSchema = lazySchema(() => zodSchema(z.object({})));
-
-export const mcpOutputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- type: z.literal('call'),
- serverLabel: z.string(),
- name: z.string(),
- arguments: z.string(),
- output: z.string().nullish(),
- error: z.union([z.string(), jsonValueSchema]).optional(),
- }),
- ),
-);
-
-type McpArgs = {
- /** A label for this MCP server, used to identify it in tool calls. */
- serverLabel: string;
- /** List of allowed tool names or a filter object. */
- allowedTools?:
- | string[]
- | {
- readOnly?: boolean;
- toolNames?: string[];
- };
- /** OAuth access token usable with the remote MCP server or connector. */
- authorization?: string;
- /** Identifier for a service connector. */
- connectorId?: string;
- /** Optional HTTP headers to send to the MCP server. */
- headers?: Record;
- /**
- * Which tools require approval before execution.
- */
- requireApproval?:
- | 'always'
- | 'never'
- | {
- never?: {
- toolNames?: string[];
- };
- };
- /** Optional description of the MCP server. */
- serverDescription?: string;
- /** URL for the MCP server. One of serverUrl or connectorId must be provided. */
- serverUrl?: string;
-};
-
-export const mcpToolFactory = createProviderToolFactoryWithOutputSchema<
- {},
- {
- type: 'call';
- serverLabel: string;
- name: string;
- arguments: string;
- output?: string | null;
- error?: JSONValue;
- },
- McpArgs
->({
- id: 'openai.mcp',
- inputSchema: mcpInputSchema,
- outputSchema: mcpOutputSchema,
-});
-
-export const mcp = (args: McpArgs) => mcpToolFactory(args);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/shell.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/shell.ts
deleted file mode 100644
index 439b78ebf..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/shell.ts
+++ /dev/null
@@ -1,203 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const shellInputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- action: z.object({
- commands: z.array(z.string()),
- timeoutMs: z.number().optional(),
- maxOutputLength: z.number().optional(),
- }),
- }),
- ),
-);
-
-export const shellOutputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- output: z.array(
- z.object({
- stdout: z.string(),
- stderr: z.string(),
- outcome: z.discriminatedUnion('type', [
- z.object({ type: z.literal('timeout') }),
- z.object({ type: z.literal('exit'), exitCode: z.number() }),
- ]),
- }),
- ),
- }),
- ),
-);
-
-const shellSkillsSchema = z
- .array(
- z.discriminatedUnion('type', [
- z.object({
- type: z.literal('skillReference'),
- skillId: z.string(),
- version: z.string().optional(),
- }),
- z.object({
- type: z.literal('inline'),
- name: z.string(),
- description: z.string(),
- source: z.object({
- type: z.literal('base64'),
- mediaType: z.literal('application/zip'),
- data: z.string(),
- }),
- }),
- ]),
- )
- .optional();
-
-export const shellArgsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- environment: z
- .union([
- z.object({
- type: z.literal('containerAuto'),
- fileIds: z.array(z.string()).optional(),
- memoryLimit: z.enum(['1g', '4g', '16g', '64g']).optional(),
- networkPolicy: z
- .discriminatedUnion('type', [
- z.object({ type: z.literal('disabled') }),
- z.object({
- type: z.literal('allowlist'),
- allowedDomains: z.array(z.string()),
- domainSecrets: z
- .array(
- z.object({
- domain: z.string(),
- name: z.string(),
- value: z.string(),
- }),
- )
- .optional(),
- }),
- ])
- .optional(),
- skills: shellSkillsSchema,
- }),
- z.object({
- type: z.literal('containerReference'),
- containerId: z.string(),
- }),
- z.object({
- type: z.literal('local').optional(),
- skills: z
- .array(
- z.object({
- name: z.string(),
- description: z.string(),
- path: z.string(),
- }),
- )
- .optional(),
- }),
- ])
- .optional(),
- }),
- ),
-);
-
-type ShellArgs = {
- environment?:
- | {
- type: 'containerAuto';
- fileIds?: string[];
- memoryLimit?: '1g' | '4g' | '16g' | '64g';
- networkPolicy?:
- | { type: 'disabled' }
- | {
- type: 'allowlist';
- allowedDomains: string[];
- domainSecrets?: Array<{
- domain: string;
- name: string;
- value: string;
- }>;
- };
- skills?: Array<
- | { type: 'skillReference'; skillId: string; version?: string }
- | {
- type: 'inline';
- name: string;
- description: string;
- source: {
- type: 'base64';
- mediaType: 'application/zip';
- data: string;
- };
- }
- >;
- }
- | {
- type: 'containerReference';
- containerId: string;
- }
- | {
- type?: 'local';
- skills?: Array<{
- name: string;
- description: string;
- path: string;
- }>;
- };
-};
-
-export const shell = createProviderToolFactoryWithOutputSchema<
- {
- /**
- * Shell tool action containing commands to execute.
- */
- action: {
- /**
- * A list of shell commands to execute.
- */
- commands: string[];
-
- /**
- * Optional timeout in milliseconds for the commands.
- */
- timeoutMs?: number;
-
- /**
- * Optional maximum number of characters to return from each command.
- */
- maxOutputLength?: number;
- };
- },
- {
- /**
- * An array of shell call output contents.
- */
- output: Array<{
- /**
- * Standard output from the command.
- */
- stdout: string;
-
- /**
- * Standard error from the command.
- */
- stderr: string;
-
- /**
- * The outcome of the shell execution - either timeout or exit with code.
- */
- outcome: { type: 'timeout' } | { type: 'exit'; exitCode: number };
- }>;
- },
- ShellArgs
->({
- id: 'openai.shell',
- inputSchema: shellInputSchema,
- outputSchema: shellOutputSchema,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/tool-search.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/tool-search.ts
deleted file mode 100644
index 28d69eb47..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/tool-search.ts
+++ /dev/null
@@ -1,98 +0,0 @@
-import { JSONObject } from '@ai-sdk/provider';
-import {
- createProviderToolFactoryWithOutputSchema,
- FlexibleSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const toolSearchArgsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- execution: z.enum(['server', 'client']).optional(),
- description: z.string().optional(),
- parameters: z.record(z.string(), z.unknown()).optional(),
- }),
- ),
-);
-
-export const toolSearchInputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- arguments: z.unknown().optional(),
- call_id: z.string().nullish(),
- }),
- ),
-);
-
-export const toolSearchOutputSchema: FlexibleSchema<{
- tools: Array;
-}> = lazySchema(() =>
- zodSchema(
- z.object({
- tools: z.array(z.record(z.string(), z.unknown())),
- }),
- ),
-) as FlexibleSchema<{ tools: Array }>;
-
-const toolSearchToolFactory = createProviderToolFactoryWithOutputSchema<
- {
- /**
- * The arguments from the tool_search_call.
- * This is preserved for multi-turn conversation reconstruction.
- */
- arguments?: unknown;
-
- /**
- * The call ID from the tool_search_call.
- * Present for client-executed tool search; null for hosted.
- */
- call_id?: string | null;
- },
- {
- /**
- * The tools that were loaded by the tool search.
- * These are the deferred tools that the model requested to load.
- * Each tool is represented as a JSON object with properties depending on its type.
- *
- * Common properties include:
- * - `type`: The type of the tool (e.g., 'function', 'web_search', etc.)
- * - `name`: The name of the tool (for function tools)
- * - `description`: A description of the tool
- * - `deferLoading`: Whether this tool was deferred (had defer_loading: true)
- * - `parameters`: The JSON Schema for the function parameters (for function tools)
- * - `strict`: Whether to enable strict schema adherence (for function tools)
- */
- tools: Array;
- },
- {
- /**
- * Whether the tool search is executed by the server (hosted) or client.
- * - `'server'` (default): OpenAI performs the search across deferred tools.
- * - `'client'`: The model emits a `tool_search_call` and your `execute`
- * function performs the lookup, returning the tools to load.
- */
- execution?: 'server' | 'client';
-
- /**
- * A description of the tool search capability.
- * Only used for client-executed tool search.
- */
- description?: string;
-
- /**
- * JSON Schema for the search arguments your application expects.
- * Only used for client-executed tool search.
- */
- parameters?: Record;
- }
->({
- id: 'openai.tool_search',
- inputSchema: toolSearchInputSchema,
- outputSchema: toolSearchOutputSchema,
-});
-
-export const toolSearch = (
- args: Parameters[0] = {},
-) => toolSearchToolFactory(args);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/web-search-preview.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/web-search-preview.ts
deleted file mode 100644
index 24405147f..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/web-search-preview.ts
+++ /dev/null
@@ -1,141 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const webSearchPreviewArgsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- searchContextSize: z.enum(['low', 'medium', 'high']).optional(),
- userLocation: z
- .object({
- type: z.literal('approximate'),
- country: z.string().optional(),
- city: z.string().optional(),
- region: z.string().optional(),
- timezone: z.string().optional(),
- })
- .optional(),
- }),
- ),
-);
-
-export const webSearchPreviewInputSchema = lazySchema(() =>
- zodSchema(z.object({})),
-);
-
-const webSearchPreviewOutputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- action: z
- .discriminatedUnion('type', [
- z.object({
- type: z.literal('search'),
- query: z.string().optional(),
- }),
- z.object({
- type: z.literal('openPage'),
- url: z.string().nullish(),
- }),
- z.object({
- type: z.literal('findInPage'),
- url: z.string().nullish(),
- pattern: z.string().nullish(),
- }),
- ])
- .optional(),
- }),
- ),
-);
-
-export const webSearchPreview = createProviderToolFactoryWithOutputSchema<
- {
- // Web search preview doesn't take input parameters - it's controlled by the prompt
- },
- {
- /**
- * An object describing the specific action taken in this web search call.
- * Includes details on how the model used the web (search, open_page, find_in_page).
- */
- action?:
- | {
- /**
- * Action type "search" - Performs a web search query.
- */
- type: 'search';
-
- /**
- * The search query.
- */
- query?: string;
- }
- | {
- /**
- * Action type "openPage" - Opens a specific URL from search results.
- */
- type: 'openPage';
-
- /**
- * The URL opened by the model.
- */
- url?: string | null;
- }
- | {
- /**
- * Action type "findInPage": Searches for a pattern within a loaded page.
- */
- type: 'findInPage';
-
- /**
- * The URL of the page searched for the pattern.
- */
- url?: string | null;
-
- /**
- * The pattern or text to search for within the page.
- */
- pattern?: string | null;
- };
- },
- {
- /**
- * Search context size to use for the web search.
- * - high: Most comprehensive context, highest cost, slower response
- * - medium: Balanced context, cost, and latency (default)
- * - low: Least context, lowest cost, fastest response
- */
- searchContextSize?: 'low' | 'medium' | 'high';
-
- /**
- * User location information to provide geographically relevant search results.
- */
- userLocation?: {
- /**
- * Type of location (always 'approximate')
- */
- type: 'approximate';
- /**
- * Two-letter ISO country code (e.g., 'US', 'GB')
- */
- country?: string;
- /**
- * City name (free text, e.g., 'Minneapolis')
- */
- city?: string;
- /**
- * Region name (free text, e.g., 'Minnesota')
- */
- region?: string;
- /**
- * IANA timezone (e.g., 'America/Chicago')
- */
- timezone?: string;
- };
- }
->({
- id: 'openai.web_search_preview',
- inputSchema: webSearchPreviewInputSchema,
- outputSchema: webSearchPreviewOutputSchema,
-});
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/web-search.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/web-search.ts
deleted file mode 100644
index 2bceb6809..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/tool/web-search.ts
+++ /dev/null
@@ -1,181 +0,0 @@
-import {
- createProviderToolFactoryWithOutputSchema,
- lazySchema,
- zodSchema,
-} from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const webSearchArgsSchema = lazySchema(() =>
- zodSchema(
- z.object({
- externalWebAccess: z.boolean().optional(),
- filters: z
- .object({ allowedDomains: z.array(z.string()).optional() })
- .optional(),
- searchContextSize: z.enum(['low', 'medium', 'high']).optional(),
- userLocation: z
- .object({
- type: z.literal('approximate'),
- country: z.string().optional(),
- city: z.string().optional(),
- region: z.string().optional(),
- timezone: z.string().optional(),
- })
- .optional(),
- }),
- ),
-);
-
-const webSearchInputSchema = lazySchema(() => zodSchema(z.object({})));
-
-export const webSearchOutputSchema = lazySchema(() =>
- zodSchema(
- z.object({
- action: z
- .discriminatedUnion('type', [
- z.object({
- type: z.literal('search'),
- query: z.string().optional(),
- }),
- z.object({
- type: z.literal('openPage'),
- url: z.string().nullish(),
- }),
- z.object({
- type: z.literal('findInPage'),
- url: z.string().nullish(),
- pattern: z.string().nullish(),
- }),
- ])
- .optional(),
- sources: z
- .array(
- z.discriminatedUnion('type', [
- z.object({ type: z.literal('url'), url: z.string() }),
- z.object({ type: z.literal('api'), name: z.string() }),
- ]),
- )
- .optional(),
- }),
- ),
-);
-
-export const webSearchToolFactory = createProviderToolFactoryWithOutputSchema<
- {
- // Web search doesn't take input parameters - it's controlled by the prompt
- },
- {
- /**
- * An object describing the specific action taken in this web search call.
- * Includes details on how the model used the web (search, open_page, find_in_page).
- */
- action?:
- | {
- /**
- * Action type "search" - Performs a web search query.
- */
- type: 'search';
-
- /**
- * The search query.
- */
- query?: string;
- }
- | {
- /**
- * Action type "openPage" - Opens a specific URL from search results.
- */
- type: 'openPage';
-
- /**
- * The URL opened by the model.
- */
- url?: string | null;
- }
- | {
- /**
- * Action type "findInPage": Searches for a pattern within a loaded page.
- */
- type: 'findInPage';
-
- /**
- * The URL of the page searched for the pattern.
- */
- url?: string | null;
-
- /**
- * The pattern or text to search for within the page.
- */
- pattern?: string | null;
- };
-
- /**
- * Optional sources cited by the model for the web search call.
- */
- sources?: Array<
- { type: 'url'; url: string } | { type: 'api'; name: string }
- >;
- },
- {
- /**
- * Whether to use external web access for fetching live content.
- * - true: Fetch live web content (default)
- * - false: Use cached/indexed results
- */
- externalWebAccess?: boolean;
-
- /**
- * Filters for the search.
- */
- filters?: {
- /**
- * Allowed domains for the search.
- * If not provided, all domains are allowed.
- * Subdomains of the provided domains are allowed as well.
- */
- allowedDomains?: string[];
- };
-
- /**
- * Search context size to use for the web search.
- * - high: Most comprehensive context, highest cost, slower response
- * - medium: Balanced context, cost, and latency (default)
- * - low: Least context, lowest cost, fastest response
- */
- searchContextSize?: 'low' | 'medium' | 'high';
-
- /**
- * User location information to provide geographically relevant search results.
- */
- userLocation?: {
- /**
- * Type of location (always 'approximate')
- */
- type: 'approximate';
- /**
- * Two-letter ISO country code (e.g., 'US', 'GB')
- */
- country?: string;
- /**
- * City name (free text, e.g., 'Minneapolis')
- */
- city?: string;
- /**
- * Region name (free text, e.g., 'Minnesota')
- */
- region?: string;
- /**
- * IANA timezone (e.g., 'America/Chicago')
- */
- timezone?: string;
- };
- }
->({
- id: 'openai.web_search',
- inputSchema: webSearchInputSchema,
- outputSchema: webSearchOutputSchema,
-});
-
-export const webSearch = (
- args: Parameters[0] = {}, // default
-) => webSearchToolFactory(args);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/transcription/openai-transcription-api.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/transcription/openai-transcription-api.ts
deleted file mode 100644
index 4753c65b6..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/transcription/openai-transcription-api.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export const openaiTranscriptionResponseSchema = lazySchema(() =>
- zodSchema(
- z.object({
- text: z.string(),
- language: z.string().nullish(),
- duration: z.number().nullish(),
- words: z
- .array(
- z.object({
- word: z.string(),
- start: z.number(),
- end: z.number(),
- }),
- )
- .nullish(),
- segments: z
- .array(
- z.object({
- id: z.number(),
- seek: z.number(),
- start: z.number(),
- end: z.number(),
- text: z.string(),
- tokens: z.array(z.number()),
- temperature: z.number(),
- avg_logprob: z.number(),
- compression_ratio: z.number(),
- no_speech_prob: z.number(),
- }),
- )
- .nullish(),
- }),
- ),
-);
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/transcription/openai-transcription-model.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/transcription/openai-transcription-model.ts
deleted file mode 100644
index ef5efa080..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/transcription/openai-transcription-model.ts
+++ /dev/null
@@ -1,232 +0,0 @@
-import {
- TranscriptionModelV3,
- TranscriptionModelV3CallOptions,
- SharedV3Warning,
-} from '@ai-sdk/provider';
-import {
- combineHeaders,
- convertBase64ToUint8Array,
- createJsonResponseHandler,
- mediaTypeToExtension,
- parseProviderOptions,
- postFormDataToApi,
-} from '@ai-sdk/provider-utils';
-import { OpenAIConfig } from '../openai-config';
-import { openaiFailedResponseHandler } from '../openai-error';
-import { openaiTranscriptionResponseSchema } from './openai-transcription-api';
-import {
- OpenAITranscriptionModelId,
- openAITranscriptionModelOptions,
- OpenAITranscriptionModelOptions,
-} from './openai-transcription-options';
-
-export type OpenAITranscriptionCallOptions = Omit<
- TranscriptionModelV3CallOptions,
- 'providerOptions'
-> & {
- providerOptions?: {
- openai?: OpenAITranscriptionModelOptions;
- };
-};
-
-interface OpenAITranscriptionModelConfig extends OpenAIConfig {
- _internal?: {
- currentDate?: () => Date;
- };
-}
-
-// https://platform.openai.com/docs/guides/speech-to-text#supported-languages
-const languageMap = {
- afrikaans: 'af',
- arabic: 'ar',
- armenian: 'hy',
- azerbaijani: 'az',
- belarusian: 'be',
- bosnian: 'bs',
- bulgarian: 'bg',
- catalan: 'ca',
- chinese: 'zh',
- croatian: 'hr',
- czech: 'cs',
- danish: 'da',
- dutch: 'nl',
- english: 'en',
- estonian: 'et',
- finnish: 'fi',
- french: 'fr',
- galician: 'gl',
- german: 'de',
- greek: 'el',
- hebrew: 'he',
- hindi: 'hi',
- hungarian: 'hu',
- icelandic: 'is',
- indonesian: 'id',
- italian: 'it',
- japanese: 'ja',
- kannada: 'kn',
- kazakh: 'kk',
- korean: 'ko',
- latvian: 'lv',
- lithuanian: 'lt',
- macedonian: 'mk',
- malay: 'ms',
- marathi: 'mr',
- maori: 'mi',
- nepali: 'ne',
- norwegian: 'no',
- persian: 'fa',
- polish: 'pl',
- portuguese: 'pt',
- romanian: 'ro',
- russian: 'ru',
- serbian: 'sr',
- slovak: 'sk',
- slovenian: 'sl',
- spanish: 'es',
- swahili: 'sw',
- swedish: 'sv',
- tagalog: 'tl',
- tamil: 'ta',
- thai: 'th',
- turkish: 'tr',
- ukrainian: 'uk',
- urdu: 'ur',
- vietnamese: 'vi',
- welsh: 'cy',
-};
-
-export class OpenAITranscriptionModel implements TranscriptionModelV3 {
- readonly specificationVersion = 'v3';
-
- get provider(): string {
- return this.config.provider;
- }
-
- constructor(
- readonly modelId: OpenAITranscriptionModelId,
- private readonly config: OpenAITranscriptionModelConfig,
- ) {}
-
- private async getArgs({
- audio,
- mediaType,
- providerOptions,
- }: OpenAITranscriptionCallOptions) {
- const warnings: SharedV3Warning[] = [];
-
- // Parse provider options
- const openAIOptions = await parseProviderOptions({
- provider: 'openai',
- providerOptions,
- schema: openAITranscriptionModelOptions,
- });
-
- // Create form data with base fields
- const formData = new FormData();
- const blob =
- audio instanceof Uint8Array
- ? new Blob([audio])
- : new Blob([convertBase64ToUint8Array(audio)]);
-
- formData.append('model', this.modelId);
- const fileExtension = mediaTypeToExtension(mediaType);
- formData.append(
- 'file',
- new File([blob], 'audio', { type: mediaType }),
- `audio.${fileExtension}`,
- );
-
- // Add provider-specific options
- if (openAIOptions) {
- const transcriptionModelOptions = {
- include: openAIOptions.include,
- language: openAIOptions.language,
- prompt: openAIOptions.prompt,
- // https://platform.openai.com/docs/api-reference/audio/createTranscription#audio_createtranscription-response_format
- // prefer verbose_json to get segments for models that support it
- response_format: [
- 'gpt-4o-transcribe',
- 'gpt-4o-mini-transcribe',
- ].includes(this.modelId)
- ? 'json'
- : 'verbose_json',
- temperature: openAIOptions.temperature,
- timestamp_granularities: openAIOptions.timestampGranularities,
- };
-
- for (const [key, value] of Object.entries(transcriptionModelOptions)) {
- if (value != null) {
- if (Array.isArray(value)) {
- for (const item of value) {
- formData.append(`${key}[]`, String(item));
- }
- } else {
- formData.append(key, String(value));
- }
- }
- }
- }
-
- return {
- formData,
- warnings,
- };
- }
-
- async doGenerate(
- options: OpenAITranscriptionCallOptions,
- ): Promise>> {
- const currentDate = this.config._internal?.currentDate?.() ?? new Date();
- const { formData, warnings } = await this.getArgs(options);
-
- const {
- value: response,
- responseHeaders,
- rawValue: rawResponse,
- } = await postFormDataToApi({
- url: this.config.url({
- path: '/audio/transcriptions',
- modelId: this.modelId,
- }),
- headers: combineHeaders(this.config.headers(), options.headers),
- formData,
- failedResponseHandler: openaiFailedResponseHandler,
- successfulResponseHandler: createJsonResponseHandler(
- openaiTranscriptionResponseSchema,
- ),
- abortSignal: options.abortSignal,
- fetch: this.config.fetch,
- });
-
- const language =
- response.language != null && response.language in languageMap
- ? languageMap[response.language as keyof typeof languageMap]
- : undefined;
-
- return {
- text: response.text,
- segments:
- response.segments?.map(segment => ({
- text: segment.text,
- startSecond: segment.start,
- endSecond: segment.end,
- })) ??
- response.words?.map(word => ({
- text: word.word,
- startSecond: word.start,
- endSecond: word.end,
- })) ??
- [],
- language,
- durationInSeconds: response.duration ?? undefined,
- warnings,
- response: {
- timestamp: currentDate,
- modelId: this.modelId,
- headers: responseHeaders,
- body: rawResponse,
- },
- };
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/transcription/openai-transcription-options.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/transcription/openai-transcription-options.ts
deleted file mode 100644
index b992b423d..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/transcription/openai-transcription-options.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { InferSchema, lazySchema, zodSchema } from '@ai-sdk/provider-utils';
-import { z } from 'zod/v4';
-
-export type OpenAITranscriptionModelId =
- | 'whisper-1'
- | 'gpt-4o-mini-transcribe'
- | 'gpt-4o-mini-transcribe-2025-03-20'
- | 'gpt-4o-mini-transcribe-2025-12-15'
- | 'gpt-4o-transcribe'
- | 'gpt-4o-transcribe-diarize'
- | (string & {});
-
-// https://platform.openai.com/docs/api-reference/audio/createTranscription
-export const openAITranscriptionModelOptions = lazySchema(() =>
- zodSchema(
- z.object({
- /**
- * Additional information to include in the transcription response.
- */
-
- include: z.array(z.string()).optional(),
-
- /**
- * The language of the input audio in ISO-639-1 format.
- */
- language: z.string().optional(),
-
- /**
- * An optional text to guide the model's style or continue a previous audio segment.
- */
- prompt: z.string().optional(),
-
- /**
- * The sampling temperature, between 0 and 1.
- * @default 0
- */
- temperature: z.number().min(0).max(1).default(0).optional(),
-
- /**
- * The timestamp granularities to populate for this transcription.
- * @default ['segment']
- */
- timestampGranularities: z
- .array(z.enum(['word', 'segment']))
- .default(['segment'])
- .optional(),
- }),
- ),
-);
-
-export type OpenAITranscriptionModelOptions = InferSchema<
- typeof openAITranscriptionModelOptions
->;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/transcription/transcription-test.mp3 b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/transcription/transcription-test.mp3
deleted file mode 100644
index 6a4cf7b67..000000000
Binary files a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/transcription/transcription-test.mp3 and /dev/null differ
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/version.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/version.ts
deleted file mode 100644
index 7a35d46f5..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/openai/src/version.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-// Version string of this package injected at build time.
-declare const __PACKAGE_VERSION__: string | undefined;
-export const VERSION: string =
- typeof __PACKAGE_VERSION__ !== 'undefined'
- ? __PACKAGE_VERSION__
- : '0.0.0-test';
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/CHANGELOG.md b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/CHANGELOG.md
deleted file mode 100644
index 2efe6d401..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/CHANGELOG.md
+++ /dev/null
@@ -1,1574 +0,0 @@
-# @ai-sdk/provider-utils
-
-## 4.0.21
-
-### Patch Changes
-
-- 055cd68: fix: publish v6 to latest npm dist tag
-
-## 4.0.20
-
-### Patch Changes
-
-- 64ac0fd: fix(security): validate redirect targets in download functions to prevent SSRF bypass
-
- Both `downloadBlob` and `download` now validate the final URL after following HTTP redirects, preventing attackers from bypassing SSRF protections via open redirects to internal/private addresses.
-
-## 4.0.19
-
-### Patch Changes
-
-- ad4cfc2: Add URL validation to `downloadBlob` and `download` to prevent blind SSRF attacks. Private/internal IP addresses, localhost, and non-HTTP protocols are now rejected before fetching.
-
-## 4.0.18
-
-### Patch Changes
-
-- 824b295: fix(provider-utils): prevent unicode escape bypass in secureJsonParse
-
-## 4.0.17
-
-### Patch Changes
-
-- 08336f1: fix(bedrock): strip file extensions from filename
-
-## 4.0.16
-
-### Patch Changes
-
-- 58bc42d: feat(provider/openai): support custom tools with alias mapping
-
-## 4.0.15
-
-### Patch Changes
-
-- 4024a3a: security: prevent unbounded memory growth in download functions
-
- The `download()` and `downloadBlob()` functions now enforce a default 2 GiB size limit when downloading from user-provided URLs. Downloads that exceed this limit are aborted with a `DownloadError` instead of consuming unbounded memory and crashing the process. The `abortSignal` parameter is now passed through to `fetch()` in all download call sites.
-
- Added `download` option to `transcribe()` and `experimental_generateVideo()` for providing a custom download function. Use the new `createDownload({ maxBytes })` factory to configure download size limits.
-
-## 4.0.14
-
-### Patch Changes
-
-- Updated dependencies [7168375]
- - @ai-sdk/provider@3.0.8
-
-## 4.0.13
-
-### Patch Changes
-
-- Updated dependencies [53f6731]
- - @ai-sdk/provider@3.0.7
-
-## 4.0.12
-
-### Patch Changes
-
-- 96936e5: fix(provider-utils): export only types from standard-schema package
-
-## 4.0.11
-
-### Patch Changes
-
-- 2810850: fix(ai): improve type validation error messages with field paths and entity identifiers
-- Updated dependencies [2810850]
- - @ai-sdk/provider@3.0.6
-
-## 4.0.10
-
-### Patch Changes
-
-- 462ad00: fix(provider-utils): recognize bun fetch errors as retryable
-
-## 4.0.9
-
-### Patch Changes
-
-- 4de5a1d: chore: excluded tests from src folder in npm package
-- Updated dependencies [4de5a1d]
- - @ai-sdk/provider@3.0.5
-
-## 4.0.8
-
-### Patch Changes
-
-- Updated dependencies [5c090e7]
- - @ai-sdk/provider@3.0.4
-
-## 4.0.7
-
-### Patch Changes
-
-- 46f46e4: fix(provider-utils): improve tool type inference when using `inputExamples` with Zod schemas that use `.optional().default()` or `.refine()`.
-
-## 4.0.6
-
-### Patch Changes
-
-- 1b11dcb: chore(ai): include sources in npm package
-- Updated dependencies [1b11dcb]
- - @ai-sdk/provider@3.0.3
-
-## 4.0.5
-
-### Patch Changes
-
-- 34d1c8a: fix(provider-utils): add additionalProperties field for standard schema function
-
-## 4.0.4
-
-### Patch Changes
-
-- Updated dependencies [d937c8f]
- - @ai-sdk/provider@3.0.2
-
-## 4.0.3
-
-### Patch Changes
-
-- 0b429d4: fix(provider-utils): handle anyOf/allOf/oneOf and definitions in addAdditionalPropertiesToJsonSchema
-
-## 4.0.2
-
-### Patch Changes
-
-- 863d34f: fix: trigger release to update `@latest`
-- Updated dependencies [863d34f]
- - @ai-sdk/provider@3.0.1
-
-## 4.0.1
-
-### Patch Changes
-
-- 29264a3: feat: add MCP tool approval
-
-## 4.0.0
-
-### Major Changes
-
-- dee8b05: ai SDK 6 beta
-
-### Minor Changes
-
-- 78928cb: release: start 5.1 beta
-
-### Patch Changes
-
-- 0adc679: feat(provider): shared spec v3
-- 50b70d6: feat(anthropic): add programmatic tool calling
-- dce03c4: feat: tool input examples
-- 3b1d015: feat(ai): Effect schema support
-- 95f65c2: chore: use import \* from zod/v4
-- 016b111: fix(provider-utils): make ReadableStream.cancel() properly finalize async iterators
-- 58920e0: refactor: consolidate header normalization across packages, remove duplicates, preserve custom headers
-- 954c356: feat(openai): allow custom names for provider-defined tools
-- 544d4e8: chore(specification): rename v3 provider defined tool to provider tool
-- 521c537: feat(ai): Tool.needsApproval can be a function
-- e8109d3: feat: tool execution approval
-- 03849b0: move DelayedPromise into provider utils
-- e06565c: feat(provider-utils): add needsApproval support to provider-defined tools
-- 32d8dbb: fix(provider-utils): compatibility with V8 readonly execution environment
-- d116b4b: feat(ai): arktype support
-- 293a6b7: Added a title to the tools
-- 703459a: feat: tool execution approval for dynamic tools
-- 83e5744: feat: support async Tool.toModelOutput
-- 7e32fea: feat(ai): valibot support
-- 3ed5519: chore: rename ToolCallOptions to ToolExecutionOptions
-- 8dac895: feat: `LanguageModelV3`
-- cbb1d35: Update for provider-util changeset after change in PR #8588
-- 9061dc0: feat: image editing
-- 32223c8: feat: add toolCallId arg to toModelOutput
-- c1efac4: feat: add input arg to toModelOutput
-- 4616b86: chore: update zod peer depenedency version
-- 4f16c37: chore(provider-utils): upgrade eventsource-parser to 3.0.6
-- 81e29ab: chore: update docs
-- 6306603: chore: replace Validator with Schema
-- fca786b: feat(provider-utils): add MaybePromiseLike type
-- 763d04a: feat: Standard JSON Schema support
-- 3794514: feat: flexible tool output content support
-- e9e157f: fix: generate zod4 json schema from input schema
-- 960ec8f: chore: change argument of toModelOutput to parameter object
-- 1bd7d32: feat: tool-specific strict mode
-- f0b2157: fix: revert zod import change
-- 95f65c2: chore: load zod schemas lazily
-- Updated dependencies
- - @ai-sdk/provider@3.0.0
-
-## 4.0.0-beta.59
-
-### Patch Changes
-
-- Updated dependencies [475189e]
- - @ai-sdk/provider@3.0.0-beta.32
-
-## 4.0.0-beta.58
-
-### Patch Changes
-
-- Updated dependencies [2625a04]
- - @ai-sdk/provider@3.0.0-beta.31
-
-## 4.0.0-beta.57
-
-### Patch Changes
-
-- Updated dependencies [cbf52cd]
- - @ai-sdk/provider@3.0.0-beta.30
-
-## 4.0.0-beta.56
-
-### Patch Changes
-
-- Updated dependencies [9549c9e]
- - @ai-sdk/provider@3.0.0-beta.29
-
-## 4.0.0-beta.55
-
-### Patch Changes
-
-- 50b70d6: feat(anthropic): add programmatic tool calling
-
-## 4.0.0-beta.54
-
-### Patch Changes
-
-- 9061dc0: feat: image editing
-- Updated dependencies [9061dc0]
- - @ai-sdk/provider@3.0.0-beta.28
-
-## 4.0.0-beta.53
-
-### Patch Changes
-
-- Updated dependencies [366f50b]
- - @ai-sdk/provider@3.0.0-beta.27
-
-## 4.0.0-beta.52
-
-### Patch Changes
-
-- 763d04a: feat: Standard JSON Schema support
-
-## 4.0.0-beta.51
-
-### Patch Changes
-
-- c1efac4: feat: add input arg to toModelOutput
-
-## 4.0.0-beta.50
-
-### Patch Changes
-
-- 32223c8: feat: add toolCallId arg to toModelOutput
-
-## 4.0.0-beta.49
-
-### Patch Changes
-
-- 83e5744: feat: support async Tool.toModelOutput
-
-## 4.0.0-beta.48
-
-### Patch Changes
-
-- 960ec8f: chore: change argument of toModelOutput to parameter object
-
-## 4.0.0-beta.47
-
-### Patch Changes
-
-- e9e157f: fix: generate zod4 json schema from input schema
-
-## 4.0.0-beta.46
-
-### Patch Changes
-
-- 81e29ab: chore: update docs
-
-## 4.0.0-beta.45
-
-### Patch Changes
-
-- Updated dependencies [3bd2689]
- - @ai-sdk/provider@3.0.0-beta.26
-
-## 4.0.0-beta.44
-
-### Patch Changes
-
-- Updated dependencies [53f3368]
- - @ai-sdk/provider@3.0.0-beta.25
-
-## 4.0.0-beta.43
-
-### Patch Changes
-
-- dce03c4: feat: tool input examples
-- Updated dependencies [dce03c4]
- - @ai-sdk/provider@3.0.0-beta.24
-
-## 4.0.0-beta.42
-
-### Patch Changes
-
-- 3ed5519: chore: rename ToolCallOptions to ToolExecutionOptions
-
-## 4.0.0-beta.41
-
-### Patch Changes
-
-- 1bd7d32: feat: tool-specific strict mode
-- Updated dependencies [1bd7d32]
- - @ai-sdk/provider@3.0.0-beta.23
-
-## 4.0.0-beta.40
-
-### Patch Changes
-
-- 544d4e8: chore(specification): rename v3 provider defined tool to provider tool
-- Updated dependencies [544d4e8]
- - @ai-sdk/provider@3.0.0-beta.22
-
-## 4.0.0-beta.39
-
-### Patch Changes
-
-- 954c356: feat(openai): allow custom names for provider-defined tools
-- Updated dependencies [954c356]
- - @ai-sdk/provider@3.0.0-beta.21
-
-## 4.0.0-beta.38
-
-### Patch Changes
-
-- 03849b0: move DelayedPromise into provider utils
-
-## 4.0.0-beta.37
-
-### Patch Changes
-
-- Updated dependencies [457318b]
- - @ai-sdk/provider@3.0.0-beta.20
-
-## 4.0.0-beta.36
-
-### Patch Changes
-
-- Updated dependencies [8d9e8ad]
- - @ai-sdk/provider@3.0.0-beta.19
-
-## 4.0.0-beta.35
-
-### Patch Changes
-
-- Updated dependencies [10d819b]
- - @ai-sdk/provider@3.0.0-beta.18
-
-## 4.0.0-beta.34
-
-### Patch Changes
-
-- Updated dependencies [db913bd]
- - @ai-sdk/provider@3.0.0-beta.17
-
-## 4.0.0-beta.33
-
-### Patch Changes
-
-- Updated dependencies [b681d7d]
- - @ai-sdk/provider@3.0.0-beta.16
-
-## 4.0.0-beta.32
-
-### Patch Changes
-
-- 32d8dbb: fix(provider-utils): compatibility with V8 readonly execution environment
-
-## 4.0.0-beta.31
-
-### Patch Changes
-
-- Updated dependencies [bb36798]
- - @ai-sdk/provider@3.0.0-beta.15
-
-## 4.0.0-beta.30
-
-### Patch Changes
-
-- 4f16c37: chore(provider-utils): upgrade eventsource-parser to 3.0.6
-
-## 4.0.0-beta.29
-
-### Patch Changes
-
-- Updated dependencies [af3780b]
- - @ai-sdk/provider@3.0.0-beta.14
-
-## 4.0.0-beta.28
-
-### Patch Changes
-
-- 016b111: fix(provider-utils): make ReadableStream.cancel() properly finalize async iterators
-
-## 4.0.0-beta.27
-
-### Patch Changes
-
-- Updated dependencies [37c58a0]
- - @ai-sdk/provider@3.0.0-beta.13
-
-## 4.0.0-beta.26
-
-### Patch Changes
-
-- Updated dependencies [d1bdadb]
- - @ai-sdk/provider@3.0.0-beta.12
-
-## 4.0.0-beta.25
-
-### Patch Changes
-
-- Updated dependencies [4c44a5b]
- - @ai-sdk/provider@3.0.0-beta.11
-
-## 4.0.0-beta.24
-
-### Patch Changes
-
-- Updated dependencies [0c3b58b]
- - @ai-sdk/provider@3.0.0-beta.10
-
-## 4.0.0-beta.23
-
-### Patch Changes
-
-- Updated dependencies [a755db5]
- - @ai-sdk/provider@3.0.0-beta.9
-
-## 4.0.0-beta.22
-
-### Patch Changes
-
-- 58920e0: refactor: consolidate header normalization across packages, remove duplicates, preserve custom headers
-
-## 4.0.0-beta.21
-
-### Patch Changes
-
-- 293a6b7: Added a title to the tools
-
-## 4.0.0-beta.20
-
-### Patch Changes
-
-- fca786b: feat(provider-utils): add MaybePromiseLike type
-
-## 4.0.0-beta.19
-
-### Patch Changes
-
-- 3794514: feat: flexible tool output content support
-- Updated dependencies [3794514]
- - @ai-sdk/provider@3.0.0-beta.8
-
-## 4.0.0-beta.18
-
-### Patch Changes
-
-- Updated dependencies [81d4308]
- - @ai-sdk/provider@3.0.0-beta.7
-
-## 4.0.0-beta.17
-
-### Patch Changes
-
-- 703459a: feat: tool execution approval for dynamic tools
-
-## 4.0.0-beta.16
-
-### Patch Changes
-
-- 6306603: chore: replace Validator with Schema
-
-## 4.0.0-beta.15
-
-### Patch Changes
-
-- f0b2157: fix: revert zod import change
-
-## 4.0.0-beta.14
-
-### Patch Changes
-
-- 3b1d015: feat(ai): Effect schema support
-
-## 4.0.0-beta.13
-
-### Patch Changes
-
-- d116b4b: feat(ai): arktype support
-
-## 4.0.0-beta.12
-
-### Patch Changes
-
-- 7e32fea: feat(ai): valibot support
-
-## 4.0.0-beta.11
-
-### Patch Changes
-
-- 95f65c2: chore: use import \* from zod/v4
-- 95f65c2: chore: load zod schemas lazily
-
-## 4.0.0-beta.10
-
-### Major Changes
-
-- dee8b05: ai SDK 6 beta
-
-### Patch Changes
-
-- Updated dependencies [dee8b05]
- - @ai-sdk/provider@3.0.0-beta.6
-
-## 3.1.0-beta.9
-
-### Patch Changes
-
-- 521c537: feat(ai): Tool.needsApproval can be a function
-
-## 3.1.0-beta.8
-
-### Patch Changes
-
-- e06565c: feat(provider-utils): add needsApproval support to provider-defined tools
-
-## 3.1.0-beta.7
-
-### Patch Changes
-
-- e8109d3: feat: tool execution approval
-- Updated dependencies
- - @ai-sdk/provider@2.1.0-beta.5
-
-## 3.1.0-beta.6
-
-### Patch Changes
-
-- 0adc679: feat(provider): shared spec v3
-- Updated dependencies
- - @ai-sdk/provider@2.1.0-beta.4
-
-## 3.1.0-beta.5
-
-### Patch Changes
-
-- 8dac895: feat: `LanguageModelV3`
-- Updated dependencies [8dac895]
- - @ai-sdk/provider@2.1.0-beta.3
-
-## 3.1.0-beta.4
-
-### Patch Changes
-
-- 4616b86: chore: update zod peer depenedency version
-
-## 3.1.0-beta.3
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.1.0-beta.2
-
-## 3.1.0-beta.2
-
-### Patch Changes
-
-- Updated dependencies [0c4822d]
- - @ai-sdk/provider@2.1.0-beta.1
-
-## 3.1.0-beta.1
-
-### Patch Changes
-
-- cbb1d35: Update for provider-util changeset after change in PR #8588
-
-## 3.1.0-beta.0
-
-### Minor Changes
-
-- 78928cb: release: start 5.1 beta
-
-### Patch Changes
-
-- Updated dependencies [78928cb]
- - @ai-sdk/provider@2.1.0-beta.0
-
-## 3.0.9
-
-### Patch Changes
-
-- 0294b58: feat(ai): set `ai`, `@ai-sdk/provider-utils`, and runtime in `user-agent` header
-
-## 3.0.8
-
-### Patch Changes
-
-- 99964ed: fix(provider-utils): fix type inference for toModelOutput
-
-## 3.0.7
-
-### Patch Changes
-
-- 886e7cd: chore(provider-utils): upgrade event-source parser to 3.0.5
-
-## 3.0.6
-
-### Patch Changes
-
-- 1b5a3d3: chore(provider-util): integrate zod-to-json-schema
-
-## 3.0.5
-
-### Patch Changes
-
-- 0857788: fix(provider/groq): `experimental_transcribe` fails with valid Buffer
-
-## 3.0.4
-
-### Patch Changes
-
-- 68751f9: fix(provider-utils): add inject json utility function
-
-## 3.0.3
-
-### Patch Changes
-
-- 034e229: fix(provider/utils): fix FlexibleSchema type inference with zod/v3
-- f25040d: fix(provider-utils): fix tools type inference
-
-## 3.0.2
-
-### Patch Changes
-
-- 38ac190: feat(ai): preliminary tool results
-
-## 3.0.1
-
-### Patch Changes
-
-- 90d212f: feat (ai): add experimental tool call context
-
-## 3.0.0
-
-### Major Changes
-
-- 5d142ab: remove deprecated `CoreToolCall` and `CoreToolResult` types
-- d5f588f: AI SDK 5
-- e025824: refactoring (ai): restructure provider-defined tools
-- 40acf9b: feat (ui): introduce ChatStore and ChatTransport
-- 957b739: chore (provider-utils): rename TestServerCall.requestBody to requestBodyJson
-- ea7a7c9: feat (ui): UI message metadata
-- 41fa418: chore (provider-utils): return IdGenerator interface
-- 71f938d: feat (ai): add output schema for tools
-
-### Patch Changes
-
-- a571d6e: chore(provider-utils): move ToolResultContent to provider-utils
-- e7fcc86: feat (ai): introduce dynamic tools
-- 45c1ea2: refactoring: introduce FlexibleSchema
-- 060370c: feat(provider-utils): add TestServerCall#requestCredentials
-- 0571b98: chore (provider-utils): update eventsource-parser to 3.0.3
-- 4fef487: feat: support for zod v4 for schema validation
-
- All these methods now accept both a zod v4 and zod v3 schemas for validation:
-
- - `generateObject()`
- - `streamObject()`
- - `generateText()`
- - `experimental_useObject()` from `@ai-sdk/react`
- - `streamUI()` from `@ai-sdk/rsc`
-
-- 0c0c0b3: refactor (provider-utils): move `customAlphabet()` method from `nanoid` into codebase
-- 8ba77a7: chore (provider-utils): use eventsource-parser library
-- a166433: feat: add transcription with experimental_transcribe
-- 9f95b35: refactor (provider-utils): copy relevant code from `secure-json-parse` into codebase
-- 66962ed: fix(packages): export node10 compatible types
-- 05d2819: feat: allow zod 4.x as peer dependency
-- ac34802: Add clear object function to StructuredObject
-- 63d791d: chore (utils): remove unused test helpers
-- 87b828f: fix(provider-utils): fix SSE parser bug (CRLF)
-- bfdca8d: feat (ai): add InferToolInput and InferToolOutput helpers
-- 0ff02bb: chore(provider-utils): move over jsonSchema
-- 39a4fab: fix (provider-utils): detect failed fetch in browser environments
-- 57edfcb: Adds support for async zod validators
-- faf8446: chore (provider-utils): switch to standard-schema
-- d1a034f: feature: using Zod 4 for internal stuff
-- 88a8ee5: fix (ai): support abort during retry waits
-- 205077b: fix: improve Zod compatibility
-- 28a5ed5: refactoring: move tools helper into provider-utils
-- dd5fd43: feat (ai): support dynamic tools in Chat onToolCall
-- 383cbfa: feat (ai): add isAborted to onFinish callback for ui message streams
-- Updated dependencies
- - @ai-sdk/provider@2.0.0
-
-## 3.0.0-beta.10
-
-### Patch Changes
-
-- 88a8ee5: fix (ai): support abort during retry waits
-
-## 3.0.0-beta.9
-
-### Patch Changes
-
-- Updated dependencies [27deb4d]
- - @ai-sdk/provider@2.0.0-beta.2
-
-## 3.0.0-beta.8
-
-### Patch Changes
-
-- dd5fd43: feat (ai): support dynamic tools in Chat onToolCall
-
-## 3.0.0-beta.7
-
-### Patch Changes
-
-- e7fcc86: feat (ai): introduce dynamic tools
-
-## 3.0.0-beta.6
-
-### Patch Changes
-
-- ac34802: Add clear object function to StructuredObject
-
-## 3.0.0-beta.5
-
-### Patch Changes
-
-- 57edfcb: Adds support for async zod validators
-- 383cbfa: feat (ai): add isAborted to onFinish callback for ui message streams
-
-## 3.0.0-beta.4
-
-### Patch Changes
-
-- 205077b: fix: improve Zod compatibility
-
-## 3.0.0-beta.3
-
-### Patch Changes
-
-- 05d2819: feat: allow zod 4.x as peer dependency
-
-## 3.0.0-beta.2
-
-### Patch Changes
-
-- 0571b98: chore (provider-utils): update eventsource-parser to 3.0.3
-- 39a4fab: fix (provider-utils): detect failed fetch in browser environments
-- d1a034f: feature: using Zod 4 for internal stuff
-
-## 3.0.0-beta.1
-
-### Major Changes
-
-- e025824: refactoring (ai): restructure provider-defined tools
-- 71f938d: feat (ai): add output schema for tools
-
-### Patch Changes
-
-- 45c1ea2: refactoring: introduce FlexibleSchema
-- bfdca8d: feat (ai): add InferToolInput and InferToolOutput helpers
-- 28a5ed5: refactoring: move tools helper into provider-utils
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-beta.1
-
-## 3.0.0-alpha.15
-
-### Patch Changes
-
-- 8ba77a7: chore (provider-utils): use eventsource-parser library
-- Updated dependencies [48d257a]
- - @ai-sdk/provider@2.0.0-alpha.15
-
-## 3.0.0-alpha.14
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-alpha.14
-
-## 3.0.0-alpha.13
-
-### Patch Changes
-
-- Updated dependencies [68ecf2f]
- - @ai-sdk/provider@2.0.0-alpha.13
-
-## 3.0.0-alpha.12
-
-### Patch Changes
-
-- Updated dependencies [e2aceaf]
- - @ai-sdk/provider@2.0.0-alpha.12
-
-## 3.0.0-alpha.11
-
-### Patch Changes
-
-- Updated dependencies [c1e6647]
- - @ai-sdk/provider@2.0.0-alpha.11
-
-## 3.0.0-alpha.10
-
-### Patch Changes
-
-- Updated dependencies [c4df419]
- - @ai-sdk/provider@2.0.0-alpha.10
-
-## 3.0.0-alpha.9
-
-### Patch Changes
-
-- Updated dependencies [811dff3]
- - @ai-sdk/provider@2.0.0-alpha.9
-
-## 3.0.0-alpha.8
-
-### Patch Changes
-
-- 4fef487: feat: support for zod v4 for schema validation
-
- All these methods now accept both a zod v4 and zod v3 schemas for validation:
-
- - `generateObject()`
- - `streamObject()`
- - `generateText()`
- - `experimental_useObject()` from `@ai-sdk/react`
- - `streamUI()` from `@ai-sdk/rsc`
-
-- Updated dependencies [9222aeb]
- - @ai-sdk/provider@2.0.0-alpha.8
-
-## 3.0.0-alpha.7
-
-### Patch Changes
-
-- Updated dependencies [5c56081]
- - @ai-sdk/provider@2.0.0-alpha.7
-
-## 3.0.0-alpha.6
-
-### Patch Changes
-
-- Updated dependencies [0d2c085]
- - @ai-sdk/provider@2.0.0-alpha.6
-
-## 3.0.0-alpha.4
-
-### Patch Changes
-
-- Updated dependencies [dc714f3]
- - @ai-sdk/provider@2.0.0-alpha.4
-
-## 3.0.0-alpha.3
-
-### Patch Changes
-
-- Updated dependencies [6b98118]
- - @ai-sdk/provider@2.0.0-alpha.3
-
-## 3.0.0-alpha.2
-
-### Patch Changes
-
-- Updated dependencies [26535e0]
- - @ai-sdk/provider@2.0.0-alpha.2
-
-## 3.0.0-alpha.1
-
-### Patch Changes
-
-- Updated dependencies [3f2f00c]
- - @ai-sdk/provider@2.0.0-alpha.1
-
-## 3.0.0-canary.19
-
-### Patch Changes
-
-- faf8446: chore (provider-utils): switch to standard-schema
-
-## 3.0.0-canary.18
-
-### Major Changes
-
-- 40acf9b: feat (ui): introduce ChatStore and ChatTransport
-
-## 3.0.0-canary.17
-
-### Major Changes
-
-- ea7a7c9: feat (ui): UI message metadata
-
-## 3.0.0-canary.16
-
-### Patch Changes
-
-- 87b828f: fix(provider-utils): fix SSE parser bug (CRLF)
-
-## 3.0.0-canary.15
-
-### Major Changes
-
-- 41fa418: chore (provider-utils): return IdGenerator interface
-
-### Patch Changes
-
-- a571d6e: chore(provider-utils): move ToolResultContent to provider-utils
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.14
-
-## 3.0.0-canary.14
-
-### Major Changes
-
-- 957b739: chore (provider-utils): rename TestServerCall.requestBody to requestBodyJson
-
-### Patch Changes
-
-- Updated dependencies [9bd5ab5]
- - @ai-sdk/provider@2.0.0-canary.13
-
-## 3.0.0-canary.13
-
-### Patch Changes
-
-- 0ff02bb: chore(provider-utils): move over jsonSchema
-- Updated dependencies [7b3ae3f]
- - @ai-sdk/provider@2.0.0-canary.12
-
-## 3.0.0-canary.12
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.11
-
-## 3.0.0-canary.11
-
-### Patch Changes
-
-- 66962ed: fix(packages): export node10 compatible types
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.10
-
-## 3.0.0-canary.10
-
-### Patch Changes
-
-- Updated dependencies [e86be6f]
- - @ai-sdk/provider@2.0.0-canary.9
-
-## 3.0.0-canary.9
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.8
-
-## 3.0.0-canary.8
-
-### Major Changes
-
-- 5d142ab: remove deprecated `CoreToolCall` and `CoreToolResult` types
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.7
-
-## 3.0.0-canary.7
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.6
-
-## 3.0.0-canary.6
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.5
-
-## 3.0.0-canary.5
-
-### Patch Changes
-
-- Updated dependencies [6f6bb89]
- - @ai-sdk/provider@2.0.0-canary.4
-
-## 3.0.0-canary.4
-
-### Patch Changes
-
-- Updated dependencies [d1a1aa1]
- - @ai-sdk/provider@2.0.0-canary.3
-
-## 3.0.0-canary.3
-
-### Patch Changes
-
-- a166433: feat: add transcription with experimental_transcribe
-- 9f95b35: refactor (provider-utils): copy relevant code from `secure-json-parse` into codebase
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.2
-
-## 3.0.0-canary.2
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@2.0.0-canary.1
-
-## 3.0.0-canary.1
-
-### Patch Changes
-
-- 060370c: feat(provider-utils): add TestServerCall#requestCredentials
-- 0c0c0b3: refactor (provider-utils): move `customAlphabet()` method from `nanoid` into codebase
-- 63d791d: chore (utils): remove unused test helpers
-
-## 3.0.0-canary.0
-
-### Major Changes
-
-- d5f588f: AI SDK 5
-
-### Patch Changes
-
-- Updated dependencies [d5f588f]
- - @ai-sdk/provider@2.0.0-canary.0
-
-## 2.2.3
-
-### Patch Changes
-
-- 28be004: chore (provider-utils): add error method to TestStreamController
-
-## 2.2.2
-
-### Patch Changes
-
-- b01120e: chore (provider-utils): update unified test server
-
-## 2.2.1
-
-### Patch Changes
-
-- f10f0fa: fix (provider-utils): improve event source stream parsing performance
-
-## 2.2.0
-
-### Minor Changes
-
-- 5bc638d: AI SDK 4.2
-
-### Patch Changes
-
-- Updated dependencies [5bc638d]
- - @ai-sdk/provider@1.1.0
-
-## 2.1.15
-
-### Patch Changes
-
-- d0c4659: feat (provider-utils): parseProviderOptions function
-
-## 2.1.14
-
-### Patch Changes
-
-- Updated dependencies [0bd5bc6]
- - @ai-sdk/provider@1.0.12
-
-## 2.1.13
-
-### Patch Changes
-
-- Updated dependencies [2e1101a]
- - @ai-sdk/provider@1.0.11
-
-## 2.1.12
-
-### Patch Changes
-
-- 1531959: feat (provider-utils): add readable-stream to unified test server
-
-## 2.1.11
-
-### Patch Changes
-
-- Updated dependencies [e1d3d42]
- - @ai-sdk/provider@1.0.10
-
-## 2.1.10
-
-### Patch Changes
-
-- Updated dependencies [ddf9740]
- - @ai-sdk/provider@1.0.9
-
-## 2.1.9
-
-### Patch Changes
-
-- Updated dependencies [2761f06]
- - @ai-sdk/provider@1.0.8
-
-## 2.1.8
-
-### Patch Changes
-
-- 2e898b4: chore (ai): move mockId test helper into provider utils
-
-## 2.1.7
-
-### Patch Changes
-
-- 3ff4ef8: feat (provider-utils): export removeUndefinedEntries for working with e.g. headers
-
-## 2.1.6
-
-### Patch Changes
-
-- Updated dependencies [d89c3b9]
- - @ai-sdk/provider@1.0.7
-
-## 2.1.5
-
-### Patch Changes
-
-- 3a602ca: chore (core): rename CoreTool to Tool
-
-## 2.1.4
-
-### Patch Changes
-
-- 066206e: feat (provider-utils): move delay to provider-utils from ai
-
-## 2.1.3
-
-### Patch Changes
-
-- 39e5c1f: feat (provider-utils): add getFromApi and response handlers for binary responses and status-code errors
-
-## 2.1.2
-
-### Patch Changes
-
-- ed012d2: feat (provider): add metadata extraction mechanism to openai-compatible providers
-- Updated dependencies [3a58a2e]
- - @ai-sdk/provider@1.0.6
-
-## 2.1.1
-
-### Patch Changes
-
-- e7a9ec9: feat (provider-utils): include raw value in json parse results
-- Updated dependencies [0a699f1]
- - @ai-sdk/provider@1.0.5
-
-## 2.1.0
-
-### Minor Changes
-
-- 62ba5ad: release: AI SDK 4.1
-
-## 2.0.8
-
-### Patch Changes
-
-- 00114c5: feat: expose IDGenerator and createIdGenerator
-
-## 2.0.7
-
-### Patch Changes
-
-- 90fb95a: chore (provider-utils): switch to unified test server
-- e6dfef4: feat (provider/fireworks): Support add'l image models.
-- 6636db6: feat (provider-utils): add unified test server
-
-## 2.0.6
-
-### Patch Changes
-
-- 19a2ce7: feat (provider/fireworks): Add image model support.
-- 6337688: feat: change image generation errors to warnings
-- Updated dependencies
- - @ai-sdk/provider@1.0.4
-
-## 2.0.5
-
-### Patch Changes
-
-- 5ed5e45: chore (config): Use ts-library.json tsconfig for no-UI libs.
-- Updated dependencies [5ed5e45]
- - @ai-sdk/provider@1.0.3
-
-## 2.0.4
-
-### Patch Changes
-
-- Updated dependencies [09a9cab]
- - @ai-sdk/provider@1.0.2
-
-## 2.0.3
-
-### Patch Changes
-
-- 0984f0b: feat (provider-utils): Add resolvable type and utility routine.
-
-## 2.0.2
-
-### Patch Changes
-
-- Updated dependencies [b446ae5]
- - @ai-sdk/provider@1.0.1
-
-## 2.0.1
-
-### Patch Changes
-
-- c3ab5de: fix (provider-utils): downgrade nanoid and secure-json-parse (ESM compatibility)
-
-## 2.0.0
-
-### Major Changes
-
-- b469a7e: chore: remove isXXXError methods
-- b1da952: chore (provider-utils): remove convertStreamToArray
-- 8426f55: chore (ai):increase id generator default size from 7 to 16.
-- db46ce5: chore (provider-utils): remove isParseableJson export
-
-### Patch Changes
-
-- dce4158: chore (dependencies): update eventsource-parser to 3.0.0
-- dce4158: chore (dependencies): update nanoid to 5.0.8
-- Updated dependencies
- - @ai-sdk/provider@1.0.0
-
-## 2.0.0-canary.3
-
-### Major Changes
-
-- 8426f55: chore (ai):increase id generator default size from 7 to 16.
-
-## 2.0.0-canary.2
-
-### Patch Changes
-
-- dce4158: chore (dependencies): update eventsource-parser to 3.0.0
-- dce4158: chore (dependencies): update nanoid to 5.0.8
-
-## 2.0.0-canary.1
-
-### Major Changes
-
-- b1da952: chore (provider-utils): remove convertStreamToArray
-
-## 2.0.0-canary.0
-
-### Major Changes
-
-- b469a7e: chore: remove isXXXError methods
-- db46ce5: chore (provider-utils): remove isParseableJson export
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@1.0.0-canary.0
-
-## 1.0.22
-
-### Patch Changes
-
-- aa98cdb: chore: more flexible dependency versioning
-- 7b937c5: feat (provider-utils): improve id generator robustness
-- 811a317: feat (ai/core): multi-part tool results (incl. images)
-- Updated dependencies
- - @ai-sdk/provider@0.0.26
-
-## 1.0.21
-
-### Patch Changes
-
-- Updated dependencies [b9b0d7b]
- - @ai-sdk/provider@0.0.25
-
-## 1.0.20
-
-### Patch Changes
-
-- Updated dependencies [d595d0d]
- - @ai-sdk/provider@0.0.24
-
-## 1.0.19
-
-### Patch Changes
-
-- 273f696: fix (ai/provider-utils): expose size argument in generateId
-
-## 1.0.18
-
-### Patch Changes
-
-- 03313cd: feat (ai): expose response id, response model, response timestamp in telemetry and api
-- Updated dependencies
- - @ai-sdk/provider@0.0.23
-
-## 1.0.17
-
-### Patch Changes
-
-- Updated dependencies [26515cb]
- - @ai-sdk/provider@0.0.22
-
-## 1.0.16
-
-### Patch Changes
-
-- 09f895f: feat (ai/core): no-schema output for generateObject / streamObject
-
-## 1.0.15
-
-### Patch Changes
-
-- d67fa9c: feat (provider/amazon-bedrock): add support for session tokens
-
-## 1.0.14
-
-### Patch Changes
-
-- Updated dependencies [f2c025e]
- - @ai-sdk/provider@0.0.21
-
-## 1.0.13
-
-### Patch Changes
-
-- Updated dependencies [6ac355e]
- - @ai-sdk/provider@0.0.20
-
-## 1.0.12
-
-### Patch Changes
-
-- dd712ac: fix: use FetchFunction type to prevent self-reference
-
-## 1.0.11
-
-### Patch Changes
-
-- Updated dependencies [dd4a0f5]
- - @ai-sdk/provider@0.0.19
-
-## 1.0.10
-
-### Patch Changes
-
-- 4bd27a9: chore (ai/provider): refactor type validation
-- 845754b: fix (ai/provider): fix atob/btoa execution on cloudflare edge workers
-- Updated dependencies [4bd27a9]
- - @ai-sdk/provider@0.0.18
-
-## 1.0.9
-
-### Patch Changes
-
-- Updated dependencies [029af4c]
- - @ai-sdk/provider@0.0.17
-
-## 1.0.8
-
-### Patch Changes
-
-- Updated dependencies [d58517b]
- - @ai-sdk/provider@0.0.16
-
-## 1.0.7
-
-### Patch Changes
-
-- Updated dependencies [96aed25]
- - @ai-sdk/provider@0.0.15
-
-## 1.0.6
-
-### Patch Changes
-
-- 9614584: fix (ai/core): use Symbol.for
-- 0762a22: feat (ai/core): support zod transformers in generateObject & streamObject
-
-## 1.0.5
-
-### Patch Changes
-
-- a8d1c9e9: feat (ai/core): parallel image download
-- Updated dependencies [a8d1c9e9]
- - @ai-sdk/provider@0.0.14
-
-## 1.0.4
-
-### Patch Changes
-
-- 4f88248f: feat (core): support json schema
-
-## 1.0.3
-
-### Patch Changes
-
-- Updated dependencies
- - @ai-sdk/provider@0.0.13
-
-## 1.0.2
-
-### Patch Changes
-
-- Updated dependencies [b7290943]
- - @ai-sdk/provider@0.0.12
-
-## 1.0.1
-
-### Patch Changes
-
-- d481729f: fix (ai/provider-utils): generalize to Error (DomException not always available)
-
-## 1.0.0
-
-### Major Changes
-
-- 5edc6110: feat (provider-utils): change getRequestHeader() test helper to return Record (breaking change)
-
-### Patch Changes
-
-- 5edc6110: feat (provider-utils): add combineHeaders helper
-- Updated dependencies [5edc6110]
- - @ai-sdk/provider@0.0.11
-
-## 0.0.16
-
-### Patch Changes
-
-- 02f6a088: feat (provider-utils): add convertArrayToAsyncIterable test helper
-
-## 0.0.15
-
-### Patch Changes
-
-- 85712895: feat (@ai-sdk/provider-utils): add createJsonStreamResponseHandler
-- 85712895: chore (@ai-sdk/provider-utils): move test helper to provider utils
-
-## 0.0.14
-
-### Patch Changes
-
-- 7910ae84: feat (providers): support custom fetch implementations
-
-## 0.0.13
-
-### Patch Changes
-
-- Updated dependencies [102ca22f]
- - @ai-sdk/provider@0.0.10
-
-## 0.0.12
-
-### Patch Changes
-
-- 09295e2e: feat (@ai-sdk/provider-utils): add download helper
-- 043a5de2: fix (provider-utils): rename to isParsableJson
-- Updated dependencies [09295e2e]
- - @ai-sdk/provider@0.0.9
-
-## 0.0.11
-
-### Patch Changes
-
-- Updated dependencies [f39c0dd2]
- - @ai-sdk/provider@0.0.8
-
-## 0.0.10
-
-### Patch Changes
-
-- Updated dependencies [8e780288]
- - @ai-sdk/provider@0.0.7
-
-## 0.0.9
-
-### Patch Changes
-
-- 6a50ac4: feat (provider-utils): add loadSetting and convertAsyncGeneratorToReadableStream helpers
-- Updated dependencies [6a50ac4]
- - @ai-sdk/provider@0.0.6
-
-## 0.0.8
-
-### Patch Changes
-
-- Updated dependencies [0f6bc4e]
- - @ai-sdk/provider@0.0.5
-
-## 0.0.7
-
-### Patch Changes
-
-- Updated dependencies [325ca55]
- - @ai-sdk/provider@0.0.4
-
-## 0.0.6
-
-### Patch Changes
-
-- 276f22b: fix (ai/provider): improve request error handling
-
-## 0.0.5
-
-### Patch Changes
-
-- Updated dependencies [41d5736]
- - @ai-sdk/provider@0.0.3
-
-## 0.0.4
-
-### Patch Changes
-
-- 56ef84a: ai/core: fix abort handling in transformation stream
-
-## 0.0.3
-
-### Patch Changes
-
-- 25f3350: ai/core: add support for getting raw response headers.
-- Updated dependencies
- - @ai-sdk/provider@0.0.2
-
-## 0.0.2
-
-### Patch Changes
-
-- eb150a6: ai/core: remove scaling of setting values (breaking change). If you were using the temperature, frequency penalty, or presence penalty settings, you need to update the providers and adjust the setting values.
-- Updated dependencies [eb150a6]
- - @ai-sdk/provider@0.0.1
-
-## 0.0.1
-
-### Patch Changes
-
-- 7b8791d: Rename baseUrl to baseURL. Automatically remove trailing slashes.
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/README.md b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/README.md
deleted file mode 100644
index f7ee1685f..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# AI SDK - Provider Implementation Utilities
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/package.json b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/package.json
deleted file mode 100644
index a666da5df..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/package.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "name": "@ai-sdk/provider-utils",
- "version": "4.0.21",
- "license": "Apache-2.0",
- "sideEffects": false,
- "main": "./dist/index.js",
- "module": "./dist/index.mjs",
- "types": "./dist/index.d.ts",
- "source": "./src/index.ts",
- "files": [
- "dist/**/*",
- "src",
- "!src/**/*.test.ts",
- "!src/**/*.test-d.ts",
- "!src/**/__snapshots__",
- "!src/**/__fixtures__",
- "CHANGELOG.md",
- "README.md",
- "test.d.ts"
- ],
- "exports": {
- "./package.json": "./package.json",
- ".": {
- "types": "./dist/index.d.ts",
- "import": "./dist/index.mjs",
- "require": "./dist/index.js"
- },
- "./test": {
- "types": "./dist/test/index.d.ts",
- "import": "./dist/test/index.mjs",
- "module": "./dist/test/index.mjs",
- "require": "./dist/test/index.js"
- }
- },
- "dependencies": {
- "@standard-schema/spec": "^1.1.0",
- "eventsource-parser": "^3.0.6",
- "@ai-sdk/provider": "3.0.8"
- },
- "devDependencies": {
- "@types/node": "20.17.24",
- "msw": "2.7.0",
- "tsup": "^8",
- "typescript": "5.8.3",
- "zod": "3.25.76",
- "@vercel/ai-tsconfig": "0.0.0"
- },
- "peerDependencies": {
- "zod": "^3.25.76 || ^4.1.8"
- },
- "engines": {
- "node": ">=18"
- },
- "publishConfig": {
- "access": "public"
- },
- "homepage": "https://ai-sdk.dev/docs",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/vercel/ai.git"
- },
- "bugs": {
- "url": "https://github.com/vercel/ai/issues"
- },
- "keywords": [
- "ai"
- ],
- "scripts": {
- "build": "pnpm clean && tsup --tsconfig tsconfig.build.json",
- "build:watch": "pnpm clean && tsup --watch",
- "clean": "del-cli dist *.tsbuildinfo",
- "lint": "eslint \"./**/*.ts*\"",
- "type-check": "tsc --build",
- "prettier-check": "prettier --check \"./**/*.ts*\"",
- "test": "pnpm test:node && pnpm test:edge",
- "test:update": "pnpm test:node -u",
- "test:watch": "vitest --config vitest.node.config.js",
- "test:edge": "vitest --config vitest.edge.config.js --run",
- "test:node": "vitest --config vitest.node.config.js --run"
- }
-}
\ No newline at end of file
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/add-additional-properties-to-json-schema.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/add-additional-properties-to-json-schema.ts
deleted file mode 100644
index 2c259bdad..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/add-additional-properties-to-json-schema.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { JSONSchema7, JSONSchema7Definition } from '@ai-sdk/provider';
-
-/**
- * Recursively adds additionalProperties: false to the JSON schema. This is necessary because some providers (e.g. OpenAI) do not support additionalProperties: true.
- */
-export function addAdditionalPropertiesToJsonSchema(
- jsonSchema: JSONSchema7,
-): JSONSchema7 {
- if (
- jsonSchema.type === 'object' ||
- (Array.isArray(jsonSchema.type) && jsonSchema.type.includes('object'))
- ) {
- jsonSchema.additionalProperties = false;
- const { properties } = jsonSchema;
- if (properties != null) {
- for (const key of Object.keys(properties)) {
- properties[key] = visit(properties[key]);
- }
- }
- }
-
- if (jsonSchema.items != null) {
- jsonSchema.items = Array.isArray(jsonSchema.items)
- ? jsonSchema.items.map(visit)
- : visit(jsonSchema.items);
- }
-
- if (jsonSchema.anyOf != null) {
- jsonSchema.anyOf = jsonSchema.anyOf.map(visit);
- }
-
- if (jsonSchema.allOf != null) {
- jsonSchema.allOf = jsonSchema.allOf.map(visit);
- }
-
- if (jsonSchema.oneOf != null) {
- jsonSchema.oneOf = jsonSchema.oneOf.map(visit);
- }
-
- const { definitions } = jsonSchema;
- if (definitions != null) {
- for (const key of Object.keys(definitions)) {
- definitions[key] = visit(definitions[key]);
- }
- }
-
- return jsonSchema;
-}
-
-function visit(def: JSONSchema7Definition): JSONSchema7Definition {
- if (typeof def === 'boolean') return def;
- return addAdditionalPropertiesToJsonSchema(def);
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/combine-headers.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/combine-headers.ts
deleted file mode 100644
index 5f842268d..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/combine-headers.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export function combineHeaders(
- ...headers: Array | undefined>
-): Record {
- return headers.reduce(
- (combinedHeaders, currentHeaders) => ({
- ...combinedHeaders,
- ...(currentHeaders ?? {}),
- }),
- {},
- ) as Record;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/convert-async-iterator-to-readable-stream.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/convert-async-iterator-to-readable-stream.ts
deleted file mode 100644
index dd1121ca1..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/convert-async-iterator-to-readable-stream.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * Converts an AsyncIterator to a ReadableStream.
- *
- * @template T - The type of elements produced by the AsyncIterator.
- * @param { } iterator - The AsyncIterator to convert.
- * @returns {ReadableStream} - A ReadableStream that provides the same data as the AsyncIterator.
- */
-export function convertAsyncIteratorToReadableStream(
- iterator: AsyncIterator,
-): ReadableStream {
- let cancelled = false;
-
- return new ReadableStream({
- /**
- * Called when the consumer wants to pull more data from the stream.
- *
- * @param {ReadableStreamDefaultController} controller - The controller to enqueue data into the stream.
- * @returns {Promise}
- */
- async pull(controller) {
- if (cancelled) return;
- try {
- const { value, done } = await iterator.next();
- if (done) {
- controller.close();
- } else {
- controller.enqueue(value);
- }
- } catch (error) {
- controller.error(error);
- }
- },
- /**
- * Called when the consumer cancels the stream.
- */
- async cancel(reason?: unknown) {
- cancelled = true;
- if (iterator.return) {
- try {
- await iterator.return(reason);
- } catch {
- // intentionally ignore errors during cancellation
- }
- }
- },
- });
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/convert-image-model-file-to-data-uri.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/convert-image-model-file-to-data-uri.ts
deleted file mode 100644
index 5115fb739..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/convert-image-model-file-to-data-uri.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { ImageModelV3File } from '@ai-sdk/provider';
-import { convertUint8ArrayToBase64 } from './uint8-utils';
-
-/**
- * Convert an ImageModelV3File to a URL or data URI string.
- *
- * If the file is a URL, it returns the URL as-is.
- * If the file is base64 data, it returns a data URI with the base64 data.
- * If the file is a Uint8Array, it converts it to base64 and returns a data URI.
- */
-export function convertImageModelFileToDataUri(file: ImageModelV3File): string {
- if (file.type === 'url') return file.url;
-
- return `data:${file.mediaType};base64,${
- typeof file.data === 'string'
- ? file.data
- : convertUint8ArrayToBase64(file.data)
- }`;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/convert-to-form-data.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/convert-to-form-data.ts
deleted file mode 100644
index c2459ef93..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/convert-to-form-data.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * Converts an input object to FormData for multipart/form-data requests.
- *
- * Handles the following cases:
- * - `null` or `undefined` values are skipped
- * - Arrays with a single element are appended as a single value
- * - Arrays with multiple elements are appended with `[]` suffix (e.g., `image[]`)
- * unless `useArrayBrackets` is set to `false`
- * - All other values are appended directly
- *
- * @param input - The input object to convert. Use a generic type for type validation.
- * @param options - Optional configuration object.
- * @param options.useArrayBrackets - Whether to add `[]` suffix for multi-element arrays.
- * Defaults to `true`. Set to `false` for APIs that expect repeated keys without brackets.
- * @returns A FormData object containing the input values.
- *
- * @example
- * ```ts
- * type MyInput = {
- * model: string;
- * prompt: string;
- * images: Blob[];
- * };
- *
- * const formData = convertToFormData({
- * model: 'gpt-image-1',
- * prompt: 'A cat',
- * images: [blob1, blob2],
- * });
- * ```
- */
-export function convertToFormData>(
- input: T,
- options: { useArrayBrackets?: boolean } = {},
-): FormData {
- const { useArrayBrackets = true } = options;
- const formData = new FormData();
-
- for (const [key, value] of Object.entries(input)) {
- if (value == null) {
- continue;
- }
-
- if (Array.isArray(value)) {
- if (value.length === 1) {
- formData.append(key, value[0] as string | Blob);
- continue;
- }
-
- const arrayKey = useArrayBrackets ? `${key}[]` : key;
- for (const item of value) {
- formData.append(arrayKey, item as string | Blob);
- }
- continue;
- }
-
- formData.append(key, value as string | Blob);
- }
-
- return formData;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/create-tool-name-mapping.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/create-tool-name-mapping.ts
deleted file mode 100644
index 7116dd242..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/create-tool-name-mapping.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-import {
- LanguageModelV3FunctionTool,
- LanguageModelV3ProviderTool,
-} from '@ai-sdk/provider';
-
-/**
- * Interface for mapping between custom tool names and provider tool names.
- */
-export interface ToolNameMapping {
- /**
- * Maps a custom tool name (used by the client) to the provider's tool name.
- * If the custom tool name does not have a mapping, returns the input name.
- *
- * @param customToolName - The custom name of the tool defined by the client.
- * @returns The corresponding provider tool name, or the input name if not mapped.
- */
- toProviderToolName: (customToolName: string) => string;
-
- /**
- * Maps a provider tool name to the custom tool name used by the client.
- * If the provider tool name does not have a mapping, returns the input name.
- *
- * @param providerToolName - The name of the tool as understood by the provider.
- * @returns The corresponding custom tool name, or the input name if not mapped.
- */
- toCustomToolName: (providerToolName: string) => string;
-}
-
-/**
- * @param tools - Tools that were passed to the language model.
- * @param providerToolNames - Maps the provider tool ids to the provider tool names.
- */
-export function createToolNameMapping({
- tools = [],
- providerToolNames,
- resolveProviderToolName,
-}: {
- /**
- * Tools that were passed to the language model.
- */
- tools:
- | Array
- | undefined;
-
- /**
- * Maps the provider tool ids to the provider tool names.
- */
- providerToolNames: Record<`${string}.${string}`, string>;
-
- /**
- * Optional resolver for provider tool names that cannot be represented as
- * static id -> name mappings (e.g. dynamic provider names).
- */
- resolveProviderToolName?: (
- tool: LanguageModelV3ProviderTool,
- ) => string | undefined;
-}): ToolNameMapping {
- const customToolNameToProviderToolName: Record = {};
- const providerToolNameToCustomToolName: Record = {};
-
- for (const tool of tools) {
- if (tool.type === 'provider') {
- const providerToolName =
- resolveProviderToolName?.(tool) ??
- (tool.id in providerToolNames ? providerToolNames[tool.id] : undefined);
-
- if (providerToolName == null) {
- continue;
- }
-
- customToolNameToProviderToolName[tool.name] = providerToolName;
- providerToolNameToCustomToolName[providerToolName] = tool.name;
- }
- }
-
- return {
- toProviderToolName: (customToolName: string) =>
- customToolNameToProviderToolName[customToolName] ?? customToolName,
- toCustomToolName: (providerToolName: string) =>
- providerToolNameToCustomToolName[providerToolName] ?? providerToolName,
- };
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/delay.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/delay.ts
deleted file mode 100644
index a99ea5698..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/delay.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * Creates a Promise that resolves after a specified delay
- * @param delayInMs - The delay duration in milliseconds. If null or undefined, resolves immediately.
- * @param signal - Optional AbortSignal to cancel the delay
- * @returns A Promise that resolves after the specified delay
- * @throws {DOMException} When the signal is aborted
- */
-export async function delay(
- delayInMs?: number | null,
- options?: {
- abortSignal?: AbortSignal;
- },
-): Promise {
- if (delayInMs == null) {
- return Promise.resolve();
- }
-
- const signal = options?.abortSignal;
-
- return new Promise((resolve, reject) => {
- if (signal?.aborted) {
- reject(createAbortError());
- return;
- }
-
- const timeoutId = setTimeout(() => {
- cleanup();
- resolve();
- }, delayInMs);
-
- const cleanup = () => {
- clearTimeout(timeoutId);
- signal?.removeEventListener('abort', onAbort);
- };
-
- const onAbort = () => {
- cleanup();
- reject(createAbortError());
- };
-
- signal?.addEventListener('abort', onAbort);
- });
-}
-
-function createAbortError(): DOMException {
- return new DOMException('Delay was aborted', 'AbortError');
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/delayed-promise.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/delayed-promise.ts
deleted file mode 100644
index d25c8a2c5..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/delayed-promise.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * Delayed promise. It is only constructed once the value is accessed.
- * This is useful to avoid unhandled promise rejections when the promise is created
- * but not accessed.
- */
-export class DelayedPromise {
- private status:
- | { type: 'pending' }
- | { type: 'resolved'; value: T }
- | { type: 'rejected'; error: unknown } = { type: 'pending' };
- private _promise: Promise | undefined;
- private _resolve: undefined | ((value: T) => void) = undefined;
- private _reject: undefined | ((error: unknown) => void) = undefined;
-
- get promise(): Promise {
- if (this._promise) {
- return this._promise;
- }
-
- this._promise = new Promise((resolve, reject) => {
- if (this.status.type === 'resolved') {
- resolve(this.status.value);
- } else if (this.status.type === 'rejected') {
- reject(this.status.error);
- }
-
- this._resolve = resolve;
- this._reject = reject;
- });
-
- return this._promise;
- }
-
- resolve(value: T): void {
- this.status = { type: 'resolved', value };
-
- if (this._promise) {
- this._resolve?.(value);
- }
- }
-
- reject(error: unknown): void {
- this.status = { type: 'rejected', error };
-
- if (this._promise) {
- this._reject?.(error);
- }
- }
-
- isResolved(): boolean {
- return this.status.type === 'resolved';
- }
-
- isRejected(): boolean {
- return this.status.type === 'rejected';
- }
-
- isPending(): boolean {
- return this.status.type === 'pending';
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/download-blob.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/download-blob.ts
deleted file mode 100644
index 56fdbc31f..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/download-blob.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { DownloadError } from './download-error';
-import {
- readResponseWithSizeLimit,
- DEFAULT_MAX_DOWNLOAD_SIZE,
-} from './read-response-with-size-limit';
-import { validateDownloadUrl } from './validate-download-url';
-
-/**
- * Download a file from a URL and return it as a Blob.
- *
- * @param url - The URL to download from.
- * @param options - Optional settings for the download.
- * @param options.maxBytes - Maximum allowed download size in bytes. Defaults to 100 MiB.
- * @param options.abortSignal - An optional abort signal to cancel the download.
- * @returns A Promise that resolves to the downloaded Blob.
- *
- * @throws DownloadError if the download fails or exceeds maxBytes.
- */
-export async function downloadBlob(
- url: string,
- options?: { maxBytes?: number; abortSignal?: AbortSignal },
-): Promise {
- validateDownloadUrl(url);
- try {
- const response = await fetch(url, {
- signal: options?.abortSignal,
- });
-
- // Validate final URL after redirects to prevent SSRF via open redirect
- if (response.redirected) {
- validateDownloadUrl(response.url);
- }
-
- if (!response.ok) {
- throw new DownloadError({
- url,
- statusCode: response.status,
- statusText: response.statusText,
- });
- }
-
- const data = await readResponseWithSizeLimit({
- response,
- url,
- maxBytes: options?.maxBytes ?? DEFAULT_MAX_DOWNLOAD_SIZE,
- });
-
- const contentType = response.headers.get('content-type') ?? undefined;
- return new Blob([data], contentType ? { type: contentType } : undefined);
- } catch (error) {
- if (DownloadError.isInstance(error)) {
- throw error;
- }
-
- throw new DownloadError({ url, cause: error });
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/download-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/download-error.ts
deleted file mode 100644
index 455e5b377..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/download-error.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { AISDKError } from '@ai-sdk/provider';
-
-const name = 'AI_DownloadError';
-const marker = `vercel.ai.error.${name}`;
-const symbol = Symbol.for(marker);
-
-export class DownloadError extends AISDKError {
- private readonly [symbol] = true; // used in isInstance
-
- readonly url: string;
- readonly statusCode?: number;
- readonly statusText?: string;
-
- constructor({
- url,
- statusCode,
- statusText,
- cause,
- message = cause == null
- ? `Failed to download ${url}: ${statusCode} ${statusText}`
- : `Failed to download ${url}: ${cause}`,
- }: {
- url: string;
- statusCode?: number;
- statusText?: string;
- message?: string;
- cause?: unknown;
- }) {
- super({ name, message, cause });
-
- this.url = url;
- this.statusCode = statusCode;
- this.statusText = statusText;
- }
-
- static isInstance(error: unknown): error is DownloadError {
- return AISDKError.hasMarker(error, marker);
- }
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/extract-response-headers.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/extract-response-headers.ts
deleted file mode 100644
index 4056ce2f5..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/extract-response-headers.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * Extracts the headers from a response object and returns them as a key-value object.
- *
- * @param response - The response object to extract headers from.
- * @returns The headers as a key-value object.
- */
-export function extractResponseHeaders(response: Response) {
- return Object.fromEntries([...response.headers]);
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/fetch-function.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/fetch-function.ts
deleted file mode 100644
index f7882f903..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/fetch-function.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * Fetch function type (standardizes the version of fetch used).
- */
-export type FetchFunction = typeof globalThis.fetch;
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/generate-id.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/generate-id.ts
deleted file mode 100644
index 32a8a53be..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/generate-id.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { InvalidArgumentError } from '@ai-sdk/provider';
-
-/**
- * Creates an ID generator.
- * The total length of the ID is the sum of the prefix, separator, and random part length.
- * Not cryptographically secure.
- *
- * @param alphabet - The alphabet to use for the ID. Default: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.
- * @param prefix - The prefix of the ID to generate. Optional.
- * @param separator - The separator between the prefix and the random part of the ID. Default: '-'.
- * @param size - The size of the random part of the ID to generate. Default: 16.
- */
-export const createIdGenerator = ({
- prefix,
- size = 16,
- alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
- separator = '-',
-}: {
- prefix?: string;
- separator?: string;
- size?: number;
- alphabet?: string;
-} = {}): IdGenerator => {
- const generator = () => {
- const alphabetLength = alphabet.length;
- const chars = new Array(size);
- for (let i = 0; i < size; i++) {
- chars[i] = alphabet[(Math.random() * alphabetLength) | 0];
- }
- return chars.join('');
- };
-
- if (prefix == null) {
- return generator;
- }
-
- // check that the prefix is not part of the alphabet (otherwise prefix checking can fail randomly)
- if (alphabet.includes(separator)) {
- throw new InvalidArgumentError({
- argument: 'separator',
- message: `The separator "${separator}" must not be part of the alphabet "${alphabet}".`,
- });
- }
-
- return () => `${prefix}${separator}${generator()}`;
-};
-
-/**
- * A function that generates an ID.
- */
-export type IdGenerator = () => string;
-
-/**
- * Generates a 16-character random string to use for IDs.
- * Not cryptographically secure.
- */
-export const generateId = createIdGenerator();
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/get-error-message.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/get-error-message.ts
deleted file mode 100644
index 62c29e58a..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/get-error-message.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-export function getErrorMessage(error: unknown | undefined) {
- if (error == null) {
- return 'unknown error';
- }
-
- if (typeof error === 'string') {
- return error;
- }
-
- if (error instanceof Error) {
- return error.message;
- }
-
- return JSON.stringify(error);
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/get-from-api.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/get-from-api.ts
deleted file mode 100644
index 0a786dd06..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/get-from-api.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-import { APICallError } from '@ai-sdk/provider';
-import { extractResponseHeaders } from './extract-response-headers';
-import { FetchFunction } from './fetch-function';
-import { handleFetchError } from './handle-fetch-error';
-import { isAbortError } from './is-abort-error';
-import { ResponseHandler } from './response-handler';
-import { getRuntimeEnvironmentUserAgent } from './get-runtime-environment-user-agent';
-import { withUserAgentSuffix } from './with-user-agent-suffix';
-import { VERSION } from './version';
-
-// use function to allow for mocking in tests:
-const getOriginalFetch = () => globalThis.fetch;
-
-export const getFromApi = async ({
- url,
- headers = {},
- successfulResponseHandler,
- failedResponseHandler,
- abortSignal,
- fetch = getOriginalFetch(),
-}: {
- url: string;
- headers?: Record;
- failedResponseHandler: ResponseHandler;
- successfulResponseHandler: ResponseHandler;
- abortSignal?: AbortSignal;
- fetch?: FetchFunction;
-}) => {
- try {
- const response = await fetch(url, {
- method: 'GET',
- headers: withUserAgentSuffix(
- headers,
- `ai-sdk/provider-utils/${VERSION}`,
- getRuntimeEnvironmentUserAgent(),
- ),
- signal: abortSignal,
- });
-
- const responseHeaders = extractResponseHeaders(response);
-
- if (!response.ok) {
- let errorInformation: {
- value: Error;
- responseHeaders?: Record | undefined;
- };
-
- try {
- errorInformation = await failedResponseHandler({
- response,
- url,
- requestBodyValues: {},
- });
- } catch (error) {
- if (isAbortError(error) || APICallError.isInstance(error)) {
- throw error;
- }
-
- throw new APICallError({
- message: 'Failed to process error response',
- cause: error,
- statusCode: response.status,
- url,
- responseHeaders,
- requestBodyValues: {},
- });
- }
-
- throw errorInformation.value;
- }
-
- try {
- return await successfulResponseHandler({
- response,
- url,
- requestBodyValues: {},
- });
- } catch (error) {
- if (error instanceof Error) {
- if (isAbortError(error) || APICallError.isInstance(error)) {
- throw error;
- }
- }
-
- throw new APICallError({
- message: 'Failed to process successful response',
- cause: error,
- statusCode: response.status,
- url,
- responseHeaders,
- requestBodyValues: {},
- });
- }
- } catch (error) {
- throw handleFetchError({ error, url, requestBodyValues: {} });
- }
-};
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/get-runtime-environment-user-agent.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/get-runtime-environment-user-agent.ts
deleted file mode 100644
index f553f7353..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/get-runtime-environment-user-agent.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-export function getRuntimeEnvironmentUserAgent(
- globalThisAny: any = globalThis as any,
-): string {
- // Browsers
- if (globalThisAny.window) {
- return `runtime/browser`;
- }
-
- // Cloudflare Workers / Deno / Bun / Node.js >= 21.1
- if (globalThisAny.navigator?.userAgent) {
- return `runtime/${globalThisAny.navigator.userAgent.toLowerCase()}`;
- }
-
- // Nodes.js < 21.1
- if (globalThisAny.process?.versions?.node) {
- return `runtime/node.js/${globalThisAny.process.version.substring(0)}`;
- }
-
- if (globalThisAny.EdgeRuntime) {
- return `runtime/vercel-edge`;
- }
-
- return 'runtime/unknown';
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/handle-fetch-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/handle-fetch-error.ts
deleted file mode 100644
index d9774ab6b..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/handle-fetch-error.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import { APICallError } from '@ai-sdk/provider';
-import { isAbortError } from './is-abort-error';
-
-const FETCH_FAILED_ERROR_MESSAGES = ['fetch failed', 'failed to fetch'];
-
-const BUN_ERROR_CODES = [
- 'ConnectionRefused',
- 'ConnectionClosed',
- 'FailedToOpenSocket',
- 'ECONNRESET',
- 'ECONNREFUSED',
- 'ETIMEDOUT',
- 'EPIPE',
-];
-
-function isBunNetworkError(error: unknown): error is Error & { code?: string } {
- if (!(error instanceof Error)) {
- return false;
- }
-
- const code = (error as any).code;
- if (typeof code === 'string' && BUN_ERROR_CODES.includes(code)) {
- return true;
- }
-
- return false;
-}
-
-export function handleFetchError({
- error,
- url,
- requestBodyValues,
-}: {
- error: unknown;
- url: string;
- requestBodyValues: unknown;
-}) {
- if (isAbortError(error)) {
- return error;
- }
-
- // unwrap original error when fetch failed (for easier debugging):
- if (
- error instanceof TypeError &&
- FETCH_FAILED_ERROR_MESSAGES.includes(error.message.toLowerCase())
- ) {
- const cause = (error as any).cause;
-
- if (cause != null) {
- // Failed to connect to server:
- return new APICallError({
- message: `Cannot connect to API: ${cause.message}`,
- cause,
- url,
- requestBodyValues,
- isRetryable: true, // retry when network error
- });
- }
- }
-
- if (isBunNetworkError(error)) {
- return new APICallError({
- message: `Cannot connect to API: ${error.message}`,
- cause: error,
- url,
- requestBodyValues,
- isRetryable: true,
- });
- }
-
- return error;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/index.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/index.ts
deleted file mode 100644
index dc1d45d76..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/index.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-export * from './combine-headers';
-export { convertAsyncIteratorToReadableStream } from './convert-async-iterator-to-readable-stream';
-export {
- createToolNameMapping,
- type ToolNameMapping,
-} from './create-tool-name-mapping';
-export * from './delay';
-export { DelayedPromise } from './delayed-promise';
-export * from './extract-response-headers';
-export { convertImageModelFileToDataUri } from './convert-image-model-file-to-data-uri';
-export { convertToFormData } from './convert-to-form-data';
-export { downloadBlob } from './download-blob';
-export { DownloadError } from './download-error';
-export {
- readResponseWithSizeLimit,
- DEFAULT_MAX_DOWNLOAD_SIZE,
-} from './read-response-with-size-limit';
-export * from './fetch-function';
-export { createIdGenerator, generateId, type IdGenerator } from './generate-id';
-export * from './get-error-message';
-export * from './get-from-api';
-export { getRuntimeEnvironmentUserAgent } from './get-runtime-environment-user-agent';
-export { injectJsonInstructionIntoMessages } from './inject-json-instruction';
-export * from './is-abort-error';
-export { isNonNullable } from './is-non-nullable';
-export { isUrlSupported } from './is-url-supported';
-export * from './load-api-key';
-export { loadOptionalSetting } from './load-optional-setting';
-export { loadSetting } from './load-setting';
-export { type MaybePromiseLike } from './maybe-promise-like';
-export { mediaTypeToExtension } from './media-type-to-extension';
-export { normalizeHeaders } from './normalize-headers';
-export * from './parse-json';
-export { parseJsonEventStream } from './parse-json-event-stream';
-export { parseProviderOptions } from './parse-provider-options';
-export * from './post-to-api';
-export {
- createProviderToolFactory,
- createProviderToolFactoryWithOutputSchema,
- type ProviderToolFactory,
- type ProviderToolFactoryWithOutputSchema,
-} from './provider-tool-factory';
-export * from './remove-undefined-entries';
-export * from './resolve';
-export * from './response-handler';
-export {
- asSchema,
- jsonSchema,
- lazySchema,
- zodSchema,
- type FlexibleSchema,
- type InferSchema,
- type LazySchema,
- type Schema,
- type ValidationResult,
-} from './schema';
-export { stripFileExtension } from './strip-file-extension';
-export * from './uint8-utils';
-export { validateDownloadUrl } from './validate-download-url';
-export * from './validate-types';
-export { VERSION } from './version';
-export { withUserAgentSuffix } from './with-user-agent-suffix';
-export * from './without-trailing-slash';
-
-// folder re-exports
-export * from './types';
-
-// external re-exports
-export type * from '@standard-schema/spec';
-export {
- EventSourceParserStream,
- type EventSourceMessage,
-} from 'eventsource-parser/stream';
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/inject-json-instruction.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/inject-json-instruction.ts
deleted file mode 100644
index f307b7595..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/inject-json-instruction.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import {
- JSONSchema7,
- LanguageModelV3Message,
- LanguageModelV3Prompt,
-} from '@ai-sdk/provider';
-
-const DEFAULT_SCHEMA_PREFIX = 'JSON schema:';
-const DEFAULT_SCHEMA_SUFFIX =
- 'You MUST answer with a JSON object that matches the JSON schema above.';
-const DEFAULT_GENERIC_SUFFIX = 'You MUST answer with JSON.';
-
-export function injectJsonInstruction({
- prompt,
- schema,
- schemaPrefix = schema != null ? DEFAULT_SCHEMA_PREFIX : undefined,
- schemaSuffix = schema != null
- ? DEFAULT_SCHEMA_SUFFIX
- : DEFAULT_GENERIC_SUFFIX,
-}: {
- prompt?: string;
- schema?: JSONSchema7;
- schemaPrefix?: string;
- schemaSuffix?: string;
-}): string {
- return [
- prompt != null && prompt.length > 0 ? prompt : undefined,
- prompt != null && prompt.length > 0 ? '' : undefined, // add a newline if prompt is not null
- schemaPrefix,
- schema != null ? JSON.stringify(schema) : undefined,
- schemaSuffix,
- ]
- .filter(line => line != null)
- .join('\n');
-}
-
-export function injectJsonInstructionIntoMessages({
- messages,
- schema,
- schemaPrefix,
- schemaSuffix,
-}: {
- messages: LanguageModelV3Prompt;
- schema?: JSONSchema7;
- schemaPrefix?: string;
- schemaSuffix?: string;
-}): LanguageModelV3Prompt {
- const systemMessage: LanguageModelV3Message =
- messages[0]?.role === 'system'
- ? { ...messages[0] }
- : { role: 'system', content: '' };
-
- systemMessage.content = injectJsonInstruction({
- prompt: systemMessage.content,
- schema,
- schemaPrefix,
- schemaSuffix,
- });
-
- return [
- systemMessage,
- ...(messages[0]?.role === 'system' ? messages.slice(1) : messages),
- ];
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/is-abort-error.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/is-abort-error.ts
deleted file mode 100644
index 195c6e473..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/is-abort-error.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export function isAbortError(error: unknown): error is Error {
- return (
- (error instanceof Error || error instanceof DOMException) &&
- (error.name === 'AbortError' ||
- error.name === 'ResponseAborted' || // Next.js
- error.name === 'TimeoutError')
- );
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/is-async-iterable.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/is-async-iterable.ts
deleted file mode 100644
index 1bd9ce1d3..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/is-async-iterable.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function isAsyncIterable(obj: any): obj is AsyncIterable {
- return obj != null && typeof obj[Symbol.asyncIterator] === 'function';
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/is-non-nullable.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/is-non-nullable.ts
deleted file mode 100644
index 39963ded3..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/is-non-nullable.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * Type guard that checks whether a value is not `null` or `undefined`.
- *
- * @template T - The type of the value to check.
- * @param value - The value to check.
- * @returns `true` if the value is neither `null` nor `undefined`, otherwise `false`.
- */
-export function isNonNullable(
- value: T | undefined | null,
-): value is NonNullable {
- return value != null;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/is-url-supported.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/is-url-supported.ts
deleted file mode 100644
index 94db5e773..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/is-url-supported.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Checks if the given URL is supported natively by the model.
- *
- * @param mediaType - The media type of the URL. Case-sensitive.
- * @param url - The URL to check.
- * @param supportedUrls - A record where keys are case-sensitive media types (or '*')
- * and values are arrays of RegExp patterns for URLs.
- *
- * @returns `true` if the URL matches a pattern under the specific media type
- * or the wildcard '*', `false` otherwise.
- */
-export function isUrlSupported({
- mediaType,
- url,
- supportedUrls,
-}: {
- mediaType: string;
- url: string;
- supportedUrls: Record;
-}): boolean {
- // standardize media type and url to lower case
- url = url.toLowerCase();
- mediaType = mediaType.toLowerCase();
-
- return (
- Object.entries(supportedUrls)
- // standardize supported url map into lowercase prefixes:
- .map(([key, value]) => {
- const mediaType = key.toLowerCase();
- return mediaType === '*' || mediaType === '*/*'
- ? { mediaTypePrefix: '', regexes: value }
- : { mediaTypePrefix: mediaType.replace(/\*/, ''), regexes: value };
- })
- // gather all regexp pattern from matched media type prefixes:
- .filter(({ mediaTypePrefix }) => mediaType.startsWith(mediaTypePrefix))
- .flatMap(({ regexes }) => regexes)
- // check if any pattern matches the url:
- .some(pattern => pattern.test(url))
- );
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/load-api-key.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/load-api-key.ts
deleted file mode 100644
index 44d9c9967..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/load-api-key.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { LoadAPIKeyError } from '@ai-sdk/provider';
-
-export function loadApiKey({
- apiKey,
- environmentVariableName,
- apiKeyParameterName = 'apiKey',
- description,
-}: {
- apiKey: string | undefined;
- environmentVariableName: string;
- apiKeyParameterName?: string;
- description: string;
-}): string {
- if (typeof apiKey === 'string') {
- return apiKey;
- }
-
- if (apiKey != null) {
- throw new LoadAPIKeyError({
- message: `${description} API key must be a string.`,
- });
- }
-
- if (typeof process === 'undefined') {
- throw new LoadAPIKeyError({
- message: `${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter. Environment variables is not supported in this environment.`,
- });
- }
-
- apiKey = process.env[environmentVariableName];
-
- if (apiKey == null) {
- throw new LoadAPIKeyError({
- message: `${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter or the ${environmentVariableName} environment variable.`,
- });
- }
-
- if (typeof apiKey !== 'string') {
- throw new LoadAPIKeyError({
- message: `${description} API key must be a string. The value of the ${environmentVariableName} environment variable is not a string.`,
- });
- }
-
- return apiKey;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/load-optional-setting.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/load-optional-setting.ts
deleted file mode 100644
index bce841c02..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/load-optional-setting.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * Loads an optional `string` setting from the environment or a parameter.
- *
- * @param settingValue - The setting value.
- * @param environmentVariableName - The environment variable name.
- * @returns The setting value.
- */
-export function loadOptionalSetting({
- settingValue,
- environmentVariableName,
-}: {
- settingValue: string | undefined;
- environmentVariableName: string;
-}): string | undefined {
- if (typeof settingValue === 'string') {
- return settingValue;
- }
-
- if (settingValue != null || typeof process === 'undefined') {
- return undefined;
- }
-
- settingValue = process.env[environmentVariableName];
-
- if (settingValue == null || typeof settingValue !== 'string') {
- return undefined;
- }
-
- return settingValue;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/load-setting.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/load-setting.ts
deleted file mode 100644
index 2042fcb89..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/load-setting.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import { LoadSettingError } from '@ai-sdk/provider';
-
-/**
- * Loads a `string` setting from the environment or a parameter.
- *
- * @param settingValue - The setting value.
- * @param environmentVariableName - The environment variable name.
- * @param settingName - The setting name.
- * @param description - The description of the setting.
- * @returns The setting value.
- */
-export function loadSetting({
- settingValue,
- environmentVariableName,
- settingName,
- description,
-}: {
- settingValue: string | undefined;
- environmentVariableName: string;
- settingName: string;
- description: string;
-}): string {
- if (typeof settingValue === 'string') {
- return settingValue;
- }
-
- if (settingValue != null) {
- throw new LoadSettingError({
- message: `${description} setting must be a string.`,
- });
- }
-
- if (typeof process === 'undefined') {
- throw new LoadSettingError({
- message:
- `${description} setting is missing. ` +
- `Pass it using the '${settingName}' parameter. ` +
- `Environment variables is not supported in this environment.`,
- });
- }
-
- settingValue = process.env[environmentVariableName];
-
- if (settingValue == null) {
- throw new LoadSettingError({
- message:
- `${description} setting is missing. ` +
- `Pass it using the '${settingName}' parameter ` +
- `or the ${environmentVariableName} environment variable.`,
- });
- }
-
- if (typeof settingValue !== 'string') {
- throw new LoadSettingError({
- message:
- `${description} setting must be a string. ` +
- `The value of the ${environmentVariableName} environment variable is not a string.`,
- });
- }
-
- return settingValue;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/maybe-promise-like.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/maybe-promise-like.ts
deleted file mode 100644
index f3dc1c577..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/maybe-promise-like.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export type MaybePromiseLike =
- | T // Raw value
- | PromiseLike; // Promise of value
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/media-type-to-extension.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/media-type-to-extension.ts
deleted file mode 100644
index 40b475390..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/media-type-to-extension.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * Maps a media type to its corresponding file extension.
- * It was originally introduced to set a filename for audio file uploads
- * in https://github.com/vercel/ai/pull/8159.
- *
- * @param mediaType The media type to map.
- * @returns The corresponding file extension
- * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types
- */
-export function mediaTypeToExtension(mediaType: string) {
- const [_type, subtype = ''] = mediaType.toLowerCase().split('/');
-
- return (
- {
- mpeg: 'mp3',
- 'x-wav': 'wav',
- opus: 'ogg',
- mp4: 'm4a',
- 'x-m4a': 'm4a',
- }[subtype] ?? subtype
- );
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/normalize-headers.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/normalize-headers.ts
deleted file mode 100644
index ade0a3431..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/normalize-headers.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Normalizes different header inputs into a plain record with lower-case keys.
- * Entries with `undefined` or `null` values are removed.
- *
- * @param headers - Input headers (`Headers`, tuples array, plain record) to normalize.
- * @returns A record containing the normalized header entries.
- */
-export function normalizeHeaders(
- headers:
- | HeadersInit
- | Record
- | Array<[string, string | undefined]>
- | undefined,
-): Record {
- if (headers == null) {
- return {};
- }
-
- const normalized: Record = {};
-
- if (headers instanceof Headers) {
- headers.forEach((value, key) => {
- normalized[key.toLowerCase()] = value;
- });
- } else {
- if (!Array.isArray(headers)) {
- headers = Object.entries(headers);
- }
-
- for (const [key, value] of headers) {
- if (value != null) {
- normalized[key.toLowerCase()] = value;
- }
- }
- }
-
- return normalized;
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/parse-json-event-stream.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/parse-json-event-stream.ts
deleted file mode 100644
index bd23542b9..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/parse-json-event-stream.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import {
- EventSourceMessage,
- EventSourceParserStream,
-} from 'eventsource-parser/stream';
-import { ParseResult, safeParseJSON } from './parse-json';
-import { FlexibleSchema } from './schema';
-
-/**
- * Parses a JSON event stream into a stream of parsed JSON objects.
- */
-export function parseJsonEventStream({
- stream,
- schema,
-}: {
- stream: ReadableStream;
- schema: FlexibleSchema;
-}): ReadableStream> {
- return stream
- .pipeThrough(new TextDecoderStream())
- .pipeThrough(new EventSourceParserStream())
- .pipeThrough(
- new TransformStream>({
- async transform({ data }, controller) {
- // ignore the 'DONE' event that e.g. OpenAI sends:
- if (data === '[DONE]') {
- return;
- }
-
- controller.enqueue(await safeParseJSON({ text: data, schema }));
- },
- }),
- );
-}
diff --git a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/parse-json.ts b/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/parse-json.ts
deleted file mode 100644
index f6bcc5369..000000000
--- a/examples/vercel-ai-sdk-pr/node-headroom-compression/node_modules/@ai-sdk/provider-utils/src/parse-json.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-import {
- JSONParseError,
- JSONValue,
- TypeValidationError,
-} from '@ai-sdk/provider';
-import { secureJsonParse } from './secure-json-parse';
-import { safeValidateTypes, validateTypes } from './validate-types';
-import { FlexibleSchema } from './schema';
-
-/**
- * Parses a JSON string into an unknown object.
- *
- * @param text - The JSON string to parse.
- * @returns {JSONValue} - The parsed JSON object.
- */
-export async function parseJSON(options: {
- text: string;
- schema?: undefined;
-}): Promise;
-/**
- * Parses a JSON string into a strongly-typed object using the provided schema.
- *
- * @template T - The type of the object to parse the JSON into.
- * @param {string} text - The JSON string to parse.
- * @param {Validator} schema - The schema to use for parsing the JSON.
- * @returns {Promise} - The parsed object.
- */
-export async function parseJSON(options: {
- text: string;
- schema: FlexibleSchema;
-}): Promise;
-export async function parseJSON({
- text,
- schema,
-}: {
- text: string;
- schema?: FlexibleSchema