feat: add Vercel AI Gateway adapter - #1093
Conversation
…nd image adapters
📝 WalkthroughWalkthroughAdds ChangesVercel AI Gateway adapter
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Application
participant VercelGatewayTextFactory
participant VercelGatewayTextAdapter
participant VercelAIGateway
Application->>VercelGatewayTextFactory: Select Responses or Chat API
VercelGatewayTextFactory->>VercelGatewayTextAdapter: Create configured adapter
VercelGatewayTextAdapter->>VercelAIGateway: Send OpenAI-compatible request
VercelAIGateway-->>Application: Return streamed text events
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
View your CI Pipeline Execution ↗ for commit 7a403ff
☁️ Nx Cloud last updated this comment at |
@tanstack/ai
@tanstack/ai-acp
@tanstack/ai-angular
@tanstack/ai-anthropic
@tanstack/ai-bedrock
@tanstack/ai-byteplus
@tanstack/ai-claude-code
@tanstack/ai-client
@tanstack/ai-code-mode
@tanstack/ai-code-mode-skills
@tanstack/ai-codex
@tanstack/ai-cohere
@tanstack/ai-devtools-core
@tanstack/ai-durable-stream
@tanstack/ai-elevenlabs
@tanstack/ai-event-client
@tanstack/ai-fal
@tanstack/ai-gemini
@tanstack/ai-grok
@tanstack/ai-grok-build
@tanstack/ai-groq
@tanstack/ai-isolate-cloudflare
@tanstack/ai-isolate-daytona
@tanstack/ai-isolate-node
@tanstack/ai-isolate-quickjs
@tanstack/ai-isolate-quickjs-bun
@tanstack/ai-mcp
@tanstack/ai-memory
@tanstack/ai-mistral
@tanstack/ai-ollama
@tanstack/ai-openai
@tanstack/ai-opencode
@tanstack/ai-openrouter
@tanstack/ai-persistence
@tanstack/ai-preact
@tanstack/ai-react
@tanstack/ai-react-ui
@tanstack/ai-sandbox
@tanstack/ai-sandbox-cloudflare
@tanstack/ai-sandbox-daytona
@tanstack/ai-sandbox-docker
@tanstack/ai-sandbox-local-process
@tanstack/ai-sandbox-sprites
@tanstack/ai-sandbox-vercel
@tanstack/ai-solid
@tanstack/ai-solid-ui
@tanstack/ai-svelte
@tanstack/ai-utils
@tanstack/ai-vercel-gateway
@tanstack/ai-vue
@tanstack/ai-vue-ui
@tanstack/openai-base
@tanstack/preact-ai-devtools
@tanstack/react-ai-devtools
@tanstack/solid-ai-devtools
commit: |
There was a problem hiding this comment.
Actionable comments posted: 9
🧹 Nitpick comments (1)
packages/ai-vercel-gateway/tests/client.test.ts (1)
1-77: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMove unit tests alongside their source modules.
packages/ai-vercel-gateway/tests/client.test.ts#L1-L77: Move this test next topackages/ai-vercel-gateway/src/utils/client.ts.packages/ai-vercel-gateway/tests/map-gateway-options.test.ts#L1-L28: Move this test next topackages/ai-vercel-gateway/src/utils/map-gateway-options.ts.As per coding guidelines: “Unit tests in
*.test.tsfiles alongside source”.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ai-vercel-gateway/tests/client.test.ts` around lines 1 - 77, Move the tests from packages/ai-vercel-gateway/tests/client.test.ts (lines 1-77) alongside the source module packages/ai-vercel-gateway/src/utils/client.ts, preserving the getVercelGatewayApiKeyFromEnv and withVercelGatewayDefaults coverage. Also move packages/ai-vercel-gateway/tests/map-gateway-options.test.ts (lines 1-28) alongside packages/ai-vercel-gateway/src/utils/map-gateway-options.ts; update any relative imports as needed.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/adapters/vercel-gateway.md`:
- Around line 59-60: Update the model IDs in the examples: in
docs/adapters/vercel-gateway.md ranges 39-41, 59-60, 117-119, 132-140, 156, 172,
and 184, replace openai/gpt-5.5 with openai/gpt-5.6-sol and openai/gpt-image-1
with openai/gpt-image-2 where present. In docs/embeddings.md ranges 37 and
53-60, retain openai/text-embedding-3-small without changes; also preserve
anthropic/claude-opus-5 in the gateway examples.
In `@packages/ai-vercel-gateway/package.json`:
- Around line 23-32: Add the adapter barrel at src/adapters/index.ts and update
the package exports map with an ./adapters entry, pointing types and import to
the generated ESM declaration and JavaScript files under dist/esm/adapters.
Preserve the existing root and ./tools exports.
In `@packages/ai-vercel-gateway/src/text/text-provider-options.ts`:
- Around line 1-16: Update the VercelGatewayRoutingOptions interface: change
byok to Record<string, Array<Record<string, unknown>>> and providerTimeouts to
an object with an optional byok Record<string, number>. Add type-level coverage
verifying Vertex or Bedrock credential objects are accepted and
providerTimeouts.byok is correctly typed.
In `@packages/ai-vercel-gateway/src/tools/function-tool.ts`:
- Around line 20-28: Update the inputSchema initialization in the function-tool
flow to copy tool.inputSchema before adding a default properties object,
preserving the caller-owned schema and supporting frozen inputs. Keep the
existing fallback schema behavior, and add coverage verifying the original
inputSchema remains unchanged.
In `@packages/ai-vercel-gateway/src/utils/map-gateway-options.ts`:
- Around line 3-14: Update mapGatewayModelOptions to preserve and merge any
existing providerOptions object when gateway is present, adding gateway without
discarding provider-specific settings such as openai or anthropic. Keep the
current behavior unchanged when modelOptions or gateway is absent, and add a
regression test covering providerOptions alongside gateway.
In `@packages/ai-vercel-gateway/vite.config.ts`:
- Around line 31-35: Add the adapters public entrypoint by creating
src/adapters/index.ts, including it in the entry list passed to
tanstackViteConfig, and exposing the resulting ./adapters subpath in the package
exports. Ensure consumers can import the provider adapters through the required
subpath.
In `@scripts/convert-vercel-gateway-models.ts`:
- Around line 39-50: Update classifyModel and the chat-catalog generation logic
to derive categories and input modalities from authoritative model capability
metadata rather than identifier heuristics. Exclude audio-only and other
non-chat model families from VERCEL_GATEWAY_CHAT_MODELS, and do not mark every
chat model as image-capable. When capabilities are unavailable, exclude the
model from the chat catalog and use the conservative readonly text modality for
retained text models.
In `@testing/e2e/package.json`:
- Line 40: Update the `@tanstack/ai-vercel-gateway` dependency in package.json
from workspace:* to workspace:^, preserving the existing internal workspace
dependency and version reference.
In `@testing/e2e/src/lib/feature-support.ts`:
- Line 279: Update the documented image-gen provider count in the README to 4 so
it matches the four entries in the image-gen set used by
providersFor('feature').
---
Nitpick comments:
In `@packages/ai-vercel-gateway/tests/client.test.ts`:
- Around line 1-77: Move the tests from
packages/ai-vercel-gateway/tests/client.test.ts (lines 1-77) alongside the
source module packages/ai-vercel-gateway/src/utils/client.ts, preserving the
getVercelGatewayApiKeyFromEnv and withVercelGatewayDefaults coverage. Also move
packages/ai-vercel-gateway/tests/map-gateway-options.test.ts (lines 1-28)
alongside packages/ai-vercel-gateway/src/utils/map-gateway-options.ts; update
any relative imports as needed.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e8336888-bcb6-4e18-8bba-589dbf65ebda
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (51)
.changeset/ai-vercel-gateway-adapter.md.github/workflows/sync-models.ymldocs/adapters/openai-compatible.mddocs/adapters/vercel-gateway.mddocs/comparison/vercel-ai-sdk.mddocs/config.jsondocs/embeddings.mdpackage.jsonpackages/ai-vercel-gateway/LICENSEpackages/ai-vercel-gateway/README.mdpackages/ai-vercel-gateway/package.jsonpackages/ai-vercel-gateway/src/adapters/embedding.tspackages/ai-vercel-gateway/src/adapters/image.tspackages/ai-vercel-gateway/src/adapters/responses-text.tspackages/ai-vercel-gateway/src/adapters/summarize.tspackages/ai-vercel-gateway/src/adapters/text.tspackages/ai-vercel-gateway/src/embedding/embedding-provider-options.tspackages/ai-vercel-gateway/src/image/image-provider-options.tspackages/ai-vercel-gateway/src/index.tspackages/ai-vercel-gateway/src/message-types.tspackages/ai-vercel-gateway/src/model-meta.tspackages/ai-vercel-gateway/src/text/responses-provider-options.tspackages/ai-vercel-gateway/src/text/text-provider-options.tspackages/ai-vercel-gateway/src/tools/function-tool.tspackages/ai-vercel-gateway/src/tools/index.tspackages/ai-vercel-gateway/src/tools/tool-converter.tspackages/ai-vercel-gateway/src/utils/client.tspackages/ai-vercel-gateway/src/utils/map-gateway-options.tspackages/ai-vercel-gateway/tests/client.test.tspackages/ai-vercel-gateway/tests/embedding-adapter.test.tspackages/ai-vercel-gateway/tests/image-adapter.test.tspackages/ai-vercel-gateway/tests/map-gateway-options.test.tspackages/ai-vercel-gateway/tests/responses-text-adapter.test.tspackages/ai-vercel-gateway/tests/summarize-adapter.test.tspackages/ai-vercel-gateway/tests/text-adapter.test.tspackages/ai-vercel-gateway/tsconfig.jsonpackages/ai-vercel-gateway/vite.config.tspackages/ai-vercel-gateway/vitest.config.tsscripts/convert-vercel-gateway-models.tsscripts/fetch-vercel-gateway-models.tsscripts/vercel-gateway.models.jsonscripts/vercel-gateway.models.tstesting/e2e/README.mdtesting/e2e/package.jsontesting/e2e/src/lib/feature-support.tstesting/e2e/src/lib/media-providers.tstesting/e2e/src/lib/providers.tstesting/e2e/src/lib/types.tstesting/e2e/src/routes/api.embedding.tstesting/e2e/src/routes/api.summarize.tstesting/e2e/tests/test-matrix.ts
| adapter: vercelGatewayText("anthropic/claude-opus-5"), | ||
| messages, |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
meta="$(fd -a -t f '^model-meta\.ts$' packages/ai-vercel-gateway/src | head -n 1)"
test -n "$meta"
rg -n -C 4 'VERCEL_GATEWAY_|claude-|gpt-|text-embedding' "$meta"
rg -n 'anthropic/claude-opus-5|openai/gpt-5\.5|openai/gpt-image-1|openai/text-embedding-3-small' \
docs/adapters/vercel-gateway.md docs/embeddings.mdRepository: TanStack/ai
Length of output: 5631
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "== model metadata files =="
fd -a -t f 'model-meta\.ts$' packages | sort
echo "== adapter model metadata references =="
rg -n -C 3 'MODEL|model|latest|embedding|image|summar|claude-opus|gpt-5\.|text-embedding|gpt-image' \
packages/*/src/**/model-meta.ts packages/*/src/model-meta.ts 2>/dev/null || true
echo "== relevant documentation =="
sed -n '1,210p' docs/adapters/vercel-gateway.md
sed -n '1,90p' docs/embeddings.mdRepository: TanStack/ai
Length of output: 50368
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
meta="$(fd -a -t f '^model-meta\.ts$' packages/ai-vercel-gateway/src | head -n 1)"
test -n "$meta"
echo "== catalog declarations =="
rg -n '^export const VERCEL_GATEWAY_|^export type VercelGateway|^[[:space:]]*\x27(anthropic|openai)/' "$meta" \
| awk '
/export const VERCEL_GATEWAY_/ { section=$0 }
/'\''(anthropic|openai)\// { print FNR ":" section "\n" $0 }
'
echo "== relevant catalog ranges =="
sed -n '35,60p' "$meta"
sed -n '145,185p' "$meta"
sed -n '240,315p' "$meta"
echo "== adapter-specific model validation and defaults =="
rg -n -C 4 'VERCEL_GATEWAY_(CHAT|EMBEDDING|IMAGE)_MODELS|VercelGateway(Chat|Embedding|Image)Model|modelId|model' \
packages/ai-vercel-gateway/src \
-g '*.ts' | head -n 500Repository: TanStack/ai
Length of output: 50367
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "== catalog generator =="
fd -a -t f 'convert-vercel-gateway-models\.ts$|vercel.*gateway.*model' scripts packages/ai-vercel-gateway
rg -n -C 5 'sort|CHAT_MODELS|EMBEDDING_MODELS|IMAGE_MODELS|supports|output|input|model' \
scripts/convert-vercel-gateway-models.ts 2>/dev/null || true
echo "== exact relevant metadata =="
meta="packages/ai-vercel-gateway/src/model-meta.ts"
rg -n -C 2 \
"id: '(anthropic/claude-(opus|sonnet)-5|openai/(gpt-5\.5|gpt-5\.6|gpt-image-1|gpt-image-1\.5|gpt-image-2|text-embedding-3-(small|large)))'" \
"$meta"
echo "== all affected documentation occurrences =="
rg -n -C 1 \
'anthropic/claude-opus-5|openai/gpt-5\.5|openai/text-embedding-3-small|openai/gpt-image-1' \
docs/adapters/vercel-gateway.md docs/embeddings.mdRepository: TanStack/ai
Length of output: 4323
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "== source catalog shape =="
python3 - <<'PY'
import json
from pathlib import Path
for name in ("scripts/vercel-gateway.models.json",):
path = Path(name)
data = json.loads(path.read_text())
print(name, type(data).__name__, len(data) if hasattr(data, "__len__") else "")
rows = data if isinstance(data, list) else data.get("models", data.get("data", []))
if rows:
print("keys:", sorted(rows[0]))
wanted = {
"anthropic/claude-opus-5",
"anthropic/claude-opus-5-fast",
"anthropic/claude-sonnet-5",
"openai/gpt-5.5",
"openai/gpt-5.5-pro",
"openai/gpt-5.6-luna",
"openai/gpt-5.6-sol",
"openai/gpt-5.6-terra",
"openai/text-embedding-3-small",
"openai/text-embedding-3-large",
"openai/gpt-image-1",
"openai/gpt-image-1.5",
"openai/gpt-image-2",
}
for row in rows:
if row.get("id") in wanted:
print(json.dumps(row, sort_keys=True))
PY
echo "== generator source =="
sed -n '1,120p' scripts/convert-vercel-gateway-models.tsRepository: TanStack/ai
Length of output: 21767
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
import json
from collections import defaultdict
from datetime import datetime, timezone
from pathlib import Path
rows = json.loads(Path("scripts/vercel-gateway.models.json").read_text())
affected = {
"anthropic/claude-opus-5",
"openai/gpt-5.5",
"openai/text-embedding-3-small",
"openai/gpt-image-1",
}
groups = defaultdict(list)
for row in rows:
model_type = row.get("type", "")
if model_type in {"language", "chat", "embedding", "embeddings", "image"}:
groups[(row.get("owned_by"), model_type)].append(row)
for affected_id in sorted(affected):
row = next(r for r in rows if r["id"] == affected_id)
matching = [
r for (owner, model_type), models in groups.items()
if owner == row.get("owned_by")
for r in models
if r["id"] == affected_id
]
print(f"\n{affected_id}")
for r in matching:
print(" type:", r.get("type"), "released:",
datetime.fromtimestamp(r["released"], timezone.utc).isoformat()
if r.get("released") else None)
candidates = [
r for (owner, model_type), models in groups.items()
if owner == row.get("owned_by") and model_type == row.get("type")
for r in models
]
max_released = max((r.get("released", 0) for r in candidates), default=0)
print(" newest candidates:")
for r in sorted(
[r for r in candidates if r.get("released", 0) == max_released],
key=lambda r: r["id"],
):
print(" ", r["id"], "-", r.get("description", "")[:110])
print("\nAll affected documentation IDs:")
for path in ("docs/adapters/vercel-gateway.md", "docs/embeddings.md"):
for number, line in enumerate(Path(path).read_text().splitlines(), 1):
if any(model_id in line for model_id in affected):
print(f"{path}:{number}:{line.strip()}")
PYRepository: TanStack/ai
Length of output: 2687
Update superseded OpenAI model IDs
Replace openai/gpt-5.5 with openai/gpt-5.6-sol in the Responses and routing examples. Replace openai/gpt-image-1 with openai/gpt-image-2. Keep anthropic/claude-opus-5 and openai/text-embedding-3-small; both remain current supported examples.
📍 Affects 2 files
docs/adapters/vercel-gateway.md#L59-L60(this comment)docs/adapters/vercel-gateway.md#L39-L41docs/adapters/vercel-gateway.md#L117-L119docs/adapters/vercel-gateway.md#L132-L140docs/adapters/vercel-gateway.md#L156-L156docs/adapters/vercel-gateway.md#L172-L172docs/adapters/vercel-gateway.md#L184-L184docs/embeddings.md#L37-L37docs/embeddings.md#L53-L60
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/adapters/vercel-gateway.md` around lines 59 - 60, Update the model IDs
in the examples: in docs/adapters/vercel-gateway.md ranges 39-41, 59-60,
117-119, 132-140, 156, 172, and 184, replace openai/gpt-5.5 with
openai/gpt-5.6-sol and openai/gpt-image-1 with openai/gpt-image-2 where present.
In docs/embeddings.md ranges 37 and 53-60, retain openai/text-embedding-3-small
without changes; also preserve anthropic/claude-opus-5 in the gateway examples.
Sources: Coding guidelines, Learnings
| "exports": { | ||
| ".": { | ||
| "types": "./dist/esm/index.d.ts", | ||
| "import": "./dist/esm/index.js" | ||
| }, | ||
| "./tools": { | ||
| "types": "./dist/esm/tools/index.d.ts", | ||
| "import": "./dist/esm/tools/index.js" | ||
| } | ||
| }, |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Export the adapter barrel from ./adapters.
The new provider adapters are not available through the required /adapters subpath. Add src/adapters/index.ts and an ./adapters export-map entry with its generated ESM and type paths.
As per coding guidelines, “Export from /adapters subpath.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ai-vercel-gateway/package.json` around lines 23 - 32, Add the
adapter barrel at src/adapters/index.ts and update the package exports map with
an ./adapters entry, pointing types and import to the generated ESM declaration
and JavaScript files under dist/esm/adapters. Preserve the existing root and
./tools exports.
Source: Coding guidelines
| export interface VercelGatewayRoutingOptions { | ||
| order?: Array<string> | ||
| only?: Array<string> | ||
| sort?: 'cost' | 'ttft' | 'tps' | ||
| models?: Array<string> | ||
| caching?: 'auto' | ||
| byok?: Record<string, Array<{ apiKey: string }>> | ||
| zeroDataRetention?: boolean | ||
| disallowPromptTraining?: boolean | ||
| user?: string | ||
| tags?: Array<string> | ||
| serviceTier?: string | ||
| providerTimeouts?: Record<string, number> | ||
| quotaEntityId?: string | ||
| has?: Array<string> | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- target file ---'
cat -n packages/ai-vercel-gateway/src/text/text-provider-options.ts
printf '%s\n' '--- related symbols and routing fields ---'
rg -n --glob '!node_modules' 'VercelGatewayRoutingOptions|providerTimeouts|zeroDataRetention|byok' packages/ai-vercel-gateway packages | head -250
printf '%s\n' '--- package metadata and local documentation ---'
fd -i 'package.json|README|CHANGELOG|.*test.*|.*spec.*' packages/ai-vercel-gateway | sortRepository: TanStack/ai
Length of output: 5329
🌐 Web query:
Vercel AI Gateway provider timeouts providerTimeouts byok BYOK credential shapes Vertex AI Bedrock official documentation
💡 Result:
Vercel AI Gateway supports per-provider timeouts specifically for Bring Your Own Key (BYOK) credentials [1][2]. This feature enables fast failover by allowing the gateway to abort a request and switch to a different provider if the current one fails to respond within a specified duration [1][2]. Configuration Details: - The timeouts are set using the providerTimeouts property within the providerOptions.gateway object of your request [1][2]. - Values are defined in milliseconds [1][2]. - You can apply these timeouts per provider (e.g., anthropic, bedrock, vertex) [1][2]. Example implementation: const result = streamText({ model: 'anthropic/claude-sonnet-4.6', prompt, providerOptions: { gateway: { order: ['anthropic', 'bedrock', 'vertex'], providerTimeouts: { byok: { anthropic: 10000, // 10 seconds bedrock: 15000, // 15 seconds }, }, }, }, }); When a timeout occurs, the AI Gateway includes metadata in the response (e.g., providerTimeout and configuredTimeoutMs) to help you audit the attempt [1]. Note that some providers do not support stream cancellation, meaning you may still be billed for requests that timed out [2]. BYOK credentials can be configured either at the team level in the Vercel dashboard or passed dynamically on a per-request basis within the byok field [3][4].
Citations:
- 1: https://vercel.com/docs/ai-gateway/models-and-providers/provider-timeouts
- 2: https://vercel.com/changelog/provider-level-custom-timeouts-available-on-ai-gateway
- 3: https://vercel.com/docs/ai-gateway/authentication-and-byok/byok
- 4: https://vercel.com/docs/ai-gateway/authentication-and-byok/byok.md
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- gateway option mapping ---'
cat -n packages/ai-vercel-gateway/src/utils/map-gateway-options.ts
printf '%s\n' '--- existing gateway tests ---'
rg -n -C 5 'gateway|byok|providerTimeouts|type|satisfies' packages/ai-vercel-gateway/tests packages/ai-vercel-gateway/README.md
printf '%s\n' '--- official BYOK documentation excerpts ---'
for url in \
https://vercel.com/docs/ai-gateway/authentication-and-byok/byok \
https://vercel.com/docs/ai-gateway/authentication-and-byok/byok.md \
https://vercel.com/docs/ai-gateway/models-and-providers/provider-timeouts; do
echo "URL: $url"
curl -L --fail --silent --show-error "$url" | \
tr '\n' ' ' | \
sed 's/<[^>]*>/ /g; s/"/"/g; s/&`#x27`;/'"'"'/g; s/&/\&/g' | \
grep -oE '.{0,300}(providerTimeouts|byok|Vertex|Bedrock|apiKey|credential).{0,500}' | head -20 || true
doneRepository: TanStack/ai
Length of output: 50369
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- repository dependency versions ---'
cat packages/ai-vercel-gateway/package.json
rg -n 'ai-sdk/gateway|GatewayProviderOptions|providerTimeouts' pnpm-lock.yaml package.json packages docs --glob '*.{json,md,ts,tsx,yml,yaml}' | head -120
printf '%s\n' '--- concise official timeout documentation ---'
curl -L --fail --silent --show-error https://vercel.com/docs/ai-gateway/models-and-providers/provider-timeouts.md |
rg -n -C 3 'providerTimeouts|byok|milliseconds|timeout' | head -100
printf '%s\n' '--- published gateway type references ---'
for url in \
https://unpkg.com/@ai-sdk/gateway/package.json \
https://unpkg.com/@ai-sdk/gateway/dist/index.d.ts \
https://unpkg.com/@ai-sdk/gateway@latest/dist/index.d.ts; do
echo "URL: $url"
curl -L --fail --silent --show-error "$url" | \
rg -n -C 4 'GatewayProviderOptions|providerTimeouts|byok' | head -100 || true
doneRepository: TanStack/ai
Length of output: 12238
Correct the Gateway routing option types.
Use byok?: Record<string, Array<Record<string, unknown>>> and providerTimeouts?: { byok?: Record<string, number> }. Add type-level coverage for Vertex or Bedrock credentials and providerTimeouts.byok.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ai-vercel-gateway/src/text/text-provider-options.ts` around lines 1
- 16, Update the VercelGatewayRoutingOptions interface: change byok to
Record<string, Array<Record<string, unknown>>> and providerTimeouts to an object
with an optional byok Record<string, number>. Add type-level coverage verifying
Vertex or Bedrock credential objects are accepted and providerTimeouts.byok is
correctly typed.
| const inputSchema = (tool.inputSchema ?? { | ||
| type: 'object', | ||
| properties: {}, | ||
| required: [], | ||
| }) as JSONSchema | ||
|
|
||
| if (inputSchema.type === 'object' && !inputSchema.properties) { | ||
| inputSchema.properties = {} | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
file='packages/ai-vercel-gateway/src/tools/function-tool.ts'
printf '%s\n' '--- candidate files ---'
git ls-files 'packages/ai-vercel-gateway/src/**' | sed -n '1,120p'
printf '%s\n' '--- outline ---'
if command -v ast-grep >/dev/null 2>&1; then
ast-grep outline "$file" || true
fi
printf '%s\n' '--- target source ---'
cat -n "$file"
printf '%s\n' '--- related symbols and usages ---'
rg -n --glob '*.{ts,tsx}' 'function-tool|inputSchema|JSONSchema' packages/ai-vercel-gateway packages/ai | sed -n '1,240p'Repository: TanStack/ai
Length of output: 25964
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- converter implementation ---'
rg -n --glob '*.{ts,tsx}' 'makeStructuredOutputCompatible' packages | sed -n '1,120p'
printf '%s\n' '--- tool converter and package tests ---'
cat -n packages/ai-vercel-gateway/src/tools/tool-converter.ts
cat -n packages/ai-vercel-gateway/src/tools/index.ts
find packages/ai-vercel-gateway -maxdepth 3 -type f \( -iname '*test*' -o -iname '*spec*' \) -print | sort
printf '%s\n' '--- JSONSchema definition ---'
sed -n '70,105p' packages/ai/src/types.ts
printf '%s\n' '--- workspace/package metadata ---'
rg -n --glob 'package.json' --glob 'pnpm-workspace.yaml' --glob 'pnpm-lock.yaml' \
'ai-vercel-gateway|openai-base|test|typecheck' package.json packages/ai-vercel-gateway/package.json packages/openai-base/package.json pnpm-workspace.yaml 2>/dev/null | sed -n '1,220p'Repository: TanStack/ai
Length of output: 15509
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- openai-base schema converter ---'
cat -n packages/openai-base/src/utils/schema-converter.ts
printf '%s\n' '--- openai-base function-tool converter ---'
cat -n packages/openai-base/src/tools/function-tool.ts
printf '%s\n' '--- relevant converter tests ---'
sed -n '1,220p' packages/openai-base/tests/schema-converter.test.ts
sed -n '220,380p' packages/openai-base/tests/schema-converter.test.ts
printf '%s\n' '--- Vercel Gateway test conventions ---'
sed -n '1,220p' packages/ai-vercel-gateway/tests/text-adapter.test.tsRepository: TanStack/ai
Length of output: 30824
🏁 Script executed:
#!/bin/bash
set -eu
node - <<'JS'
'use strict'
function convert(tool) {
const inputSchema = (tool.inputSchema ?? {
type: 'object',
properties: {},
required: [],
})
if (inputSchema.type === 'object' && !inputSchema.properties) {
inputSchema.properties = {}
}
// Model the imported converter's relevant contract: it returns a fresh tree.
const jsonSchema = { ...inputSchema }
jsonSchema.additionalProperties = false
return jsonSchema
}
const schema = Object.freeze({ type: 'object' })
let threw = false
try {
convert({ inputSchema: schema })
} catch (error) {
threw = error instanceof TypeError
}
const reusable = { type: 'object' }
convert({ inputSchema: reusable })
console.log(JSON.stringify({
frozenSchemaThrowsTypeError: threw,
reusedSchemaPropertiesAfterConversion: reusable.properties,
undefinedSchemaIsLocal: convert({}).properties,
}))
JSRepository: TanStack/ai
Length of output: 257
Avoid mutating tool.inputSchema.
When tool.inputSchema is an object schema without properties, line 27 changes the caller-owned object and throws for a frozen schema. Create a copy before adding properties. Add coverage that the input schema remains unchanged.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ai-vercel-gateway/src/tools/function-tool.ts` around lines 20 - 28,
Update the inputSchema initialization in the function-tool flow to copy
tool.inputSchema before adding a default properties object, preserving the
caller-owned schema and supporting frozen inputs. Keep the existing fallback
schema behavior, and add coverage verifying the original inputSchema remains
unchanged.
| export function mapGatewayModelOptions( | ||
| modelOptions: | ||
| | (Record<string, unknown> & { gateway?: VercelGatewayRoutingOptions }) | ||
| | undefined, | ||
| ): Record<string, unknown> { | ||
| if (!modelOptions) return {} | ||
| const { gateway, ...rest } = modelOptions | ||
| if (gateway === undefined) return rest | ||
| return { | ||
| ...rest, | ||
| providerOptions: { gateway }, | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- target file ---'
ast-grep outline packages/ai-vercel-gateway/src/utils/map-gateway-options.ts
cat -n packages/ai-vercel-gateway/src/utils/map-gateway-options.ts
printf '%s\n' '--- related symbols and tests ---'
rg -n --glob '!node_modules' 'mapGatewayModelOptions|VercelGatewayRoutingOptions|providerOptions' packages/ai-vercel-gateway
printf '%s\n' '--- package files ---'
git ls-files packages/ai-vercel-gateway | sed -n '1,160p'Repository: TanStack/ai
Length of output: 6623
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- utility tests ---'
cat -n packages/ai-vercel-gateway/tests/map-gateway-options.test.ts
printf '%s\n' '--- provider option types ---'
cat -n packages/ai-vercel-gateway/src/text/text-provider-options.ts
cat -n packages/ai-vercel-gateway/src/text/responses-provider-options.ts
cat -n packages/ai-vercel-gateway/src/image/image-provider-options.ts
cat -n packages/ai-vercel-gateway/src/embedding/embedding-provider-options.ts
printf '%s\n' '--- adapter call sites ---'
cat -n packages/ai-vercel-gateway/src/adapters/text.ts | sed -n '45,75p'
cat -n packages/ai-vercel-gateway/src/adapters/responses-text.ts | sed -n '50,80p'
cat -n packages/ai-vercel-gateway/src/adapters/image.ts | sed -n '60,90p'
cat -n packages/ai-vercel-gateway/src/adapters/embedding.ts | sed -n '40,70p'Repository: TanStack/ai
Length of output: 7907
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- existing adapter assertions ---'
cat -n packages/ai-vercel-gateway/tests/text-adapter.test.ts | sed -n '115,160p'
cat -n packages/ai-vercel-gateway/tests/responses-text-adapter.test.ts | sed -n '85,130p'
cat -n packages/ai-vercel-gateway/tests/image-adapter.test.ts | sed -n '1,45p'
cat -n packages/ai-vercel-gateway/tests/embedding-adapter.test.ts | sed -n '1,45p'
printf '%s\n' '--- shared modelOptions mapping ---'
rg -n --glob '*.ts' --glob '*.tsx' 'mapOptionsToRequest|modelOptions.*providerOptions|providerOptions.*modelOptions' packages | sed -n '1,220p'
printf '%s\n' '--- option declarations and providerOptions usage ---'
rg -n --glob '*.ts' --glob '*.tsx' 'interface .*Options|type .*Options|providerOptions' packages/ai-openai packages/ai-core packages | sed -n '1,260p'Repository: TanStack/ai
Length of output: 39000
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- chat-completions base mapper ---'
cat -n packages/openai-base/src/adapters/chat-completions-text.ts | sed -n '1090,1165p'
printf '%s\n' '--- responses base mapper ---'
cat -n packages/openai-base/src/adapters/responses-text.ts | sed -n '1620,1695p'
printf '%s\n' '--- OpenAI adapter mapper ---'
cat -n packages/ai-openai/src/adapters/text.ts | sed -n '90,145p'
printf '%s\n' '--- generic model option types ---'
rg -n --glob '*.ts' 'export (interface|type).*TextOptions|modelOptions\??:' packages/ai packages/openai-base | sed -n '1,180p'
printf '%s\n' '--- behavioral probe ---'
python3 - <<'PY'
def map_gateway_model_options(model_options):
if not model_options:
return {}
gateway = model_options.get("gateway")
rest = {k: v for k, v in model_options.items() if k != "gateway"}
if gateway is None:
return rest
return {**rest, "providerOptions": {"gateway": gateway}}
value = {
"temperature": 0.2,
"providerOptions": {"openai": {"reasoningEffort": "low"}},
"gateway": {"order": ["anthropic"]},
}
print(map_gateway_model_options(value))
PYRepository: TanStack/ai
Length of output: 23579
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- package documentation and examples ---'
rg -n -C 4 --glob 'README.md' --glob '*.md' 'providerOptions|gateway|modelOptions' packages/ai-vercel-gateway README.md docs 2>/dev/null | sed -n '1,220p'
printf '%s\n' '--- Vercel Gateway package metadata ---'
cat -n packages/ai-vercel-gateway/package.json
printf '%s\n' '--- all Vercel Gateway option examples ---'
rg -n -C 5 --glob '*.ts' --glob '*.tsx' --glob '*.md' 'gateway:|providerOptions:' packages/ai-vercel-gateway | sed -n '1,240p'Repository: TanStack/ai
Length of output: 27020
🌐 Web query:
Vercel AI Gateway provider options gateway providerOptions combine provider-specific options
💡 Result:
In Vercel AI Gateway, providerOptions is a parameter used to configure both Gateway-specific routing behavior and provider-specific settings within the same request [1][2]. To combine these, you structure the providerOptions object using namespaced keys [2]. Gateway-specific configurations (such as routing, fallbacks, and caching) must be placed under the gateway key, while configurations intended for a specific AI model provider (such as Anthropic or OpenAI) must be placed under that provider's own name as the key (e.g., anthropic, openai) [3][2]. Key implementation details include: 1. Gateway-specific options: Use the gateway key to control how the Gateway manages the request [4][2]. Common options include: - order: An array specifying the sequence in which providers should be attempted [5][6]. - only: An array restricting routing to a specific subset of providers [5][6]. - sort: Ranks providers by metrics like performance or cost (e.g., tps, ttft) [5][3]. - models: Defines a list of fallback models to try if the primary model fails [6][7]. - caching: Enables strategies like 'auto' for providers requiring explicit markers [8][6]. 2. Provider-specific options: Use the actual provider name (e.g., anthropic, openai) as the key [3][2]. The AI Gateway automatically forwards these options to the target provider [2]. Example usage combining both: import { generateText } from 'ai'; import type { GatewayProviderOptions } from '@ai-sdk/gateway'; import type { AnthropicLanguageModelOptions } from '@ai-sdk/anthropic'; const result = await generateText({ model: 'anthropic/claude-sonnet-4.6', prompt: 'Explain quantum computing', providerOptions: { // Gateway-specific: control routing and fallbacks gateway: { order: ['vertex', 'anthropic'], } satisfies GatewayProviderOptions, // Provider-specific: enable provider-specific features anthropic: { thinking: { type: 'enabled', budgetTokens: 12000 }, } satisfies AnthropicLanguageModelOptions, }, }); When using these options, only the settings matching the active provider are applied to the request [2]. If you are using the OpenAI or Anthropic SDKs directly, you may need to use a comment like // @ts-expect-error if the types do not explicitly include providerOptions [7].
Citations:
- 1: https://vercel.com/docs/ai-gateway/sdks-and-apis/openai-chat-completions/advanced
- 2: https://ai-sdk.dev/docs/foundations/provider-options
- 3: https://ai-sdk.dev/v7/providers/ai-sdk-providers/ai-gateway
- 4: https://ai-sdk.dev/providers/ai-sdk-providers/ai-gateway
- 5: https://vercel.com/docs/ai-gateway/models-and-providers/provider-filtering-and-ordering
- 6: https://vercel.com/docs/ai-gateway/sdks-and-apis/openresponses/provider-options
- 7: https://vercel.com/docs/ai-gateway/models-and-providers/model-fallbacks.md
- 8: https://vercel.com/docs/ai-gateway/models-and-providers/provider-options
Preserve existing providerOptions.
When modelOptions contains both providerOptions and gateway, merge the existing object before adding gateway. The current assignment discards provider-specific settings such as openai or anthropic. Add a regression test for both fields.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ai-vercel-gateway/src/utils/map-gateway-options.ts` around lines 3 -
14, Update mapGatewayModelOptions to preserve and merge any existing
providerOptions object when gateway is present, adding gateway without
discarding provider-specific settings such as openai or anthropic. Keep the
current behavior unchanged when modelOptions or gateway is absent, and add a
regression test covering providerOptions alongside gateway.
| tanstackViteConfig({ | ||
| entry: ['./src/index.ts', './src/tools/index.ts'], | ||
| srcDir: './src', | ||
| cjs: false, | ||
| }), |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '/"exports"/,/^[[:space:]]*}/p' packages/ai-vercel-gateway/package.json
rg -n -C 3 'entry:|src/adapters' packages/ai-vercel-gateway/vite.config.ts
fd -a '^index\.ts$' packages/ai-vercel-gateway/src/adaptersRepository: TanStack/ai
Length of output: 440
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- package manifest ---'
cat -n packages/ai-vercel-gateway/package.json
printf '%s\n' '--- source files ---'
git ls-files packages/ai-vercel-gateway/src
printf '%s\n' '--- adapter-related symbols and imports ---'
rg -n -i 'adapter|create.*Text|provider' packages/ai-vercel-gateway/src packages/ai-vercel-gateway/package.json packages/ai-vercel-gateway/vite.config.ts || true
printf '%s\n' '--- package configuration ---'
cat -n packages/ai-vercel-gateway/vite.config.tsRepository: TanStack/ai
Length of output: 17809
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import json
from pathlib import Path
pkg_dir = Path("packages/ai-vercel-gateway")
manifest = json.loads((pkg_dir / "package.json").read_text())
vite = (pkg_dir / "vite.config.ts").read_text()
entries = ["./src/index.ts", "./src/tools/index.ts", "./src/adapters/index.ts"]
print("exports.adapters:", "./adapters" in manifest.get("exports", {}))
print("adapters.index.exists:", (pkg_dir / "src/adapters/index.ts").exists())
print("configured.entries:", all(entry in vite for entry in entries))
print("adapter.source.files:", sorted(str(path.relative_to(pkg_dir)) for path in (pkg_dir / "src/adapters").glob("*.ts")))
PY
printf '%s\n' '--- comparable adapter exports ---'
rg -n -A 12 '"\./adapters"' packages/*/package.json | head -80Repository: TanStack/ai
Length of output: 1214
Publish the required /adapters subpath.
The package contains separate provider adapters, but it has no src/adapters/index.ts, build entry, or ./adapters export. Add these so consumers can import the adapters from the required subpath.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ai-vercel-gateway/vite.config.ts` around lines 31 - 35, Add the
adapters public entrypoint by creating src/adapters/index.ts, including it in
the entry list passed to tanstackViteConfig, and exposing the resulting
./adapters subpath in the package exports. Ensure consumers can import the
provider adapters through the required subpath.
Source: Coding guidelines
| function classifyModel(model: VercelGatewayCatalogModel): CatalogKind { | ||
| const type = typeof model.type === 'string' ? model.type.toLowerCase() : '' | ||
| if (type in TYPE_ALIASES) { | ||
| return TYPE_ALIASES[type]! | ||
| } | ||
|
|
||
| const id = model.id | ||
| if (/embed/i.test(id)) return 'embedding' | ||
| if (/image|dall-e|imagen|flux|seedream/i.test(id)) return 'image' | ||
| if (/rerank/i.test(id)) return 'reranking' | ||
| if (/video|veo|sora|seedance/i.test(id)) return 'video' | ||
| return 'language' |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Generate categories and modalities from authoritative model capabilities.
The converter includes audio-only models in the chat catalog. The generated output includes fish-audio/transcribe-1, openai/tts-1, and openai/whisper-1 in VERCEL_GATEWAY_CHAT_MODELS. The Chat Completions adapter can then send unsupported requests for those models.
The converter also declares image input for every chat model. This permits image prompts for text-only models such as openai/gpt-3.5-turbo.
Use catalog capability metadata for model classification and input modalities. If capability metadata is unavailable, exclude unknown models from the chat catalog and use a conservative readonly ['text'] modality.
Based on learnings, exclude non-chat model families from chat catalogs to keep text adapters text-only.
Also applies to: 144-150
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/convert-vercel-gateway-models.ts` around lines 39 - 50, Update
classifyModel and the chat-catalog generation logic to derive categories and
input modalities from authoritative model capability metadata rather than
identifier heuristics. Exclude audio-only and other non-chat model families from
VERCEL_GATEWAY_CHAT_MODELS, and do not mark every chat model as image-capable.
When capabilities are unavailable, exclude the model from the chat catalog and
use the conservative readonly text modality for retained text models.
Source: Learnings
| "@tanstack/ai-react": "workspace:*", | ||
| "@tanstack/ai-react-ui": "workspace:*", | ||
| "@tanstack/ai-sandbox": "workspace:*", | ||
| "@tanstack/ai-vercel-gateway": "workspace:*", |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use workspace:^ for the internal package.
Line 40 uses "workspace:*". Change it to "workspace:^".
Proposed fix
- "`@tanstack/ai-vercel-gateway`": "workspace:*",
+ "`@tanstack/ai-vercel-gateway`": "workspace:^",As per coding guidelines, internal package dependencies must use the workspace: protocol with workspace:^.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "@tanstack/ai-vercel-gateway": "workspace:*", | |
| "@tanstack/ai-vercel-gateway": "workspace:^", |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@testing/e2e/package.json` at line 40, Update the `@tanstack/ai-vercel-gateway`
dependency in package.json from workspace:* to workspace:^, preserving the
existing internal workspace dependency and version reference.
Source: Coding guidelines
| 'image-gen': new Set(['openai', 'grok', 'byteplus']), | ||
| // vercel-gateway uses POST /v1/images/generations, the same path aimock | ||
| // already mocks for openai. Drop this entry if the first run has no fixture. | ||
| 'image-gen': new Set(['openai', 'grok', 'byteplus', 'vercel-gateway']), |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct the documented image-gen count.
The final image-gen set contains four providers: openai, grok, byteplus, and vercel-gateway. testing/e2e/README.md Line 34 still reports seven providers.
Update the README count to 4, or add the missing providers to this set if seven is intended.
Based on the providersFor('feature') contract documented in testing/e2e/README.md and the changed matrix in this file.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@testing/e2e/src/lib/feature-support.ts` at line 279, Update the documented
image-gen provider count in the README to 4 so it matches the four entries in
the image-gen set used by providersFor('feature').
… types
Merge Responses into vercelGatewayText via { api }. Make Responses the default.
Generate per-model modelOptions and input modalities from the catalog.
Type gateway.models and gateway.order/only from the catalog.
Set the package version to 0.0.1 so trusted publishing can bump it to 0.1.0.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
packages/ai-vercel-gateway/tests/model-meta.test.ts (1)
12-49: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winType tests depend on volatile catalog ids.
The assertions hard-code
alibaba/qwen-3-14b,openai/gpt-5,alibaba/qwen3-vl-instruct, andalibaba/qwen3-235b-a22b-thinking. The dailysync-models.ymljob regeneratesmodel-meta.tsfromGET /v1/models. If Vercel removes any of these ids or changes theirsupported_parameters, these type tests fail in an unrelated automated pull request.Consider deriving the assertions from the catalog instead. For example, assert that every value in
VercelGatewayModelInputModalitiesByNamestarts with'text', and keep one id-specific case as a smoke test.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ai-vercel-gateway/tests/model-meta.test.ts` around lines 12 - 49, The type tests in the per-model provider options and input modalities suites rely too heavily on volatile catalog IDs. Replace broad ID-specific assertions with catalog-derived type checks, such as verifying every modality tuple begins with “text” and preserving only one representative ID-specific smoke test for modality or option behavior; keep the existing expected behavior for the selected stable case.packages/ai-vercel-gateway/src/text/text-provider-options.ts (1)
7-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider allowing unknown provider and model ids in routing options.
order,only, andmodelsnow accept only catalog members. Vercel AI Gateway adds providers and models between daily catalog syncs. Users who route to a new id must cast to compile.Keep the catalog union for autocomplete, and add a widening branch so unknown ids remain assignable.
Based on learnings,
ai-falkeeps per-model type safety while adding a fallback for unknown models to support frequent catalog updates.♻️ Proposed widening
- order?: Array<VercelGatewayProvider> - only?: Array<VercelGatewayProvider> + order?: Array<VercelGatewayProvider | (string & {})> + only?: Array<VercelGatewayProvider | (string & {})> sort?: 'cost' | 'ttft' | 'tps' - models?: Array<VercelGatewayChatModel> + models?: Array<VercelGatewayChatModel | (string & {})>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ai-vercel-gateway/src/text/text-provider-options.ts` around lines 7 - 10, Update the routing option types in the text provider options definition so order, only, and models retain catalog-union autocomplete while also accepting arbitrary provider or model identifiers. Follow the existing per-model widening pattern used by ai-fal, preserving model-specific type safety for known entries and adding a fallback for newly introduced unknown ids.Source: Learnings
packages/ai-vercel-gateway/src/index.ts (1)
13-19: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a public
./adaptersexport.The export map exposes only
.and./tools, and nosrc/adapters/index.tsbarrel exists. Add the barrel and map./adaptersto its built output.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ai-vercel-gateway/src/index.ts` around lines 13 - 19, Add a public adapters barrel at src/adapters/index.ts that re-exports the adapter APIs currently exposed through the factory, then update the package export map to include ./adapters pointing to its built output alongside . and ./tools.Source: Coding guidelines
packages/ai-vercel-gateway/tests/factory.test.ts (1)
1-7: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUpdate Vitest discovery before moving the test. Include both
tests/**/*.test.tsandsrc/**/*.test.tsinvitest.config.ts, then move the test tosrc/adapters/factory.test.tsand update its imports.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ai-vercel-gateway/tests/factory.test.ts` around lines 1 - 7, Update vitest.config.ts to discover both tests/**/*.test.ts and src/**/*.test.ts, then move factory.test.ts from tests to src/adapters and adjust its relative imports for the new location while preserving the existing test coverage.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/ai-vercel-gateway/src/text/responses-provider-options.ts`:
- Around line 6-7: The Responses adapter should default to
ExternalResponsesProviderOptions rather than ResolveProviderOptions<TModel>,
preventing Chat Completions-only options from being exposed. Update the
adapter’s default generic or option-resolution path, using the existing
VercelGatewayResponsesProviderOptions and
VercelGatewayResponsesTextProviderOptions symbols to preserve the
Responses-specific option contract.
---
Nitpick comments:
In `@packages/ai-vercel-gateway/src/index.ts`:
- Around line 13-19: Add a public adapters barrel at src/adapters/index.ts that
re-exports the adapter APIs currently exposed through the factory, then update
the package export map to include ./adapters pointing to its built output
alongside . and ./tools.
In `@packages/ai-vercel-gateway/src/text/text-provider-options.ts`:
- Around line 7-10: Update the routing option types in the text provider options
definition so order, only, and models retain catalog-union autocomplete while
also accepting arbitrary provider or model identifiers. Follow the existing
per-model widening pattern used by ai-fal, preserving model-specific type safety
for known entries and adding a fallback for newly introduced unknown ids.
In `@packages/ai-vercel-gateway/tests/factory.test.ts`:
- Around line 1-7: Update vitest.config.ts to discover both tests/**/*.test.ts
and src/**/*.test.ts, then move factory.test.ts from tests to src/adapters and
adjust its relative imports for the new location while preserving the existing
test coverage.
In `@packages/ai-vercel-gateway/tests/model-meta.test.ts`:
- Around line 12-49: The type tests in the per-model provider options and input
modalities suites rely too heavily on volatile catalog IDs. Replace broad
ID-specific assertions with catalog-derived type checks, such as verifying every
modality tuple begins with “text” and preserving only one representative
ID-specific smoke test for modality or option behavior; keep the existing
expected behavior for the selected stable case.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 60554f76-8a22-4bd5-8858-4d332e02cfb9
📒 Files selected for processing (17)
docs/adapters/vercel-gateway.mddocs/config.jsonpackages/ai-vercel-gateway/README.mdpackages/ai-vercel-gateway/package.jsonpackages/ai-vercel-gateway/src/adapters/factory.tspackages/ai-vercel-gateway/src/adapters/responses-text.tspackages/ai-vercel-gateway/src/adapters/text.tspackages/ai-vercel-gateway/src/index.tspackages/ai-vercel-gateway/src/model-meta.tspackages/ai-vercel-gateway/src/text/responses-provider-options.tspackages/ai-vercel-gateway/src/text/text-provider-options.tspackages/ai-vercel-gateway/tests/factory.test.tspackages/ai-vercel-gateway/tests/model-meta.test.tspackages/ai-vercel-gateway/tests/text-adapter.test.tsscripts/convert-vercel-gateway-models.tsscripts/vercel-gateway.models.tstesting/e2e/src/lib/providers.ts
🚧 Files skipped from review as they are similar to previous changes (8)
- packages/ai-vercel-gateway/README.md
- docs/config.json
- docs/adapters/vercel-gateway.md
- scripts/vercel-gateway.models.ts
- packages/ai-vercel-gateway/src/adapters/responses-text.ts
- packages/ai-vercel-gateway/package.json
- packages/ai-vercel-gateway/tests/text-adapter.test.ts
- testing/e2e/src/lib/providers.ts
| export type VercelGatewayResponsesProviderOptions = VercelGatewayCommonOptions & | ||
| Pick<VercelGatewayBaseOptions, 'temperature' | 'top_p' | 'max_output_tokens'> |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Find consumers of VercelGatewayResponsesProviderOptions and check Responses adapter generic defaults.
set -euo pipefail
rg -n -C 3 'VercelGatewayResponsesProviderOptions' --glob '!node_modules'
echo '--- responses adapter and its config type ---'
fd -i 'responses-text.ts' packages/ai-vercel-gateway | xargs -r cat -n
echo '--- package exports ---'
fd -i 'index.ts' packages/ai-vercel-gateway/src --max-depth 2 | xargs -r rg -n 'responses-provider-options|ResponsesProviderOptions'Repository: TanStack/ai
Length of output: 149
🏁 Script executed:
set -euo pipefail
echo '--- candidate files ---'
fd -i -t f 'responses|provider-options|model-meta|index\.ts' packages/ai-vercel-gateway packages 2>/dev/null | head -200
echo '--- exact type references ---'
rg -n -C 4 'VercelGatewayResponsesProviderOptions|VercelGatewayResponsesTextAdapter|ResolveProviderOptions' packages/ai-vercel-gateway || true
echo '--- package source exports ---'
fd -t f 'index.ts' packages/ai-vercel-gateway/src --max-depth 3 -x sh -c 'echo "--- $1"; cat -n "$1"' sh {}Repository: TanStack/ai
Length of output: 27779
🏁 Script executed:
set -euo pipefail
echo '--- Responses adapter definitions ---'
cat -n packages/ai-vercel-gateway/src/adapters/responses-text.ts | sed -n '1,115p'
echo '--- Responses provider option definitions ---'
cat -n packages/ai-vercel-gateway/src/text/responses-provider-options.ts
cat -n packages/ai-vercel-gateway/src/text/text-provider-options.ts | sed -n '1,140p'
echo '--- all package references, including aliases ---'
rg -n -C 5 'ExternalResponsesProviderOptions|VercelGatewayResponsesTextProviderOptions|responses-provider-options' packages/ai-vercel-gatewayRepository: TanStack/ai
Length of output: 9760
Use ExternalResponsesProviderOptions as the Responses adapter default.
VercelGatewayResponsesProviderOptions is exported through VercelGatewayResponsesTextProviderOptions, but the adapter defaults to ResolveProviderOptions<TModel>. This exposes Chat Completions-only keys such as max_tokens, stop, and frequency_penalty.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/ai-vercel-gateway/src/text/responses-provider-options.ts` around
lines 6 - 7, The Responses adapter should default to
ExternalResponsesProviderOptions rather than ResolveProviderOptions<TModel>,
preventing Chat Completions-only options from being exposed. Update the
adapter’s default generic or option-resolution path, using the existing
VercelGatewayResponsesProviderOptions and
VercelGatewayResponsesTextProviderOptions symbols to preserve the
Responses-specific option contract.
Changes
Add first-party
@tanstack/ai-vercel-gatewayfor Vercel AI Gateway.GET /v1/models, plus daily sync insync-models.ymlAI_GATEWAY_API_KEYwins overVERCEL_OIDC_TOKENproviderOptions.gateway(no top-level model or provider shorthands)vercel-gatewayandvercel-gateway-responsesVideo, TTS, transcription, and rerank are out of v1.
Checklist
pnpm run test:pr.Local note: this worktree has untracked
worktrees/andmarketing/folders, so Nx (pnpm test:pr) cannot run here. Equivalent checks passed withpnpm --filter:@tanstack/ai-vercel-gatewayRelease Impact
Test Plan
pnpm --filter @tanstack/ai-vercel-gateway test:libpnpm --filter @tanstack/ai-vercel-gateway test:typespnpm --filter @tanstack/ai-vercel-gateway test:oxlintpnpm --filter @tanstack/ai-vercel-gateway buildandtest:buildpnpm --filter @tanstack/ai-e2e test:e2e -- --grep vercel-gatewayPR+E2E TestsgreenSummary by CodeRabbit
@tanstack/ai-vercel-gatewaypackage.