pydantic-ai 0.0.44__tar.gz → 0.0.45__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pydantic-ai might be problematic. Click here for more details.

Files changed (109) hide show
  1. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/PKG-INFO +3 -3
  2. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/pyproject.toml +3 -3
  3. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/conftest.py +7 -2
  4. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_openai/test_audio_as_binary_content_input.yaml +6 -5
  5. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_openai/test_image_as_binary_content_input.yaml +8 -7
  6. pydantic_ai-0.0.45/tests/models/cassettes/test_openai/test_multiple_agent_tool_calls.yaml +391 -0
  7. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_openai/test_openai_o1_mini_system_role[developer].yaml +1 -4
  8. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_openai/test_openai_o1_mini_system_role[system].yaml +1 -6
  9. pydantic_ai-0.0.45/tests/models/cassettes/test_openai/test_user_id.yaml +79 -0
  10. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/test_anthropic.py +6 -7
  11. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/test_gemini.py +33 -72
  12. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/test_groq.py +3 -1
  13. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/test_instrumented.py +14 -18
  14. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/test_mistral.py +5 -14
  15. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/test_model_function.py +43 -34
  16. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/test_model_test.py +16 -5
  17. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/test_openai.py +45 -30
  18. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/providers/test_anthropic.py +7 -11
  19. pydantic_ai-0.0.45/tests/providers/test_bedrock.py +17 -0
  20. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/providers/test_cohere.py +7 -8
  21. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/providers/test_deepseek.py +13 -13
  22. pydantic_ai-0.0.45/tests/providers/test_google_gla.py +43 -0
  23. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/providers/test_groq.py +13 -13
  24. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/providers/test_mistral.py +13 -13
  25. pydantic_ai-0.0.45/tests/providers/test_openai.py +51 -0
  26. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/providers/test_provider_names.py +6 -3
  27. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_agent.py +138 -60
  28. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_examples.py +60 -18
  29. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_logfire.py +5 -3
  30. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_parts_manager.py +20 -24
  31. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_streaming.py +82 -35
  32. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_usage_limits.py +16 -3
  33. pydantic_ai-0.0.44/tests/models/test_vertexai.py +0 -185
  34. pydantic_ai-0.0.44/tests/providers/test_bedrock.py +0 -20
  35. pydantic_ai-0.0.44/tests/providers/test_google_gla.py +0 -19
  36. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/.gitignore +0 -0
  37. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/LICENSE +0 -0
  38. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/Makefile +0 -0
  39. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/README.md +0 -0
  40. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/__init__.py +0 -0
  41. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/assets/dummy.pdf +0 -0
  42. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/assets/kiwi.png +0 -0
  43. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/assets/marcelo.mp3 +0 -0
  44. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/cassettes/test_mcp/test_agent_with_stdio_server.yaml +0 -0
  45. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/example_modules/README.md +0 -0
  46. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/example_modules/bank_database.py +0 -0
  47. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/example_modules/fake_database.py +0 -0
  48. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/example_modules/weather_service.py +0 -0
  49. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/graph/__init__.py +0 -0
  50. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/graph/test_file_persistence.py +0 -0
  51. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/graph/test_graph.py +0 -0
  52. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/graph/test_mermaid.py +0 -0
  53. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/graph/test_persistence.py +0 -0
  54. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/graph/test_state.py +0 -0
  55. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/graph/test_utils.py +0 -0
  56. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/import_examples.py +0 -0
  57. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/json_body_serializer.py +0 -0
  58. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/mcp_server.py +0 -0
  59. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/__init__.py +0 -0
  60. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_anthropic/test_document_binary_content_input.yaml +0 -0
  61. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_anthropic/test_document_url_input.yaml +0 -0
  62. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_anthropic/test_image_url_input.yaml +0 -0
  63. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_anthropic/test_image_url_input_invalid_mime_type.yaml +0 -0
  64. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_anthropic/test_multiple_parallel_tool_calls.yaml +0 -0
  65. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_anthropic/test_text_document_url_input.yaml +0 -0
  66. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_bedrock/test_bedrock_model.yaml +0 -0
  67. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_bedrock/test_bedrock_model_anthropic_model_without_tools.yaml +0 -0
  68. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_bedrock/test_bedrock_model_iter_stream.yaml +0 -0
  69. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_bedrock/test_bedrock_model_max_tokens.yaml +0 -0
  70. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_bedrock/test_bedrock_model_retry.yaml +0 -0
  71. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_bedrock/test_bedrock_model_stream.yaml +0 -0
  72. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_bedrock/test_bedrock_model_structured_response.yaml +0 -0
  73. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_bedrock/test_bedrock_model_top_p.yaml +0 -0
  74. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_bedrock/test_document_url_input.yaml +0 -0
  75. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_bedrock/test_image_as_binary_content_input.yaml +0 -0
  76. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_bedrock/test_image_url_input.yaml +0 -0
  77. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_bedrock/test_text_as_binary_content_input.yaml +0 -0
  78. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_bedrock/test_text_document_url_input.yaml +0 -0
  79. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_cohere/test_request_simple_success_with_vcr.yaml +0 -0
  80. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_gemini/test_document_url_input.yaml +0 -0
  81. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_gemini/test_image_as_binary_content_input.yaml +0 -0
  82. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_gemini/test_image_url_input.yaml +0 -0
  83. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_groq/test_image_as_binary_content_input.yaml +0 -0
  84. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_groq/test_image_url_input.yaml +0 -0
  85. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_openai/test_document_url_input.yaml +0 -0
  86. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_openai/test_max_completion_tokens[gpt-4.5-preview].yaml +0 -0
  87. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_openai/test_max_completion_tokens[gpt-4o-mini].yaml +0 -0
  88. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/cassettes/test_openai/test_max_completion_tokens[o3-mini].yaml +0 -0
  89. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/mock_async_stream.py +0 -0
  90. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/test_bedrock.py +0 -0
  91. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/test_cohere.py +0 -0
  92. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/test_fallback.py +0 -0
  93. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/test_model.py +0 -0
  94. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/models/test_model_names.py +0 -0
  95. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/providers/__init__.py +0 -0
  96. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/providers/cassettes/test_azure/test_azure_provider_call.yaml +0 -0
  97. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/providers/test_azure.py +0 -0
  98. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/providers/test_google_vertex.py +0 -0
  99. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_cli.py +0 -0
  100. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_deps.py +0 -0
  101. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_format_as_xml.py +0 -0
  102. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_json_body_serializer.py +0 -0
  103. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_live.py +0 -0
  104. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_mcp.py +0 -0
  105. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_messages.py +0 -0
  106. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_tools.py +0 -0
  107. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/test_utils.py +0 -0
  108. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/typed_agent.py +0 -0
  109. {pydantic_ai-0.0.44 → pydantic_ai-0.0.45}/tests/typed_graph.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-ai
3
- Version: 0.0.44
3
+ Version: 0.0.45
4
4
  Summary: Agent Framework / shim to use Pydantic with LLMs
5
5
  Project-URL: Homepage, https://ai.pydantic.dev
6
6
  Project-URL: Source, https://github.com/pydantic/pydantic-ai
@@ -28,9 +28,9 @@ Classifier: Topic :: Internet
28
28
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
29
29
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
30
30
  Requires-Python: >=3.9
31
- Requires-Dist: pydantic-ai-slim[anthropic,bedrock,cli,cohere,groq,mcp,mistral,openai,vertexai]==0.0.44
31
+ Requires-Dist: pydantic-ai-slim[anthropic,bedrock,cli,cohere,groq,mcp,mistral,openai,vertexai]==0.0.45
32
32
  Provides-Extra: examples
33
- Requires-Dist: pydantic-ai-examples==0.0.44; extra == 'examples'
33
+ Requires-Dist: pydantic-ai-examples==0.0.45; extra == 'examples'
34
34
  Provides-Extra: logfire
35
35
  Requires-Dist: logfire>=2.3; extra == 'logfire'
36
36
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pydantic-ai"
7
- version = "0.0.44"
7
+ version = "0.0.45"
8
8
  description = "Agent Framework / shim to use Pydantic with LLMs"
9
9
  authors = [
10
10
  { name = "Samuel Colvin", email = "samuel@pydantic.dev" },
@@ -36,7 +36,7 @@ classifiers = [
36
36
  ]
37
37
  requires-python = ">=3.9"
38
38
  dependencies = [
39
- "pydantic-ai-slim[openai,vertexai,groq,anthropic,mistral,cohere,bedrock,cli,mcp]==0.0.44",
39
+ "pydantic-ai-slim[openai,vertexai,groq,anthropic,mistral,cohere,bedrock,cli,mcp]==0.0.45",
40
40
  ]
41
41
 
42
42
  [project.urls]
@@ -46,7 +46,7 @@ Documentation = "https://ai.pydantic.dev"
46
46
  Changelog = "https://github.com/pydantic/pydantic-ai/releases"
47
47
 
48
48
  [project.optional-dependencies]
49
- examples = ["pydantic-ai-examples==0.0.44"]
49
+ examples = ["pydantic-ai-examples==0.0.45"]
50
50
  logfire = ["logfire>=2.3"]
51
51
 
52
52
  [tool.uv.sources]
@@ -40,7 +40,7 @@ else:
40
40
 
41
41
  def IsNow(*args: Any, **kwargs: Any):
42
42
  # Increase the default value of `delta` to 10 to reduce test flakiness on overburdened machines
43
- if 'delta' not in kwargs:
43
+ if 'delta' not in kwargs: # pragma: no branch
44
44
  kwargs['delta'] = 10
45
45
  return _IsNow(*args, **kwargs)
46
46
 
@@ -154,7 +154,7 @@ def create_module(tmp_path: Path, request: pytest.FixtureRequest) -> Callable[[s
154
154
 
155
155
 
156
156
  @contextmanager
157
- def try_import() -> Iterator[Callable[[], bool]]:
157
+ def try_import() -> Iterator[Callable[[], bool]]: # pragma: no cover
158
158
  import_success = False
159
159
 
160
160
  def check_import() -> bool:
@@ -251,6 +251,11 @@ def co_api_key() -> str:
251
251
  return os.getenv('CO_API_KEY', 'mock-api-key')
252
252
 
253
253
 
254
+ @pytest.fixture(scope='session')
255
+ def mistral_api_key() -> str:
256
+ return os.getenv('MISTRAL_API_KEY', 'mock-api-key')
257
+
258
+
254
259
  @pytest.fixture
255
260
  def mock_snapshot_id(mocker: MockerFixture):
256
261
  i = 0
@@ -37,13 +37,13 @@ interactions:
37
37
  connection:
38
38
  - keep-alive
39
39
  content-length:
40
- - '882'
40
+ - '909'
41
41
  content-type:
42
42
  - application/json
43
43
  openai-organization:
44
44
  - pydantic-28gund
45
45
  openai-processing-ms:
46
- - '1394'
46
+ - '1898'
47
47
  openai-version:
48
48
  - '2020-10-01'
49
49
  strict-transport-security:
@@ -55,15 +55,16 @@ interactions:
55
55
  - finish_reason: stop
56
56
  index: 0
57
57
  message:
58
+ annotations: []
58
59
  content: The name mentioned in the audio is Marcelo.
59
60
  refusal: null
60
61
  role: assistant
61
- created: 1740408639
62
- id: chatcmpl-B4U51malankDFzpReXZCXRgKQsAx1
62
+ created: 1742905314
63
+ id: chatcmpl-BExZy74Y67dd65ec2z4iuzM0Exnks
63
64
  model: gpt-4o-audio-preview-2024-12-17
64
65
  object: chat.completion
65
66
  service_tier: default
66
- system_fingerprint: fp_31e26c9138
67
+ system_fingerprint: fp_bf4a46b2e5
67
68
  usage:
68
69
  completion_tokens: 9
69
70
  completion_tokens_details:
@@ -36,13 +36,13 @@ interactions:
36
36
  connection:
37
37
  - keep-alive
38
38
  content-length:
39
- - '812'
39
+ - '839'
40
40
  content-type:
41
41
  - application/json
42
42
  openai-organization:
43
43
  - pydantic-28gund
44
44
  openai-processing-ms:
45
- - '3988'
45
+ - '3245'
46
46
  openai-version:
47
47
  - '2020-10-01'
48
48
  strict-transport-security:
@@ -55,15 +55,16 @@ interactions:
55
55
  index: 0
56
56
  logprobs: null
57
57
  message:
58
+ annotations: []
58
59
  content: The fruit in the image is a kiwi.
59
60
  refusal: null
60
61
  role: assistant
61
- created: 1740408634
62
- id: chatcmpl-B4U4wIOoauVGgr7Nqe5H2oj5tZoKK
62
+ created: 1742905309
63
+ id: chatcmpl-BExZtIgl2l91Y1IYJW3DSJj1yRlpY
63
64
  model: gpt-4o-2024-08-06
64
65
  object: chat.completion
65
66
  service_tier: default
66
- system_fingerprint: fp_197415291b
67
+ system_fingerprint: fp_83df987f64
67
68
  usage:
68
69
  completion_tokens: 10
69
70
  completion_tokens_details:
@@ -71,11 +72,11 @@ interactions:
71
72
  audio_tokens: 0
72
73
  reasoning_tokens: 0
73
74
  rejected_prediction_tokens: 0
74
- prompt_tokens: 1152
75
+ prompt_tokens: 1119
75
76
  prompt_tokens_details:
76
77
  audio_tokens: 0
77
78
  cached_tokens: 0
78
- total_tokens: 1162
79
+ total_tokens: 1129
79
80
  status:
80
81
  code: 200
81
82
  message: OK
@@ -0,0 +1,391 @@
1
+ interactions:
2
+ - request:
3
+ headers:
4
+ accept:
5
+ - '*/*'
6
+ accept-encoding:
7
+ - gzip, deflate
8
+ connection:
9
+ - keep-alive
10
+ content-length:
11
+ - '318'
12
+ content-type:
13
+ - application/json
14
+ host:
15
+ - generativelanguage.googleapis.com
16
+ method: POST
17
+ parsed_body:
18
+ contents:
19
+ - parts:
20
+ - text: What is the capital of France?
21
+ role: user
22
+ tools:
23
+ function_declarations:
24
+ - description: Get the capital of a country.
25
+ name: get_capital
26
+ parameters:
27
+ properties:
28
+ country:
29
+ description: The country name.
30
+ type: string
31
+ required:
32
+ - country
33
+ type: object
34
+ uri: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent
35
+ response:
36
+ headers:
37
+ alt-svc:
38
+ - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
39
+ content-length:
40
+ - '741'
41
+ content-type:
42
+ - application/json; charset=UTF-8
43
+ server-timing:
44
+ - gfet4t7; dur=407
45
+ transfer-encoding:
46
+ - chunked
47
+ vary:
48
+ - Origin
49
+ - X-Origin
50
+ - Referer
51
+ parsed_body:
52
+ candidates:
53
+ - avgLogprobs: 3.921892493963242e-06
54
+ content:
55
+ parts:
56
+ - functionCall:
57
+ args:
58
+ country: France
59
+ name: get_capital
60
+ role: model
61
+ finishReason: STOP
62
+ modelVersion: gemini-2.0-flash-exp
63
+ usageMetadata:
64
+ candidatesTokenCount: 5
65
+ candidatesTokensDetails:
66
+ - modality: TEXT
67
+ tokenCount: 5
68
+ promptTokenCount: 23
69
+ promptTokensDetails:
70
+ - modality: TEXT
71
+ tokenCount: 23
72
+ totalTokenCount: 28
73
+ status:
74
+ code: 200
75
+ message: OK
76
+ - request:
77
+ headers:
78
+ accept:
79
+ - '*/*'
80
+ accept-encoding:
81
+ - gzip, deflate
82
+ connection:
83
+ - keep-alive
84
+ content-length:
85
+ - '519'
86
+ content-type:
87
+ - application/json
88
+ host:
89
+ - generativelanguage.googleapis.com
90
+ method: POST
91
+ parsed_body:
92
+ contents:
93
+ - parts:
94
+ - text: What is the capital of France?
95
+ role: user
96
+ - parts:
97
+ - functionCall:
98
+ args:
99
+ country: France
100
+ name: get_capital
101
+ role: model
102
+ - parts:
103
+ - functionResponse:
104
+ name: get_capital
105
+ response:
106
+ return_value: Paris
107
+ role: user
108
+ tools:
109
+ function_declarations:
110
+ - description: Get the capital of a country.
111
+ name: get_capital
112
+ parameters:
113
+ properties:
114
+ country:
115
+ description: The country name.
116
+ type: string
117
+ required:
118
+ - country
119
+ type: object
120
+ uri: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent
121
+ response:
122
+ headers:
123
+ alt-svc:
124
+ - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
125
+ content-length:
126
+ - '640'
127
+ content-type:
128
+ - application/json; charset=UTF-8
129
+ server-timing:
130
+ - gfet4t7; dur=381
131
+ transfer-encoding:
132
+ - chunked
133
+ vary:
134
+ - Origin
135
+ - X-Origin
136
+ - Referer
137
+ parsed_body:
138
+ candidates:
139
+ - avgLogprobs: 5.035180947743356e-07
140
+ content:
141
+ parts:
142
+ - text: |
143
+ The capital of France is Paris.
144
+ role: model
145
+ finishReason: STOP
146
+ modelVersion: gemini-2.0-flash-exp
147
+ usageMetadata:
148
+ candidatesTokenCount: 8
149
+ candidatesTokensDetails:
150
+ - modality: TEXT
151
+ tokenCount: 8
152
+ promptTokenCount: 35
153
+ promptTokensDetails:
154
+ - modality: TEXT
155
+ tokenCount: 35
156
+ totalTokenCount: 43
157
+ status:
158
+ code: 200
159
+ message: OK
160
+ - request:
161
+ headers:
162
+ accept:
163
+ - application/json
164
+ accept-encoding:
165
+ - gzip, deflate
166
+ connection:
167
+ - keep-alive
168
+ content-length:
169
+ - '801'
170
+ content-type:
171
+ - application/json
172
+ host:
173
+ - api.openai.com
174
+ method: POST
175
+ parsed_body:
176
+ messages:
177
+ - content: What is the capital of France?
178
+ role: user
179
+ - role: assistant
180
+ tool_calls:
181
+ - function:
182
+ arguments: '{"country":"France"}'
183
+ name: get_capital
184
+ id: pyd_ai_504f8147f83f44f3a5f14d87bfd01bda
185
+ type: function
186
+ - content: Paris
187
+ role: tool
188
+ tool_call_id: pyd_ai_504f8147f83f44f3a5f14d87bfd01bda
189
+ - content: |
190
+ The capital of France is Paris.
191
+ role: assistant
192
+ - content: What is the capital of England?
193
+ role: user
194
+ model: gpt-4o-mini
195
+ n: 1
196
+ stream: false
197
+ tool_choice: auto
198
+ tools:
199
+ - function:
200
+ description: Get the capital of a country.
201
+ name: get_capital
202
+ parameters:
203
+ additionalProperties: false
204
+ properties:
205
+ country:
206
+ description: The country name.
207
+ type: string
208
+ required:
209
+ - country
210
+ type: object
211
+ type: function
212
+ uri: https://api.openai.com/v1/chat/completions
213
+ response:
214
+ headers:
215
+ access-control-expose-headers:
216
+ - X-Request-ID
217
+ alt-svc:
218
+ - h3=":443"; ma=86400
219
+ connection:
220
+ - keep-alive
221
+ content-length:
222
+ - '1091'
223
+ content-type:
224
+ - application/json
225
+ openai-organization:
226
+ - pydantic-28gund
227
+ openai-processing-ms:
228
+ - '784'
229
+ openai-version:
230
+ - '2020-10-01'
231
+ strict-transport-security:
232
+ - max-age=31536000; includeSubDomains; preload
233
+ transfer-encoding:
234
+ - chunked
235
+ parsed_body:
236
+ choices:
237
+ - finish_reason: tool_calls
238
+ index: 0
239
+ logprobs: null
240
+ message:
241
+ annotations: []
242
+ content: null
243
+ refusal: null
244
+ role: assistant
245
+ tool_calls:
246
+ - function:
247
+ arguments: '{"country":"England"}'
248
+ name: get_capital
249
+ id: call_SkEQ3ZGSJC8m6AvaIGNuuKdm
250
+ type: function
251
+ created: 1742842885
252
+ id: chatcmpl-BEhL3fZWgTz2Z57jXexYbQPsOBUm3
253
+ model: gpt-4o-mini-2024-07-18
254
+ object: chat.completion
255
+ service_tier: default
256
+ system_fingerprint: fp_b8bc95a0ac
257
+ usage:
258
+ completion_tokens: 16
259
+ completion_tokens_details:
260
+ accepted_prediction_tokens: 0
261
+ audio_tokens: 0
262
+ reasoning_tokens: 0
263
+ rejected_prediction_tokens: 0
264
+ prompt_tokens: 104
265
+ prompt_tokens_details:
266
+ audio_tokens: 0
267
+ cached_tokens: 0
268
+ total_tokens: 120
269
+ status:
270
+ code: 200
271
+ message: OK
272
+ - request:
273
+ headers:
274
+ accept:
275
+ - application/json
276
+ accept-encoding:
277
+ - gzip, deflate
278
+ connection:
279
+ - keep-alive
280
+ content-length:
281
+ - '1050'
282
+ content-type:
283
+ - application/json
284
+ cookie:
285
+ - __cf_bm=fEZONI5B238kQ6OXHK13zgt8ywFP33X_T.Rj7kOX_.U-1742842886-1.0.1.1-Qx39nivaihVZJFeyQKfx9cVGl_qxdo0BULRdHDhZN7JckuOkQmjCwesvWu7fLNf8qR8oZBKufDsfLmg4lUd3l314ZvU8xxx44rgtJTHVQTM;
286
+ _cfuvid=6dZO7_a2pjh.BwMhl506o0zCkNlkhADPSV7Hxx2Pqks-1742842886619-0.0.1.1-604800000
287
+ host:
288
+ - api.openai.com
289
+ method: POST
290
+ parsed_body:
291
+ messages:
292
+ - content: What is the capital of France?
293
+ role: user
294
+ - role: assistant
295
+ tool_calls:
296
+ - function:
297
+ arguments: '{"country":"France"}'
298
+ name: get_capital
299
+ id: pyd_ai_504f8147f83f44f3a5f14d87bfd01bda
300
+ type: function
301
+ - content: Paris
302
+ role: tool
303
+ tool_call_id: pyd_ai_504f8147f83f44f3a5f14d87bfd01bda
304
+ - content: |
305
+ The capital of France is Paris.
306
+ role: assistant
307
+ - content: What is the capital of England?
308
+ role: user
309
+ - role: assistant
310
+ tool_calls:
311
+ - function:
312
+ arguments: '{"country":"England"}'
313
+ name: get_capital
314
+ id: call_SkEQ3ZGSJC8m6AvaIGNuuKdm
315
+ type: function
316
+ - content: London
317
+ role: tool
318
+ tool_call_id: call_SkEQ3ZGSJC8m6AvaIGNuuKdm
319
+ model: gpt-4o-mini
320
+ n: 1
321
+ stream: false
322
+ tool_choice: auto
323
+ tools:
324
+ - function:
325
+ description: Get the capital of a country.
326
+ name: get_capital
327
+ parameters:
328
+ additionalProperties: false
329
+ properties:
330
+ country:
331
+ description: The country name.
332
+ type: string
333
+ required:
334
+ - country
335
+ type: object
336
+ type: function
337
+ uri: https://api.openai.com/v1/chat/completions
338
+ response:
339
+ headers:
340
+ access-control-expose-headers:
341
+ - X-Request-ID
342
+ alt-svc:
343
+ - h3=":443"; ma=86400
344
+ connection:
345
+ - keep-alive
346
+ content-length:
347
+ - '841'
348
+ content-type:
349
+ - application/json
350
+ openai-organization:
351
+ - pydantic-28gund
352
+ openai-processing-ms:
353
+ - '456'
354
+ openai-version:
355
+ - '2020-10-01'
356
+ strict-transport-security:
357
+ - max-age=31536000; includeSubDomains; preload
358
+ transfer-encoding:
359
+ - chunked
360
+ parsed_body:
361
+ choices:
362
+ - finish_reason: stop
363
+ index: 0
364
+ logprobs: null
365
+ message:
366
+ annotations: []
367
+ content: The capital of England is London.
368
+ refusal: null
369
+ role: assistant
370
+ created: 1742842886
371
+ id: chatcmpl-BEhL4jHN01U9VPVVYzgKrwORTJ0Pw
372
+ model: gpt-4o-mini-2024-07-18
373
+ object: chat.completion
374
+ service_tier: default
375
+ system_fingerprint: fp_b8bc95a0ac
376
+ usage:
377
+ completion_tokens: 9
378
+ completion_tokens_details:
379
+ accepted_prediction_tokens: 0
380
+ audio_tokens: 0
381
+ reasoning_tokens: 0
382
+ rejected_prediction_tokens: 0
383
+ prompt_tokens: 129
384
+ prompt_tokens_details:
385
+ audio_tokens: 0
386
+ cached_tokens: 0
387
+ total_tokens: 138
388
+ status:
389
+ code: 200
390
+ message: OK
391
+ version: 1
@@ -11,9 +11,6 @@ interactions:
11
11
  - '149'
12
12
  content-type:
13
13
  - application/json
14
- cookie:
15
- - __cf_bm=k1xoKY2.Jtgshh4aAfJbgzfCta3eg2_pKpOubx52AqY-1740396355-1.0.1.1-piAnJhOpL2bGY4paQ8VURT3k0nvStOyXvtsja2kOYPgRmSNpE1vUf87UU.AnB_di_8lc63rtIkZjSJSSZPPgDQ;
16
- _cfuvid=9Q7wbAVWuVxqmo8CZYy4FZvphfjrBGzqwRIt0TKETsE-1740396355005-0.0.1.1-604800000
17
14
  host:
18
15
  - api.openai.com
19
16
  method: POST
@@ -42,7 +39,7 @@ interactions:
42
39
  openai-organization:
43
40
  - pydantic-28gund
44
41
  openai-processing-ms:
45
- - '23'
42
+ - '36'
46
43
  openai-version:
47
44
  - '2020-10-01'
48
45
  strict-transport-security:
@@ -39,14 +39,9 @@ interactions:
39
39
  openai-organization:
40
40
  - pydantic-28gund
41
41
  openai-processing-ms:
42
- - '15'
42
+ - '157'
43
43
  openai-version:
44
44
  - '2020-10-01'
45
- set-cookie:
46
- - __cf_bm=k1xoKY2.Jtgshh4aAfJbgzfCta3eg2_pKpOubx52AqY-1740396355-1.0.1.1-piAnJhOpL2bGY4paQ8VURT3k0nvStOyXvtsja2kOYPgRmSNpE1vUf87UU.AnB_di_8lc63rtIkZjSJSSZPPgDQ;
47
- path=/; expires=Mon, 24-Feb-25 11:55:55 GMT; domain=.api.openai.com; HttpOnly; Secure; SameSite=None
48
- - _cfuvid=9Q7wbAVWuVxqmo8CZYy4FZvphfjrBGzqwRIt0TKETsE-1740396355005-0.0.1.1-604800000; path=/; domain=.api.openai.com;
49
- HttpOnly; Secure; SameSite=None
50
45
  strict-transport-security:
51
46
  - max-age=31536000; includeSubDomains; preload
52
47
  parsed_body:
@@ -0,0 +1,79 @@
1
+ interactions:
2
+ - request:
3
+ headers:
4
+ accept:
5
+ - application/json
6
+ accept-encoding:
7
+ - gzip, deflate
8
+ connection:
9
+ - keep-alive
10
+ content-length:
11
+ - '103'
12
+ content-type:
13
+ - application/json
14
+ host:
15
+ - api.openai.com
16
+ method: POST
17
+ parsed_body:
18
+ messages:
19
+ - content: hello
20
+ role: user
21
+ model: gpt-4o
22
+ n: 1
23
+ stream: false
24
+ user: user_id
25
+ uri: https://api.openai.com/v1/chat/completions
26
+ response:
27
+ headers:
28
+ access-control-expose-headers:
29
+ - X-Request-ID
30
+ alt-svc:
31
+ - h3=":443"; ma=86400
32
+ connection:
33
+ - keep-alive
34
+ content-length:
35
+ - '835'
36
+ content-type:
37
+ - application/json
38
+ openai-organization:
39
+ - pydantic-28gund
40
+ openai-processing-ms:
41
+ - '235'
42
+ openai-version:
43
+ - '2020-10-01'
44
+ strict-transport-security:
45
+ - max-age=31536000; includeSubDomains; preload
46
+ transfer-encoding:
47
+ - chunked
48
+ parsed_body:
49
+ choices:
50
+ - finish_reason: stop
51
+ index: 0
52
+ logprobs: null
53
+ message:
54
+ annotations: []
55
+ content: Hello! How can I assist you today?
56
+ refusal: null
57
+ role: assistant
58
+ created: 1742906323
59
+ id: chatcmpl-BExqF10T3Bt833bEyp7OAqjVznPeS
60
+ model: gpt-4o-2024-08-06
61
+ object: chat.completion
62
+ service_tier: default
63
+ system_fingerprint: fp_90d33c15d4
64
+ usage:
65
+ completion_tokens: 10
66
+ completion_tokens_details:
67
+ accepted_prediction_tokens: 0
68
+ audio_tokens: 0
69
+ reasoning_tokens: 0
70
+ rejected_prediction_tokens: 0
71
+ prompt_tokens: 8
72
+ prompt_tokens_details:
73
+ audio_tokens: 0
74
+ cached_tokens: 0
75
+ total_tokens: 18
76
+ status:
77
+ code: 200
78
+ message: OK
79
+ version: 1
@@ -7,7 +7,6 @@ from dataclasses import dataclass, field
7
7
  from datetime import timezone
8
8
  from functools import cached_property
9
9
  from typing import Any, TypeVar, Union, cast
10
- from unittest.mock import patch
11
10
 
12
11
  import httpx
13
12
  import pytest
@@ -30,7 +29,7 @@ from pydantic_ai.messages import (
30
29
  from pydantic_ai.result import Usage
31
30
  from pydantic_ai.settings import ModelSettings
32
31
 
33
- from ..conftest import IsDatetime, IsNow, IsStr, raise_if_exception, try_import
32
+ from ..conftest import IsDatetime, IsNow, IsStr, TestEnv, raise_if_exception, try_import
34
33
  from .mock_async_stream import MockAsyncStream
35
34
 
36
35
  with try_import() as imports_successful:
@@ -680,8 +679,8 @@ def test_init_with_provider():
680
679
  assert model.client == provider.client
681
680
 
682
681
 
683
- def test_init_with_provider_string():
684
- with patch.dict(os.environ, {'ANTHROPIC_API_KEY': 'env-api-key'}, clear=False):
685
- model = AnthropicModel('claude-3-opus-latest', provider='anthropic')
686
- assert model.model_name == 'claude-3-opus-latest'
687
- assert model.client is not None
682
+ def test_init_with_provider_string(env: TestEnv):
683
+ env.set('ANTHROPIC_API_KEY', 'env-api-key')
684
+ model = AnthropicModel('claude-3-opus-latest', provider='anthropic')
685
+ assert model.model_name == 'claude-3-opus-latest'
686
+ assert model.client is not None