Skip to content

feat(provider): Anthropic Messages provider - #536

Open
espetro wants to merge 7 commits into
vercel-labs:mainfrom
espetro:anthropic-messages-provider
Open

feat(provider): Anthropic Messages provider#536
espetro wants to merge 7 commits into
vercel-labs:mainfrom
espetro:anthropic-messages-provider

Conversation

@espetro

@espetro espetro commented Aug 31, 2026

Copy link
Copy Markdown

Adds Anthropic as a first-class provider on top of the current provider_set architecture (supersedes the transport portion of #168, addresses #150 and #112).

What

  • Config/auth: ProviderId.anthropic, CredentialSource.anthropic_api_key, credential loading from ANTHROPIC_API_KEY env or profile key, provider catalog entry
  • Gateway: src/gateway/anthropic.zig Anthropic Messages wire transport (POST /v1/messages, SSE, x-api-key + anthropic-version headers, system hoisting, tool_use/tool_result blocks, thinking budget) and anthropic_models.zig model catalog
  • Routing: anthropic wired through provider_set.Set bundles, CLI surfaces, ACP, subagents, doctor, auth runtime, footer model menu
  • Lifecycle: FX_MODEL env fallback when a provider-scoped model is unset (non-gateway providers only), with AnthropicModelNotSelected error surface

Verification

  • zig build test: 8640 pass; the 6 remaining failures are pre-existing on current main (verified in a pristine worktree)
  • Live smoke tested against a proxy exposing the Anthropic wire: single-turn text and a full tool-calling round trip (shell exec) both work

Notes for reviewers

  • Admission is signaled after request serialization, matching the other transports
  • The codec serializes tools to Anthropic's input_schema format directly from typed tool schemas (no intermediate serialized-tools JSON)

…ial source

Extend ProviderId with .anthropic and CredentialSource with
.anthropic_api_key, mirroring the openai/openai_api_key pair from
the OpenAI-compatible transport.

Credentials resolve from the ANTHROPIC_API_KEY environment variable
or a profile-owned anthropic_api_key setting, never from repository
config. Settings store gains the anthropic_model preference and
config_runtime validates it alongside the existing per-provider
model fields.
Implement the Anthropic Messages wire as a stream_provider.Provider:
POST {base}/v1/messages with x-api-key and anthropic-version headers,
top-level system hoisting, tool_use/tool_result blocks, and SSE
parsing for message_start, content_block_start/delta/stop (text,
thinking, and input_json deltas), message_delta, message_stop, and
error events. Stop reasons map to the shared failure taxonomy
(end_turn to stop, max_tokens to length, refusal to content_filter).

Assistant messages carrying both text and tool calls serialize the
tool_use blocks inside the still-open content array; closing it
before the blocks produced invalid JSON on every agentic replay.

Base URL defaults to https://api.anthropic.com and is overridable
via FX_ANTHROPIC_BASE_URL, with FX_E2E_ANTHROPIC_URL reserved for
loopback e2e fixtures. Boundaries match the existing transports
(1MB SSE line, 64MB aggregate, 128 tool calls, 4MB tool arguments).

anthropic_models.zig fetches /v1/models with the same caps as the
grok catalog and exports the standard model_catalog_provider pair.

Both files keep credential acceptance keyed by name so they compile
independently of the enum-case commit.
…faces

Register the anthropic bundle in builtins/providers.zig and thread it
through every surface the openai bundle reaches: the auth provider
picker (choiceAt now yields the fifth provider entry), acp server and
subagent prompt routing, cli_ask and cli_surface config structs,
doctor diagnostics, output contracts, credential resolution call
sites (profile anthropic key propagated alongside the openai key),
and main.zig dependency injection for both the entry config and the
ask/acp runner paths.

Anthropic carries no permission reviewer yet, matching the optional
reviewer slots; openai_compatible.zig rejects the anthropic_api_key
source symmetrically. The model menu lists the anthropic credential
label. Agent streams flow through the same ProviderRoutes dispatch
as the other wire protocols.
… unset

configuredProviderSelection returned ModelNotSelected whenever the
saved settings lacked a model for the active provider, even when
FX_MODEL carried a process override, making 'FX_PROVIDER=openai
FX_MODEL=...' fail before the stream provider was ever consulted.

Fall back to the trimmed FX_MODEL value before erroring for the
non-gateway providers (anthropic included) and scope each
TestEnv install in the override test to its own block so the
FX_PROVIDER assertions no longer inherit a stale environment.
Verified live against an OpenAI-compatible gateway on both the
openai and anthropic wires, including a tool-calling round trip.
Gateway already resolves a compiled default model, so consulting
FX_MODEL before the default changed the reported configured_model
and broke the startup env-override test.
Requests on the anthropic wire returned ProviderAdmissionMissing at
the gateway_step boundary because the codec never called
admission.admit() after serialization, unlike the other transports.
@vercel-security-reviewer

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant