Add custom-endpoint support to the Anthropic provider - #499
Open
sairohiththammana wants to merge 1 commit into
Open
Add custom-endpoint support to the Anthropic provider#499sairohiththammana wants to merge 1 commit into
sairohiththammana wants to merge 1 commit into
Conversation
Mirrors the OpenAI slot: an optional `base_url` on the `anthropic` profile points the Anthropic SDK at any Messages-API-compatible gateway (LiteLLM, a corporate proxy). Blank keeps api.anthropic.com — and keeps the SDK's own ANTHROPIC_BASE_URL env support intact. Anthropic needs less than OpenAI did: there is one wire either way, so the endpoint only swaps the host. What it does need: - The stored value is the ROOT (the SDK appends /v1/messages itself), so a `/v1` carried over from the OpenAI box is trimmed rather than doubled. - Fable/Mythos skip the beta server-side-fallback path on a custom endpoint: the beta header, `fallbacks` param and beta route are Anthropic-only and a gateway that doesn't know them 400s the whole turn. - Test falls back to a one-token /v1/messages call when a gateway proxies messages but not /v1/models, and treats an Anthropic-shaped 4xx as proof the endpoint speaks the API. "Anthropic-shaped" means the top-level `"type": "error"` discriminator — a bare nested `error` object is the OpenAI/LiteLLM shape, and accepting it would green-light an OpenAI URL pasted into this box, passing Test and failing every turn afterwards. - `resolve_api_key` grows a `prefer_profile` flag, set when an endpoint is configured, so a key typed alongside a gateway is never shadowed by an ambient ANTHROPIC_API_KEY meant for api.anthropic.com. Belt-and-braces on the router path (the registry already passes the profile key explicitly); it earns its keep for provider instances built from a SecretStore alone. The GUI needed no new component: the endpoint row is descriptor-driven, so the field appears in both Onboarding and Settings ▸ Models as soon as the provider declares it. A stored endpoint now opens the disclosure instead of hiding behind a collapsed link. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Mirrors the OpenAI slot: an optional
base_urlon theanthropicprofile points the Anthropic SDK at any Messages-API-compatible gateway (LiteLLM, a corporate proxy). Blank keepsapi.anthropic.com— and keeps the SDK's ownANTHROPIC_BASE_URLenv support intact.Anthropic needs less than OpenAI did: there is one wire either way (no Responses ⇄ Chat Completions switch), so the endpoint only swaps the host.
What it does need
/v1/messagesitself, so a/v1carried over from the OpenAI box — where it belongs — is trimmed rather than doubled into/v1/v1/messages.fallbacksparam and the beta messages route are Anthropic-only; a gateway that doesn't know them 400s the whole turn. Losing the fallback there costs a refusal retry, not a working request./v1/messagescall when a gateway proxies messages but not/v1/models, and treats an Anthropic-shaped 4xx as proof the endpoint speaks the API. "Anthropic-shaped" means the top-level"type": "error"discriminator — a bare nestederrorobject is the OpenAI/LiteLLM shape, and accepting it would green-light an OpenAI URL pasted into this box: Test would pass and every turn would fail afterwards.resolve_api_keygrows aprefer_profileflag, set when an endpoint is configured, so a key typed alongside a gateway is never shadowed by an ambientANTHROPIC_API_KEYmeant forapi.anthropic.com. Belt-and-braces on the router path (the registry already passes the profile key explicitly); it earns its keep for provider instances built from a SecretStore alone.GUI
No new component. The endpoint row is descriptor-driven —
ProviderFormrenders it for any keyed provider that declaresbase_url— so the field appears in both Onboarding and Settings ▸ Models as soon as the descriptor has it. One behavior change: a stored endpoint now opens the disclosure instead of hiding behind the collapsed "Custom endpoint ⌄" link, since a configured gateway is the one thing a collapsed row would actively misrepresent. That applies to OpenAI too.Testing
pytest tests— 1181 passed, 1 skipped./v1trimming, blank →None),base_urlreaching the SDK only when set, key precedence under a gateway, the beta-path skip, and four verify cases (custom endpoint URL,/v1/messagesfallback, key rejection on the fallback, non-Anthropic host still failing — parametrized over a plain 404 page and an OpenAI-shaped error body).ProviderFormtests covering the descriptor-driven endpoint row. Not run locally (no Node on the authoring machine) — CI'sgui-unitjob covers them.Known limitation
Gateways that require
Authorization: Bearerinstead ofx-api-keyare not supported; the SDK sendsx-api-key. Adding an auth-style toggle would be a second field and a second verify branch — deliberately deferred until a real gateway needs it.