pydantic-ai 0.0.42__tar.gz → 0.0.44__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 (105) hide show
  1. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/PKG-INFO +3 -3
  2. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/pyproject.toml +3 -3
  3. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/conftest.py +5 -0
  4. pydantic_ai-0.0.44/tests/graph/test_utils.py +20 -0
  5. pydantic_ai-0.0.44/tests/models/cassettes/test_cohere/test_request_simple_success_with_vcr.yaml +64 -0
  6. pydantic_ai-0.0.44/tests/models/cassettes/test_openai/test_max_completion_tokens[gpt-4.5-preview].yaml +78 -0
  7. pydantic_ai-0.0.44/tests/models/cassettes/test_openai/test_max_completion_tokens[gpt-4o-mini].yaml +79 -0
  8. pydantic_ai-0.0.44/tests/models/cassettes/test_openai/test_max_completion_tokens[o3-mini].yaml +78 -0
  9. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_anthropic.py +1 -1
  10. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_bedrock.py +12 -3
  11. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_cohere.py +17 -8
  12. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_fallback.py +4 -2
  13. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_gemini.py +1 -1
  14. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_groq.py +1 -1
  15. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_instrumented.py +8 -1
  16. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_mistral.py +6 -6
  17. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_model_function.py +1 -1
  18. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_openai.py +12 -2
  19. pydantic_ai-0.0.44/tests/providers/test_cohere.py +54 -0
  20. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/providers/test_google_vertex.py +6 -5
  21. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/providers/test_provider_names.py +2 -0
  22. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_agent.py +15 -10
  23. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_examples.py +2 -0
  24. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_logfire.py +25 -4
  25. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_tools.py +148 -8
  26. pydantic_ai-0.0.42/tests/graph/test_utils.py +0 -13
  27. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/.gitignore +0 -0
  28. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/LICENSE +0 -0
  29. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/Makefile +0 -0
  30. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/README.md +0 -0
  31. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/__init__.py +0 -0
  32. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/assets/dummy.pdf +0 -0
  33. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/assets/kiwi.png +0 -0
  34. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/assets/marcelo.mp3 +0 -0
  35. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/cassettes/test_mcp/test_agent_with_stdio_server.yaml +0 -0
  36. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/example_modules/README.md +0 -0
  37. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/example_modules/bank_database.py +0 -0
  38. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/example_modules/fake_database.py +0 -0
  39. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/example_modules/weather_service.py +0 -0
  40. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/graph/__init__.py +0 -0
  41. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/graph/test_file_persistence.py +0 -0
  42. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/graph/test_graph.py +0 -0
  43. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/graph/test_mermaid.py +0 -0
  44. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/graph/test_persistence.py +0 -0
  45. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/graph/test_state.py +0 -0
  46. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/import_examples.py +0 -0
  47. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/json_body_serializer.py +0 -0
  48. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/mcp_server.py +0 -0
  49. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/__init__.py +0 -0
  50. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_anthropic/test_document_binary_content_input.yaml +0 -0
  51. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_anthropic/test_document_url_input.yaml +0 -0
  52. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_anthropic/test_image_url_input.yaml +0 -0
  53. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_anthropic/test_image_url_input_invalid_mime_type.yaml +0 -0
  54. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_anthropic/test_multiple_parallel_tool_calls.yaml +0 -0
  55. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_anthropic/test_text_document_url_input.yaml +0 -0
  56. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_bedrock/test_bedrock_model.yaml +0 -0
  57. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_bedrock/test_bedrock_model_anthropic_model_without_tools.yaml +0 -0
  58. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_bedrock/test_bedrock_model_iter_stream.yaml +0 -0
  59. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_bedrock/test_bedrock_model_max_tokens.yaml +0 -0
  60. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_bedrock/test_bedrock_model_retry.yaml +0 -0
  61. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_bedrock/test_bedrock_model_stream.yaml +0 -0
  62. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_bedrock/test_bedrock_model_structured_response.yaml +0 -0
  63. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_bedrock/test_bedrock_model_top_p.yaml +0 -0
  64. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_bedrock/test_document_url_input.yaml +0 -0
  65. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_bedrock/test_image_as_binary_content_input.yaml +0 -0
  66. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_bedrock/test_image_url_input.yaml +0 -0
  67. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_bedrock/test_text_as_binary_content_input.yaml +0 -0
  68. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_bedrock/test_text_document_url_input.yaml +0 -0
  69. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_gemini/test_document_url_input.yaml +0 -0
  70. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_gemini/test_image_as_binary_content_input.yaml +0 -0
  71. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_gemini/test_image_url_input.yaml +0 -0
  72. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_groq/test_image_as_binary_content_input.yaml +0 -0
  73. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_groq/test_image_url_input.yaml +0 -0
  74. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_openai/test_audio_as_binary_content_input.yaml +0 -0
  75. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_openai/test_document_url_input.yaml +0 -0
  76. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_openai/test_image_as_binary_content_input.yaml +0 -0
  77. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_openai/test_openai_o1_mini_system_role[developer].yaml +0 -0
  78. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/cassettes/test_openai/test_openai_o1_mini_system_role[system].yaml +0 -0
  79. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/mock_async_stream.py +0 -0
  80. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_model.py +0 -0
  81. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_model_names.py +0 -0
  82. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_model_test.py +0 -0
  83. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/models/test_vertexai.py +0 -0
  84. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/providers/__init__.py +0 -0
  85. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/providers/cassettes/test_azure/test_azure_provider_call.yaml +0 -0
  86. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/providers/test_anthropic.py +0 -0
  87. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/providers/test_azure.py +0 -0
  88. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/providers/test_bedrock.py +0 -0
  89. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/providers/test_deepseek.py +0 -0
  90. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/providers/test_google_gla.py +0 -0
  91. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/providers/test_groq.py +0 -0
  92. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/providers/test_mistral.py +0 -0
  93. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_cli.py +0 -0
  94. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_deps.py +0 -0
  95. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_format_as_xml.py +0 -0
  96. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_json_body_serializer.py +0 -0
  97. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_live.py +0 -0
  98. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_mcp.py +0 -0
  99. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_messages.py +0 -0
  100. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_parts_manager.py +0 -0
  101. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_streaming.py +0 -0
  102. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_usage_limits.py +0 -0
  103. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/test_utils.py +0 -0
  104. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/tests/typed_agent.py +0 -0
  105. {pydantic_ai-0.0.42 → pydantic_ai-0.0.44}/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.42
3
+ Version: 0.0.44
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.42
31
+ Requires-Dist: pydantic-ai-slim[anthropic,bedrock,cli,cohere,groq,mcp,mistral,openai,vertexai]==0.0.44
32
32
  Provides-Extra: examples
33
- Requires-Dist: pydantic-ai-examples==0.0.42; extra == 'examples'
33
+ Requires-Dist: pydantic-ai-examples==0.0.44; 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.42"
7
+ version = "0.0.44"
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.42",
39
+ "pydantic-ai-slim[openai,vertexai,groq,anthropic,mistral,cohere,bedrock,cli,mcp]==0.0.44",
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.42"]
49
+ examples = ["pydantic-ai-examples==0.0.44"]
50
50
  logfire = ["logfire>=2.3"]
51
51
 
52
52
  [tool.uv.sources]
@@ -246,6 +246,11 @@ def anthropic_api_key() -> str:
246
246
  return os.getenv('ANTHROPIC_API_KEY', 'mock-api-key')
247
247
 
248
248
 
249
+ @pytest.fixture(scope='session')
250
+ def co_api_key() -> str:
251
+ return os.getenv('CO_API_KEY', 'mock-api-key')
252
+
253
+
249
254
  @pytest.fixture
250
255
  def mock_snapshot_id(mocker: MockerFixture):
251
256
  i = 0
@@ -0,0 +1,20 @@
1
+ from threading import Thread
2
+
3
+ from pydantic_graph._utils import run_until_complete
4
+
5
+
6
+ def test_run_until_complete_in_main_thread():
7
+ async def run(): ...
8
+
9
+ run_until_complete(run())
10
+
11
+
12
+ def test_run_until_complete_in_thread():
13
+ async def run(): ...
14
+
15
+ def get_and_close_event_loop():
16
+ run_until_complete(run())
17
+
18
+ thread = Thread(target=get_and_close_event_loop)
19
+ thread.start()
20
+ thread.join()
@@ -0,0 +1,64 @@
1
+ interactions:
2
+ - request:
3
+ headers:
4
+ accept:
5
+ - '*/*'
6
+ accept-encoding:
7
+ - gzip, deflate
8
+ connection:
9
+ - keep-alive
10
+ content-length:
11
+ - '93'
12
+ content-type:
13
+ - application/json
14
+ host:
15
+ - api.cohere.com
16
+ method: POST
17
+ parsed_body:
18
+ messages:
19
+ - content: hello
20
+ role: user
21
+ model: command-r7b-12-2024
22
+ stream: false
23
+ uri: https://api.cohere.com/v2/chat
24
+ response:
25
+ headers:
26
+ access-control-expose-headers:
27
+ - X-Debug-Trace-ID
28
+ alt-svc:
29
+ - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
30
+ cache-control:
31
+ - no-cache, no-store, no-transform, must-revalidate, private, max-age=0
32
+ content-length:
33
+ - '286'
34
+ content-type:
35
+ - application/json
36
+ expires:
37
+ - Thu, 01 Jan 1970 00:00:00 UTC
38
+ num_chars:
39
+ - '2583'
40
+ num_tokens:
41
+ - '10'
42
+ pragma:
43
+ - no-cache
44
+ vary:
45
+ - Origin
46
+ parsed_body:
47
+ finish_reason: COMPLETE
48
+ id: f17a5f6c-1734-4098-bd0d-733ef000ac7b
49
+ message:
50
+ content:
51
+ - text: Hello! How can I assist you today?
52
+ type: text
53
+ role: assistant
54
+ usage:
55
+ billed_units:
56
+ input_tokens: 1
57
+ output_tokens: 9
58
+ tokens:
59
+ input_tokens: 496
60
+ output_tokens: 11
61
+ status:
62
+ code: 200
63
+ message: OK
64
+ version: 1
@@ -0,0 +1,78 @@
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
+ - '123'
12
+ content-type:
13
+ - application/json
14
+ host:
15
+ - api.openai.com
16
+ method: POST
17
+ parsed_body:
18
+ max_completion_tokens: 100
19
+ messages:
20
+ - content: hello
21
+ role: user
22
+ model: gpt-4.5-preview
23
+ n: 1
24
+ stream: false
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
+ - '807'
36
+ content-type:
37
+ - application/json
38
+ openai-organization:
39
+ - pydantic-28gund
40
+ openai-processing-ms:
41
+ - '1408'
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
+ message:
53
+ annotations: []
54
+ content: Hello! How can I help you today?
55
+ refusal: null
56
+ role: assistant
57
+ created: 1742636225
58
+ id: chatcmpl-BDpZplWguNLn40wA5mIpCR3OIzvYP
59
+ model: gpt-4.5-preview-2025-02-27
60
+ object: chat.completion
61
+ service_tier: default
62
+ system_fingerprint: null
63
+ usage:
64
+ completion_tokens: 10
65
+ completion_tokens_details:
66
+ accepted_prediction_tokens: 0
67
+ audio_tokens: 0
68
+ reasoning_tokens: 0
69
+ rejected_prediction_tokens: 0
70
+ prompt_tokens: 8
71
+ prompt_tokens_details:
72
+ audio_tokens: 0
73
+ cached_tokens: 0
74
+ total_tokens: 18
75
+ status:
76
+ code: 200
77
+ message: OK
78
+ version: 1
@@ -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
+ - '119'
12
+ content-type:
13
+ - application/json
14
+ host:
15
+ - api.openai.com
16
+ method: POST
17
+ parsed_body:
18
+ max_completion_tokens: 100
19
+ messages:
20
+ - content: hello
21
+ role: user
22
+ model: gpt-4o-mini
23
+ n: 1
24
+ stream: false
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
+ - '840'
36
+ content-type:
37
+ - application/json
38
+ openai-organization:
39
+ - pydantic-28gund
40
+ openai-processing-ms:
41
+ - '278'
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: 1742636224
59
+ id: chatcmpl-BDpZoxw4i90ZesN8iyrwLmGWRJ5lz
60
+ model: gpt-4o-mini-2024-07-18
61
+ object: chat.completion
62
+ service_tier: default
63
+ system_fingerprint: fp_b8bc95a0ac
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
@@ -0,0 +1,78 @@
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
+ - '115'
12
+ content-type:
13
+ - application/json
14
+ host:
15
+ - api.openai.com
16
+ method: POST
17
+ parsed_body:
18
+ max_completion_tokens: 100
19
+ messages:
20
+ - content: hello
21
+ role: user
22
+ model: o3-mini
23
+ n: 1
24
+ stream: false
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
+ - '817'
36
+ content-type:
37
+ - application/json
38
+ openai-organization:
39
+ - pydantic-28gund
40
+ openai-processing-ms:
41
+ - '1895'
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
+ message:
53
+ annotations: []
54
+ content: Hello there! How can I help you today?
55
+ refusal: null
56
+ role: assistant
57
+ created: 1742636222
58
+ id: chatcmpl-BDpZm1SiItIXIcDA0xRV9QGZhD97e
59
+ model: o3-mini-2025-01-31
60
+ object: chat.completion
61
+ service_tier: default
62
+ system_fingerprint: fp_617f206dd9
63
+ usage:
64
+ completion_tokens: 85
65
+ completion_tokens_details:
66
+ accepted_prediction_tokens: 0
67
+ audio_tokens: 0
68
+ reasoning_tokens: 64
69
+ rejected_prediction_tokens: 0
70
+ prompt_tokens: 7
71
+ prompt_tokens_details:
72
+ audio_tokens: 0
73
+ cached_tokens: 0
74
+ total_tokens: 92
75
+ status:
76
+ code: 200
77
+ message: OK
78
+ version: 1
@@ -254,7 +254,7 @@ async def test_request_tool_call(allow_model_requests: None):
254
254
  [
255
255
  ModelRequest(
256
256
  parts=[
257
- SystemPromptPart(content='this is the system prompt'),
257
+ SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)),
258
258
  UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc)),
259
259
  ]
260
260
  ),
@@ -73,7 +73,10 @@ async def test_bedrock_model(allow_model_requests: None, bedrock_provider: Bedro
73
73
  [
74
74
  ModelRequest(
75
75
  parts=[
76
- SystemPromptPart(content='You are a chatbot.'),
76
+ SystemPromptPart(
77
+ content='You are a chatbot.',
78
+ timestamp=IsDatetime(),
79
+ ),
77
80
  UserPromptPart(
78
81
  content='Hello!',
79
82
  timestamp=IsDatetime(),
@@ -122,7 +125,10 @@ async def test_bedrock_model_structured_response(allow_model_requests: None, bed
122
125
  [
123
126
  ModelRequest(
124
127
  parts=[
125
- SystemPromptPart(content='You are a helpful chatbot.'),
128
+ SystemPromptPart(
129
+ content='You are a helpful chatbot.',
130
+ timestamp=IsDatetime(),
131
+ ),
126
132
  UserPromptPart(
127
133
  content='What was the temperature in London 1st January 2022?',
128
134
  timestamp=IsDatetime(),
@@ -242,7 +248,10 @@ async def test_bedrock_model_retry(allow_model_requests: None, bedrock_provider:
242
248
  [
243
249
  ModelRequest(
244
250
  parts=[
245
- SystemPromptPart(content='You are a helpful chatbot.'),
251
+ SystemPromptPart(
252
+ content='You are a helpful chatbot.',
253
+ timestamp=IsDatetime(),
254
+ ),
246
255
  UserPromptPart(
247
256
  content='What is the capital of France?',
248
257
  timestamp=IsDatetime(),
@@ -38,6 +38,7 @@ with try_import() as imports_successful:
38
38
  from cohere.core.api_error import ApiError
39
39
 
40
40
  from pydantic_ai.models.cohere import CohereModel
41
+ from pydantic_ai.providers.cohere import CohereProvider
41
42
 
42
43
  # note: we use Union here for compatibility with Python 3.9
43
44
  MockChatResponse = Union[ChatResponse, Exception]
@@ -49,7 +50,7 @@ pytestmark = [
49
50
 
50
51
 
51
52
  def test_init():
52
- m = CohereModel('command-r7b-12-2024', api_key='foobar')
53
+ m = CohereModel('command-r7b-12-2024', provider=CohereProvider(api_key='foobar'))
53
54
  assert m.model_name == 'command-r7b-12-2024'
54
55
  assert m.system == 'cohere'
55
56
  assert m.base_url == 'https://api.cohere.com'
@@ -96,7 +97,7 @@ async def test_request_simple_success(allow_model_requests: None):
96
97
  )
97
98
  )
98
99
  mock_client = MockAsyncClientV2.create_mock(c)
99
- m = CohereModel('command-r7b-12-2024', cohere_client=mock_client)
100
+ m = CohereModel('command-r7b-12-2024', provider=CohereProvider(cohere_client=mock_client))
100
101
  agent = Agent(m)
101
102
 
102
103
  result = await agent.run('hello')
@@ -135,7 +136,7 @@ async def test_request_simple_usage(allow_model_requests: None):
135
136
  ),
136
137
  )
137
138
  mock_client = MockAsyncClientV2.create_mock(c)
138
- m = CohereModel('command-r7b-12-2024', cohere_client=mock_client)
139
+ m = CohereModel('command-r7b-12-2024', provider=CohereProvider(cohere_client=mock_client))
139
140
  agent = Agent(m)
140
141
 
141
142
  result = await agent.run('Hello')
@@ -169,7 +170,7 @@ async def test_request_structured_response(allow_model_requests: None):
169
170
  )
170
171
  )
171
172
  mock_client = MockAsyncClientV2.create_mock(c)
172
- m = CohereModel('command-r7b-12-2024', cohere_client=mock_client)
173
+ m = CohereModel('command-r7b-12-2024', provider=CohereProvider(cohere_client=mock_client))
173
174
  agent = Agent(m, result_type=list[int])
174
175
 
175
176
  result = await agent.run('Hello')
@@ -243,7 +244,7 @@ async def test_request_tool_call(allow_model_requests: None):
243
244
  ),
244
245
  ]
245
246
  mock_client = MockAsyncClientV2.create_mock(responses)
246
- m = CohereModel('command-r7b-12-2024', cohere_client=mock_client)
247
+ m = CohereModel('command-r7b-12-2024', provider=CohereProvider(cohere_client=mock_client))
247
248
  agent = Agent(m, system_prompt='this is the system prompt')
248
249
 
249
250
  @agent.tool_plain
@@ -259,7 +260,7 @@ async def test_request_tool_call(allow_model_requests: None):
259
260
  [
260
261
  ModelRequest(
261
262
  parts=[
262
- SystemPromptPart(content='this is the system prompt'),
263
+ SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)),
263
264
  UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)),
264
265
  ]
265
266
  ),
@@ -326,7 +327,7 @@ async def test_request_tool_call(allow_model_requests: None):
326
327
  async def test_multimodal(allow_model_requests: None):
327
328
  c = completion_message(AssistantMessageResponse(content=[TextAssistantMessageResponseContentItem(text='world')]))
328
329
  mock_client = MockAsyncClientV2.create_mock(c)
329
- m = CohereModel('command-r7b-12-2024', cohere_client=mock_client)
330
+ m = CohereModel('command-r7b-12-2024', provider=CohereProvider(cohere_client=mock_client))
330
331
  agent = Agent(m)
331
332
 
332
333
  with pytest.raises(RuntimeError, match='Cohere does not yet support multi-modal inputs.'):
@@ -347,8 +348,16 @@ def test_model_status_error(allow_model_requests: None) -> None:
347
348
  body={'error': 'test error'},
348
349
  )
349
350
  )
350
- m = CohereModel('command-r', cohere_client=mock_client)
351
+ m = CohereModel('command-r', provider=CohereProvider(cohere_client=mock_client))
351
352
  agent = Agent(m)
352
353
  with pytest.raises(ModelHTTPError) as exc_info:
353
354
  agent.run_sync('hello')
354
355
  assert str(exc_info.value) == snapshot("status_code: 500, model_name: command-r, body: {'error': 'test error'}")
356
+
357
+
358
+ @pytest.mark.vcr()
359
+ async def test_request_simple_success_with_vcr(allow_model_requests: None, co_api_key: str):
360
+ m = CohereModel('command-r7b-12-2024', provider=CohereProvider(api_key=co_api_key))
361
+ agent = Agent(m)
362
+ result = await agent.run('hello')
363
+ assert result.data == snapshot('Hello! How can I assist you today?')
@@ -136,6 +136,7 @@ def test_first_failed_instrumented(capfire: CaptureLogfire) -> None:
136
136
  'end_time': 5000000000,
137
137
  'attributes': {
138
138
  'gen_ai.operation.name': 'chat',
139
+ 'model_request_parameters': '{"function_tools": [], "allow_text_result": true, "result_tools": []}',
139
140
  'logfire.span_type': 'span',
140
141
  'logfire.msg': 'chat fallback:function:failure_response:,function:success_response:',
141
142
  'gen_ai.usage.input_tokens': 51,
@@ -160,7 +161,7 @@ def test_first_failed_instrumented(capfire: CaptureLogfire) -> None:
160
161
  },
161
162
  ]
162
163
  ),
163
- 'logfire.json_schema': '{"type": "object", "properties": {"events": {"type": "array"}}}',
164
+ 'logfire.json_schema': '{"type": "object", "properties": {"events": {"type": "array"}, "model_request_parameters": {"type": "object"}}}',
164
165
  },
165
166
  },
166
167
  {
@@ -233,6 +234,7 @@ async def test_first_failed_instrumented_stream(capfire: CaptureLogfire) -> None
233
234
  'end_time': 5000000000,
234
235
  'attributes': {
235
236
  'gen_ai.operation.name': 'chat',
237
+ 'model_request_parameters': '{"function_tools": [], "allow_text_result": true, "result_tools": []}',
236
238
  'logfire.span_type': 'span',
237
239
  'logfire.msg': 'chat fallback:function::failure_response_stream,function::success_response_stream',
238
240
  'gen_ai.system': 'function',
@@ -241,7 +243,7 @@ async def test_first_failed_instrumented_stream(capfire: CaptureLogfire) -> None
241
243
  'gen_ai.usage.output_tokens': 2,
242
244
  'gen_ai.response.model': 'function::success_response_stream',
243
245
  'events': '[{"content": "input", "role": "user", "gen_ai.system": "function", "gen_ai.message.index": 0, "event.name": "gen_ai.user.message"}, {"index": 0, "message": {"role": "assistant", "content": "hello world"}, "gen_ai.system": "function", "event.name": "gen_ai.choice"}]',
244
- 'logfire.json_schema': '{"type": "object", "properties": {"events": {"type": "array"}}}',
246
+ 'logfire.json_schema': '{"type": "object", "properties": {"events": {"type": "array"}, "model_request_parameters": {"type": "object"}}}',
245
247
  },
246
248
  },
247
249
  {
@@ -559,7 +559,7 @@ async def test_request_tool_call(get_gemini_client: GetGeminiClient):
559
559
  [
560
560
  ModelRequest(
561
561
  parts=[
562
- SystemPromptPart(content='this is the system prompt'),
562
+ SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)),
563
563
  UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)),
564
564
  ]
565
565
  ),
@@ -273,7 +273,7 @@ async def test_request_tool_call(allow_model_requests: None):
273
273
  [
274
274
  ModelRequest(
275
275
  parts=[
276
- SystemPromptPart(content='this is the system prompt'),
276
+ SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)),
277
277
  UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)),
278
278
  ]
279
279
  ),
@@ -152,6 +152,8 @@ async def test_instrumented_model(capfire: CaptureLogfire):
152
152
  'gen_ai.request.model': 'my_model',
153
153
  'server.address': 'example.com',
154
154
  'server.port': 8000,
155
+ 'model_request_parameters': '{"function_tools": [], "allow_text_result": true, "result_tools": []}',
156
+ 'logfire.json_schema': '{"type": "object", "properties": {"model_request_parameters": {"type": "object"}}}',
155
157
  'gen_ai.request.temperature': 1,
156
158
  'logfire.msg': 'chat my_model',
157
159
  'logfire.span_type': 'span',
@@ -374,6 +376,8 @@ async def test_instrumented_model_stream(capfire: CaptureLogfire):
374
376
  'gen_ai.request.model': 'my_model',
375
377
  'server.address': 'example.com',
376
378
  'server.port': 8000,
379
+ 'model_request_parameters': '{"function_tools": [], "allow_text_result": true, "result_tools": []}',
380
+ 'logfire.json_schema': '{"type": "object", "properties": {"model_request_parameters": {"type": "object"}}}',
377
381
  'gen_ai.request.temperature': 1,
378
382
  'logfire.msg': 'chat my_model',
379
383
  'logfire.span_type': 'span',
@@ -457,6 +461,8 @@ async def test_instrumented_model_stream_break(capfire: CaptureLogfire):
457
461
  'gen_ai.request.model': 'my_model',
458
462
  'server.address': 'example.com',
459
463
  'server.port': 8000,
464
+ 'model_request_parameters': '{"function_tools": [], "allow_text_result": true, "result_tools": []}',
465
+ 'logfire.json_schema': '{"type": "object", "properties": {"model_request_parameters": {"type": "object"}}}',
460
466
  'gen_ai.request.temperature': 1,
461
467
  'logfire.msg': 'chat my_model',
462
468
  'logfire.span_type': 'span',
@@ -559,6 +565,7 @@ async def test_instrumented_model_attributes_mode(capfire: CaptureLogfire):
559
565
  'gen_ai.request.model': 'my_model',
560
566
  'server.address': 'example.com',
561
567
  'server.port': 8000,
568
+ 'model_request_parameters': '{"function_tools": [], "allow_text_result": true, "result_tools": []}',
562
569
  'gen_ai.request.temperature': 1,
563
570
  'logfire.msg': 'chat my_model',
564
571
  'logfire.span_type': 'span',
@@ -652,7 +659,7 @@ Fix the errors and try again.\
652
659
  ]
653
660
  )
654
661
  ),
655
- 'logfire.json_schema': '{"type": "object", "properties": {"events": {"type": "array"}}}',
662
+ 'logfire.json_schema': '{"type": "object", "properties": {"events": {"type": "array"}, "model_request_parameters": {"type": "object"}}}',
656
663
  },
657
664
  },
658
665
  ]
@@ -504,7 +504,7 @@ async def test_request_result_type_with_arguments_str_response(allow_model_reque
504
504
  [
505
505
  ModelRequest(
506
506
  parts=[
507
- SystemPromptPart(content='System prompt value'),
507
+ SystemPromptPart(content='System prompt value', timestamp=IsNow(tz=timezone.utc)),
508
508
  UserPromptPart(content='User prompt value', timestamp=IsNow(tz=timezone.utc)),
509
509
  ]
510
510
  ),
@@ -1070,7 +1070,7 @@ async def test_request_tool_call(allow_model_requests: None):
1070
1070
  [
1071
1071
  ModelRequest(
1072
1072
  parts=[
1073
- SystemPromptPart(content='this is the system prompt'),
1073
+ SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)),
1074
1074
  UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)),
1075
1075
  ]
1076
1076
  ),
@@ -1207,7 +1207,7 @@ async def test_request_tool_call_with_result_type(allow_model_requests: None):
1207
1207
  [
1208
1208
  ModelRequest(
1209
1209
  parts=[
1210
- SystemPromptPart(content='this is the system prompt'),
1210
+ SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)),
1211
1211
  UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)),
1212
1212
  ]
1213
1213
  ),
@@ -1347,7 +1347,7 @@ async def test_stream_tool_call_with_return_type(allow_model_requests: None):
1347
1347
  [
1348
1348
  ModelRequest(
1349
1349
  parts=[
1350
- SystemPromptPart(content='this is the system prompt'),
1350
+ SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)),
1351
1351
  UserPromptPart(content='User prompt value', timestamp=IsNow(tz=timezone.utc)),
1352
1352
  ]
1353
1353
  ),
@@ -1447,7 +1447,7 @@ async def test_stream_tool_call(allow_model_requests: None):
1447
1447
  [
1448
1448
  ModelRequest(
1449
1449
  parts=[
1450
- SystemPromptPart(content='this is the system prompt'),
1450
+ SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)),
1451
1451
  UserPromptPart(content='User prompt value', timestamp=IsNow(tz=timezone.utc)),
1452
1452
  ]
1453
1453
  ),
@@ -1550,7 +1550,7 @@ async def test_stream_tool_call_with_retry(allow_model_requests: None):
1550
1550
  [
1551
1551
  ModelRequest(
1552
1552
  parts=[
1553
- SystemPromptPart(content='this is the system prompt'),
1553
+ SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)),
1554
1554
  UserPromptPart(content='User prompt value', timestamp=IsNow(tz=timezone.utc)),
1555
1555
  ]
1556
1556
  ),