Skip to content

Commit 733635d

Browse files
committed
refactor: Add OpenAIModelProfile
1 parent 1e6805b commit 733635d

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

pydantic_ai_slim/pydantic_ai/providers/ovhcloud.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
from pydantic_ai import ModelProfile
99
from pydantic_ai.exceptions import UserError
1010
from pydantic_ai.models import cached_async_http_client
11+
from pydantic_ai.profiles.deepseek import deepseek_model_profile
12+
from pydantic_ai.profiles.harmony import harmony_model_profile
13+
from pydantic_ai.profiles.meta import meta_model_profile
14+
from pydantic_ai.profiles.mistral import mistral_model_profile
15+
from pydantic_ai.profiles.openai import OpenAIJsonSchemaTransformer, OpenAIModelProfile
16+
from pydantic_ai.profiles.qwen import qwen_model_profile
1117
from pydantic_ai.providers import Provider
1218

1319
try:
@@ -35,7 +41,21 @@ def client(self) -> AsyncOpenAI:
3541
return self._client
3642

3743
def model_profile(self, model_name: str) -> ModelProfile | None:
38-
return None
44+
if 'deepseek' in model_name.lower():
45+
profile = deepseek_model_profile(model_name)
46+
elif 'llama' in model_name.lower():
47+
profile = meta_model_profile(model_name)
48+
elif 'mistral' in model_name.lower():
49+
profile = mistral_model_profile(model_name)
50+
elif 'qwen' in model_name.lower():
51+
profile = qwen_model_profile(model_name)
52+
elif 'openai' in model_name.lower() or 'gpt' in model_name:
53+
profile = harmony_model_profile(model_name)
54+
else:
55+
profile = None
56+
57+
# As the OVHcloud AI Endpoints API is OpenAI-compatible, let's assume we also need OpenAIJsonSchemaTransformer.
58+
return OpenAIModelProfile(json_schema_transformer=OpenAIJsonSchemaTransformer).update(profile)
3959

4060
@overload
4161
def __init__(self) -> None: ...

tests/providers/test_ovhcloud.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@
22

33
import httpx
44
import pytest
5+
from pytest_mock import MockerFixture
56

7+
from pydantic_ai._json_schema import InlineDefsJsonSchemaTransformer
68
from pydantic_ai.exceptions import UserError
9+
from pydantic_ai.profiles.deepseek import deepseek_model_profile
10+
from pydantic_ai.profiles.harmony import harmony_model_profile
11+
from pydantic_ai.profiles.meta import meta_model_profile
12+
from pydantic_ai.profiles.mistral import mistral_model_profile
13+
from pydantic_ai.profiles.openai import OpenAIJsonSchemaTransformer
14+
from pydantic_ai.profiles.qwen import qwen_model_profile
715

816
from ..conftest import TestEnv, try_import
917

@@ -51,3 +59,51 @@ def test_ovhcloud_pass_http_client():
5159
provider = OVHcloudProvider(api_key='your-api-key', http_client=http_client)
5260
assert isinstance(provider.client, openai.AsyncOpenAI)
5361
assert provider.client.api_key == 'your-api-key'
62+
63+
64+
def test_ovhcloud_model_profile(mocker: MockerFixture):
65+
provider = OVHcloudProvider(api_key='your-api-key')
66+
67+
ns = 'pydantic_ai.providers.ovhcloud'
68+
69+
# Mock all profile functions
70+
deepseek_mock = mocker.patch(f'{ns}.deepseek_model_profile', wraps=deepseek_model_profile)
71+
harmony_mock = mocker.patch(f'{ns}.harmony_model_profile', wraps=harmony_model_profile)
72+
meta_mock = mocker.patch(f'{ns}.meta_model_profile', wraps=meta_model_profile)
73+
mistral_mock = mocker.patch(f'{ns}.mistral_model_profile', wraps=mistral_model_profile)
74+
qwen_mock = mocker.patch(f'{ns}.qwen_model_profile', wraps=qwen_model_profile)
75+
76+
# Test deepseek provider
77+
profile = provider.model_profile('DeepSeek-R1-Distill-Llama-70B')
78+
deepseek_mock.assert_called_with('DeepSeek-R1-Distill-Llama-70B')
79+
assert profile is not None
80+
assert profile.json_schema_transformer == OpenAIJsonSchemaTransformer
81+
82+
# Test harmony (for openai gpt-oss) provider
83+
profile = provider.model_profile('gpt-oss-120b')
84+
harmony_mock.assert_called_with('gpt-oss-120b')
85+
assert profile is not None
86+
assert profile.json_schema_transformer == OpenAIJsonSchemaTransformer
87+
88+
# Test meta provider
89+
meta_profile = provider.model_profile('Llama-3.3-70B-Instruct')
90+
meta_mock.assert_called_with('Llama-3.3-70B-Instruct')
91+
assert meta_profile is not None
92+
assert meta_profile.json_schema_transformer == InlineDefsJsonSchemaTransformer
93+
94+
# Test mistral provider
95+
profile = provider.model_profile('Mistral-Small-3.2-24B-Instruct-2506')
96+
mistral_mock.assert_called_with('Mistral-Small-3.2-24B-Instruct-2506')
97+
assert profile is not None
98+
assert profile.json_schema_transformer == OpenAIJsonSchemaTransformer
99+
100+
# Test qwen provider
101+
qwen_profile = provider.model_profile('Qwen3-32B')
102+
qwen_mock.assert_called_with('Qwen3-32B')
103+
assert qwen_profile is not None
104+
assert qwen_profile.json_schema_transformer == InlineDefsJsonSchemaTransformer
105+
106+
# Test unknown provider
107+
unknown_profile = provider.model_profile('unknown-model')
108+
assert unknown_profile is not None
109+
assert unknown_profile.json_schema_transformer == OpenAIJsonSchemaTransformer

0 commit comments

Comments
 (0)