Skip to content
190 changes: 190 additions & 0 deletions pydantic_ai_slim/pydantic_ai/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,196 @@
'cohere:command-r7b-12-2024',
'deepseek:deepseek-chat',
'deepseek:deepseek-reasoner',
'gateway/anthropic:claude-3-5-haiku-20241022',
'gateway/anthropic:claude-3-5-haiku-latest',
'gateway/anthropic:claude-3-7-sonnet-20250219',
'gateway/anthropic:claude-3-7-sonnet-latest',
'gateway/anthropic:claude-3-haiku-20240307',
'gateway/anthropic:claude-3-opus-20240229',
'gateway/anthropic:claude-3-opus-latest',
'gateway/anthropic:claude-4-opus-20250514',
'gateway/anthropic:claude-4-sonnet-20250514',
'gateway/anthropic:claude-haiku-4-5',
'gateway/anthropic:claude-haiku-4-5-20251001',
'gateway/anthropic:claude-opus-4-0',
'gateway/anthropic:claude-opus-4-1-20250805',
'gateway/anthropic:claude-opus-4-20250514',
'gateway/anthropic:claude-opus-4-5',
'gateway/anthropic:claude-opus-4-5-20251101',
'gateway/anthropic:claude-sonnet-4-0',
'gateway/anthropic:claude-sonnet-4-20250514',
'gateway/anthropic:claude-sonnet-4-5',
'gateway/anthropic:claude-sonnet-4-5-20250929',
'gateway/bedrock:amazon.titan-text-express-v1',
'gateway/bedrock:amazon.titan-text-lite-v1',
'gateway/bedrock:amazon.titan-tg1-large',
'gateway/bedrock:anthropic.claude-3-5-haiku-20241022-v1:0',
'gateway/bedrock:anthropic.claude-3-5-sonnet-20240620-v1:0',
'gateway/bedrock:anthropic.claude-3-5-sonnet-20241022-v2:0',
'gateway/bedrock:anthropic.claude-3-7-sonnet-20250219-v1:0',
'gateway/bedrock:anthropic.claude-3-haiku-20240307-v1:0',
'gateway/bedrock:anthropic.claude-3-opus-20240229-v1:0',
'gateway/bedrock:anthropic.claude-3-sonnet-20240229-v1:0',
'gateway/bedrock:anthropic.claude-haiku-4-5-20251001-v1:0',
'gateway/bedrock:anthropic.claude-instant-v1',
'gateway/bedrock:anthropic.claude-opus-4-20250514-v1:0',
'gateway/bedrock:anthropic.claude-sonnet-4-20250514-v1:0',
'gateway/bedrock:anthropic.claude-sonnet-4-5-20250929-v1:0',
'gateway/bedrock:anthropic.claude-v2',
'gateway/bedrock:anthropic.claude-v2:1',
'gateway/bedrock:cohere.command-light-text-v14',
'gateway/bedrock:cohere.command-r-plus-v1:0',
'gateway/bedrock:cohere.command-r-v1:0',
'gateway/bedrock:cohere.command-text-v14',
'gateway/bedrock:eu.anthropic.claude-haiku-4-5-20251001-v1:0',
'gateway/bedrock:eu.anthropic.claude-sonnet-4-20250514-v1:0',
'gateway/bedrock:eu.anthropic.claude-sonnet-4-5-20250929-v1:0',
'gateway/bedrock:global.anthropic.claude-opus-4-5-20251101-v1:0',
'gateway/bedrock:meta.llama3-1-405b-instruct-v1:0',
'gateway/bedrock:meta.llama3-1-70b-instruct-v1:0',
'gateway/bedrock:meta.llama3-1-8b-instruct-v1:0',
'gateway/bedrock:meta.llama3-70b-instruct-v1:0',
'gateway/bedrock:meta.llama3-8b-instruct-v1:0',
'gateway/bedrock:mistral.mistral-7b-instruct-v0:2',
'gateway/bedrock:mistral.mistral-large-2402-v1:0',
'gateway/bedrock:mistral.mistral-large-2407-v1:0',
'gateway/bedrock:mistral.mixtral-8x7b-instruct-v0:1',
'gateway/bedrock:us.amazon.nova-lite-v1:0',
'gateway/bedrock:us.amazon.nova-micro-v1:0',
'gateway/bedrock:us.amazon.nova-pro-v1:0',
'gateway/bedrock:us.anthropic.claude-3-5-haiku-20241022-v1:0',
'gateway/bedrock:us.anthropic.claude-3-5-sonnet-20240620-v1:0',
'gateway/bedrock:us.anthropic.claude-3-5-sonnet-20241022-v2:0',
'gateway/bedrock:us.anthropic.claude-3-7-sonnet-20250219-v1:0',
'gateway/bedrock:us.anthropic.claude-3-haiku-20240307-v1:0',
'gateway/bedrock:us.anthropic.claude-3-opus-20240229-v1:0',
'gateway/bedrock:us.anthropic.claude-3-sonnet-20240229-v1:0',
'gateway/bedrock:us.anthropic.claude-haiku-4-5-20251001-v1:0',
'gateway/bedrock:us.anthropic.claude-opus-4-20250514-v1:0',
'gateway/bedrock:us.anthropic.claude-sonnet-4-20250514-v1:0',
'gateway/bedrock:us.anthropic.claude-sonnet-4-5-20250929-v1:0',
'gateway/bedrock:us.meta.llama3-1-70b-instruct-v1:0',
'gateway/bedrock:us.meta.llama3-1-8b-instruct-v1:0',
'gateway/bedrock:us.meta.llama3-2-11b-instruct-v1:0',
'gateway/bedrock:us.meta.llama3-2-1b-instruct-v1:0',
'gateway/bedrock:us.meta.llama3-2-3b-instruct-v1:0',
'gateway/bedrock:us.meta.llama3-2-90b-instruct-v1:0',
'gateway/bedrock:us.meta.llama3-3-70b-instruct-v1:0',
'gateway/google-vertex:gemini-2.0-flash',
'gateway/google-vertex:gemini-2.0-flash-lite',
'gateway/google-vertex:gemini-2.5-flash',
'gateway/google-vertex:gemini-2.5-flash-image',
'gateway/google-vertex:gemini-2.5-flash-lite',
'gateway/google-vertex:gemini-2.5-flash-lite-preview-09-2025',
'gateway/google-vertex:gemini-2.5-flash-preview-09-2025',
'gateway/google-vertex:gemini-2.5-pro',
'gateway/google-vertex:gemini-3-pro-image-preview',
'gateway/google-vertex:gemini-3-pro-preview',
'gateway/google-vertex:gemini-flash-latest',
'gateway/google-vertex:gemini-flash-lite-latest',
'gateway/groq:deepseek-r1-distill-llama-70b',
'gateway/groq:deepseek-r1-distill-qwen-32b',
'gateway/groq:distil-whisper-large-v3-en',
'gateway/groq:gemma2-9b-it',
'gateway/groq:llama-3.1-8b-instant',
'gateway/groq:llama-3.2-11b-vision-preview',
'gateway/groq:llama-3.2-1b-preview',
'gateway/groq:llama-3.2-3b-preview',
'gateway/groq:llama-3.2-90b-vision-preview',
'gateway/groq:llama-3.3-70b-specdec',
'gateway/groq:llama-3.3-70b-versatile',
'gateway/groq:llama-guard-3-8b',
'gateway/groq:llama3-70b-8192',
'gateway/groq:llama3-8b-8192',
'gateway/groq:mistral-saba-24b',
'gateway/groq:moonshotai/kimi-k2-instruct',
'gateway/groq:playai-tts',
'gateway/groq:playai-tts-arabic',
'gateway/groq:qwen-2.5-32b',
'gateway/groq:qwen-2.5-coder-32b',
'gateway/groq:qwen-qwq-32b',
'gateway/groq:whisper-large-v3',
'gateway/groq:whisper-large-v3-turbo',
'gateway/openai:chatgpt-4o-latest',
'gateway/openai:codex-mini-latest',
'gateway/openai:computer-use-preview',
'gateway/openai:computer-use-preview-2025-03-11',
'gateway/openai:gpt-3.5-turbo',
'gateway/openai:gpt-3.5-turbo-0125',
'gateway/openai:gpt-3.5-turbo-0301',
'gateway/openai:gpt-3.5-turbo-0613',
'gateway/openai:gpt-3.5-turbo-1106',
'gateway/openai:gpt-3.5-turbo-16k',
'gateway/openai:gpt-3.5-turbo-16k-0613',
'gateway/openai:gpt-4',
'gateway/openai:gpt-4-0125-preview',
'gateway/openai:gpt-4-0314',
'gateway/openai:gpt-4-0613',
'gateway/openai:gpt-4-1106-preview',
'gateway/openai:gpt-4-32k',
'gateway/openai:gpt-4-32k-0314',
'gateway/openai:gpt-4-32k-0613',
'gateway/openai:gpt-4-turbo',
'gateway/openai:gpt-4-turbo-2024-04-09',
'gateway/openai:gpt-4-turbo-preview',
'gateway/openai:gpt-4-vision-preview',
'gateway/openai:gpt-4.1',
'gateway/openai:gpt-4.1-2025-04-14',
'gateway/openai:gpt-4.1-mini',
'gateway/openai:gpt-4.1-mini-2025-04-14',
'gateway/openai:gpt-4.1-nano',
'gateway/openai:gpt-4.1-nano-2025-04-14',
'gateway/openai:gpt-4o',
'gateway/openai:gpt-4o-2024-05-13',
'gateway/openai:gpt-4o-2024-08-06',
'gateway/openai:gpt-4o-2024-11-20',
'gateway/openai:gpt-4o-audio-preview',
'gateway/openai:gpt-4o-audio-preview-2024-10-01',
'gateway/openai:gpt-4o-audio-preview-2024-12-17',
'gateway/openai:gpt-4o-audio-preview-2025-06-03',
'gateway/openai:gpt-4o-mini',
'gateway/openai:gpt-4o-mini-2024-07-18',
'gateway/openai:gpt-4o-mini-audio-preview',
'gateway/openai:gpt-4o-mini-audio-preview-2024-12-17',
'gateway/openai:gpt-4o-mini-search-preview',
'gateway/openai:gpt-4o-mini-search-preview-2025-03-11',
'gateway/openai:gpt-4o-search-preview',
'gateway/openai:gpt-4o-search-preview-2025-03-11',
'gateway/openai:gpt-5',
'gateway/openai:gpt-5-2025-08-07',
'gateway/openai:gpt-5-chat-latest',
'gateway/openai:gpt-5-codex',
'gateway/openai:gpt-5-mini',
'gateway/openai:gpt-5-mini-2025-08-07',
'gateway/openai:gpt-5-nano',
'gateway/openai:gpt-5-nano-2025-08-07',
'gateway/openai:gpt-5-pro',
'gateway/openai:gpt-5-pro-2025-10-06',
'gateway/openai:gpt-5.1',
'gateway/openai:gpt-5.1-2025-11-13',
'gateway/openai:gpt-5.1-chat-latest',
'gateway/openai:gpt-5.1-codex',
'gateway/openai:gpt-5.1-mini',
'gateway/openai:o1',
'gateway/openai:o1-2024-12-17',
'gateway/openai:o1-mini',
'gateway/openai:o1-mini-2024-09-12',
'gateway/openai:o1-preview',
'gateway/openai:o1-preview-2024-09-12',
'gateway/openai:o1-pro',
'gateway/openai:o1-pro-2025-03-19',
'gateway/openai:o3',
'gateway/openai:o3-2025-04-16',
'gateway/openai:o3-deep-research',
'gateway/openai:o3-deep-research-2025-06-26',
'gateway/openai:o3-mini',
'gateway/openai:o3-mini-2025-01-31',
'gateway/openai:o3-pro',
'gateway/openai:o3-pro-2025-06-10',
'gateway/openai:o4-mini',
'gateway/openai:o4-mini-2025-04-16',
'gateway/openai:o4-mini-deep-research',
'gateway/openai:o4-mini-deep-research-2025-06-26',
'google-gla:gemini-flash-latest',
'google-gla:gemini-flash-lite-latest',
'google-gla:gemini-2.0-flash',
Expand Down
33 changes: 30 additions & 3 deletions pydantic_ai_slim/pydantic_ai/providers/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations as _annotations

import os
from collections.abc import Awaitable, Callable
from collections.abc import Awaitable, Callable, Mapping
from typing import TYPE_CHECKING, Any, Literal, overload

import httpx
Expand Down Expand Up @@ -93,13 +93,38 @@ def gateway_provider(
) -> Provider[Any]: ...


UpstreamProvider = Literal[
ModelProviders = Literal[
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a type, so singular :)

'openai',
'groq',
'anthropic',
'bedrock',
'google-vertex',
# Those are only API formats, but we still support them for convenience.
]


def gateway_provider_to_model_names() -> Mapping[ModelProviders, object]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be a public method :)

"""Get the gateway model name for a given provider.

Args:
provider: The provider to get the model name for.
"""
from pydantic_ai.models.anthropic import AnthropicModelName
from pydantic_ai.models.bedrock import BedrockModelName
from pydantic_ai.models.google import GoogleModelName
from pydantic_ai.models.groq import GroqModelName
from pydantic_ai.models.openai import OpenAIModelName

return {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this mapping to test_model_names.py so that the get_model_names used there can also take a provider name.

Then [f'grok:{n}' for n in get_model_names(GrokModelName)] could become [f'grok:{n}' for n in get_model_names('grok')], or prefixed_model_names('grok'). And then if we have the complete dict, we can basically just to model_names = [prefixed_model_names(provider) for provider in provider_model_names.keys()] or something like that.

Basically clean up all this duplication:

anthropic_names = [f'anthropic:{n}' for n in get_model_names(AnthropicModelName)]
    cohere_names = [f'cohere:{n}' for n in get_model_names(CohereModelName)]
    google_names = [f'google-gla:{n}' for n in get_model_names(GoogleModelName)] + [
        f'google-vertex:{n}' for n in get_model_names(GoogleModelName)
    ]
    grok_names = [f'grok:{n}' for n in get_model_names(GrokModelName)]
    groq_names = [f'groq:{n}' for n in get_model_names(GroqModelName)]
    moonshotai_names = [f'moonshotai:{n}' for n in get_model_names(MoonshotAIModelName)]
    mistral_names = [f'mistral:{n}' for n in get_model_names(MistralModelName)]
    openai_names = [f'openai:{n}' for n in get_model_names(OpenAIModelName)]
    bedrock_names = [f'bedrock:{n}' for n in get_model_names(BedrockModelName)]
    deepseek_names = ['deepseek:deepseek-chat', 'deepseek:deepseek-reasoner']
    gateway_names = [
        f'gateway/{provider}:{model_name}'
        for provider, model_names in gateway_provider_to_model_names().items()
        for model_name in get_model_names(model_names)
    ]
    huggingface_names = [f'huggingface:{n}' for n in get_model_names(HuggingFaceModelName)]

By having just a dict of provider names to model name types (or functions like in the case of get_heroku_model_names)

'openai': OpenAIModelName,
'groq': GroqModelName,
'anthropic': AnthropicModelName,
'bedrock': BedrockModelName,
'google-vertex': GoogleModelName,
}


# These are only API formats, but we still support them for convenience.
ApiFormatProviders = Literal[
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ApiFormats? Or do we call them API Flavors now?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just copied the comment as was, but yeah flavor's definitely correcter (correcter than the word correcter)

'openai-chat',
'openai-responses',
'chat',
Expand All @@ -108,6 +133,8 @@ def gateway_provider(
'gemini',
]

UpstreamProvider = ModelProviders | ApiFormatProviders


def gateway_provider(
upstream_provider: UpstreamProvider | str,
Expand Down
7 changes: 7 additions & 0 deletions tests/models/test_model_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from pydantic_ai.models.huggingface import HuggingFaceModelName
from pydantic_ai.models.mistral import MistralModelName
from pydantic_ai.models.openai import OpenAIModelName
from pydantic_ai.providers.gateway import gateway_provider_to_model_names
from pydantic_ai.providers.grok import GrokModelName
from pydantic_ai.providers.moonshotai import MoonshotAIModelName

Expand Down Expand Up @@ -70,6 +71,11 @@ def get_model_names(model_name_type: Any) -> Iterator[str]:
openai_names = [f'openai:{n}' for n in get_model_names(OpenAIModelName)]
bedrock_names = [f'bedrock:{n}' for n in get_model_names(BedrockModelName)]
deepseek_names = ['deepseek:deepseek-chat', 'deepseek:deepseek-reasoner']
gateway_names = [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize you couldn't see this comment in a private Slack channel, but I responded to Samuel (and he agreed):

Agreed, but if we add just a few per provider, people are definitely gonna ask us “but why not this other one?”, so maybe just include them all?

So we should NOT hard-code this, but dynamically build this based on the known model names of the providers that are known to work with gateway/{provider}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is now done

f'gateway/{provider}:{model_name}'
for provider, model_names in gateway_provider_to_model_names().items()
for model_name in get_model_names(model_names)
]
huggingface_names = [f'huggingface:{n}' for n in get_model_names(HuggingFaceModelName)]
heroku_names = get_heroku_model_names()
cerebras_names = get_cerebras_model_names()
Expand All @@ -86,6 +92,7 @@ def get_model_names(model_name_type: Any) -> Iterator[str]:
+ openai_names
+ bedrock_names
+ deepseek_names
+ gateway_names
+ huggingface_names
+ heroku_names
+ cerebras_names
Expand Down
1 change: 1 addition & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ def test_list_models(capfd: CaptureFixture[str]):
'mistral',
'cohere',
'deepseek',
'gateway/',
'heroku',
'moonshotai',
'grok',
Expand Down