pydantic-ai 0.0.52__tar.gz → 0.0.54__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 (150) hide show
  1. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/.gitignore +1 -0
  2. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/Makefile +5 -1
  3. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/PKG-INFO +3 -3
  4. pydantic_ai-0.0.54/tests/cassettes/test_settings/test_stop_settings[anthropic].yaml +57 -0
  5. pydantic_ai-0.0.54/tests/cassettes/test_settings/test_stop_settings[bedrock].yaml +43 -0
  6. pydantic_ai-0.0.54/tests/cassettes/test_settings/test_stop_settings[cohere].yaml +66 -0
  7. pydantic_ai-0.0.54/tests/cassettes/test_settings/test_stop_settings[gemini].yaml +60 -0
  8. pydantic_ai-0.0.54/tests/cassettes/test_settings/test_stop_settings[groq].yaml +71 -0
  9. pydantic_ai-0.0.54/tests/cassettes/test_settings/test_stop_settings[mistral].yaml +69 -0
  10. pydantic_ai-0.0.54/tests/cassettes/test_settings/test_stop_settings[openai].yaml +79 -0
  11. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/conftest.py +73 -1
  12. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/test_dataset.py +10 -10
  13. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/test_evaluator_common.py +2 -2
  14. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/test_evaluators.py +33 -0
  15. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/graph/test_graph.py +3 -1
  16. pydantic_ai-0.0.54/tests/models/cassettes/test_bedrock/test_bedrock_empty_system_prompt.yaml +48 -0
  17. pydantic_ai-0.0.54/tests/models/cassettes/test_openai/test_openai_model_without_system_prompt.yaml +78 -0
  18. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_bedrock.py +10 -15
  19. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_gemini.py +24 -19
  20. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_openai.py +507 -2
  21. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/test_google_vertex.py +3 -0
  22. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_logfire.py +1 -0
  23. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_settings.py +16 -0
  24. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_tools.py +16 -0
  25. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_utils.py +43 -11
  26. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/LICENSE +0 -0
  27. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/README.md +0 -0
  28. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/pyproject.toml +0 -0
  29. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/__init__.py +0 -0
  30. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/assets/dummy.pdf +0 -0
  31. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/assets/kiwi.png +0 -0
  32. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/assets/marcelo.mp3 +0 -0
  33. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/cassettes/test_mcp/test_agent_with_stdio_server.yaml +0 -0
  34. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/__init__.py +0 -0
  35. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/test_evaluator_base.py +0 -0
  36. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/test_evaluator_context.py +0 -0
  37. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/test_evaluator_spec.py +0 -0
  38. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/test_llm_as_a_judge.py +0 -0
  39. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/test_otel.py +0 -0
  40. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/test_render_numbers.py +0 -0
  41. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/test_reporting.py +0 -0
  42. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/test_reports.py +0 -0
  43. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/test_utils.py +0 -0
  44. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/evals/utils.py +0 -0
  45. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/example_modules/README.md +0 -0
  46. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/example_modules/bank_database.py +0 -0
  47. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/example_modules/fake_database.py +0 -0
  48. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/example_modules/weather_service.py +0 -0
  49. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/graph/__init__.py +0 -0
  50. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/graph/test_file_persistence.py +0 -0
  51. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/graph/test_mermaid.py +0 -0
  52. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/graph/test_persistence.py +0 -0
  53. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/graph/test_state.py +0 -0
  54. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/graph/test_utils.py +0 -0
  55. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/import_examples.py +0 -0
  56. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/json_body_serializer.py +0 -0
  57. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/mcp_server.py +0 -0
  58. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/__init__.py +0 -0
  59. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_anthropic/test_document_binary_content_input.yaml +0 -0
  60. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_anthropic/test_document_url_input.yaml +0 -0
  61. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_anthropic/test_image_url_input.yaml +0 -0
  62. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_anthropic/test_image_url_input_invalid_mime_type.yaml +0 -0
  63. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_anthropic/test_multiple_parallel_tool_calls.yaml +0 -0
  64. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_anthropic/test_text_document_url_input.yaml +0 -0
  65. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_bedrock/test_bedrock_model.yaml +0 -0
  66. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_bedrock/test_bedrock_model_anthropic_model_without_tools.yaml +0 -0
  67. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_bedrock/test_bedrock_model_iter_stream.yaml +0 -0
  68. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_bedrock/test_bedrock_model_max_tokens.yaml +0 -0
  69. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_bedrock/test_bedrock_model_retry.yaml +0 -0
  70. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_bedrock/test_bedrock_model_stream.yaml +0 -0
  71. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_bedrock/test_bedrock_model_structured_response.yaml +0 -0
  72. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_bedrock/test_bedrock_model_top_p.yaml +0 -0
  73. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_bedrock/test_document_url_input.yaml +0 -0
  74. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_bedrock/test_image_as_binary_content_input.yaml +0 -0
  75. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_bedrock/test_image_url_input.yaml +0 -0
  76. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_bedrock/test_text_as_binary_content_input.yaml +0 -0
  77. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_bedrock/test_text_document_url_input.yaml +0 -0
  78. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_cohere/test_request_simple_success_with_vcr.yaml +0 -0
  79. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_gemini/test_document_url_input.yaml +0 -0
  80. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_gemini/test_gemini_drop_exclusive_maximum.yaml +0 -0
  81. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_gemini/test_gemini_exclusive_minimum_and_maximum.yaml +0 -0
  82. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_gemini/test_image_as_binary_content_input.yaml +0 -0
  83. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_gemini/test_image_url_input.yaml +0 -0
  84. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_groq/test_image_as_binary_content_input.yaml +0 -0
  85. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_groq/test_image_url_input.yaml +0 -0
  86. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai/test_audio_as_binary_content_input.yaml +0 -0
  87. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai/test_document_url_input.yaml +0 -0
  88. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai/test_image_as_binary_content_input.yaml +0 -0
  89. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai/test_max_completion_tokens[gpt-4.5-preview].yaml +0 -0
  90. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai/test_max_completion_tokens[gpt-4o-mini].yaml +0 -0
  91. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai/test_max_completion_tokens[o3-mini].yaml +0 -0
  92. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai/test_multiple_agent_tool_calls.yaml +0 -0
  93. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai/test_openai_o1_mini_system_role[developer].yaml +0 -0
  94. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai/test_openai_o1_mini_system_role[system].yaml +0 -0
  95. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai/test_user_id.yaml +0 -0
  96. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_audio_as_binary_content_input.yaml +0 -0
  97. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_image_as_binary_content_input.yaml +0 -0
  98. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_document_as_binary_content_input.yaml +0 -0
  99. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_document_url_input.yaml +0 -0
  100. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_image_url_input.yaml +0 -0
  101. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_model_builtin_tools.yaml +0 -0
  102. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_model_http_error.yaml +0 -0
  103. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_model_retry.yaml +0 -0
  104. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_model_simple_response.yaml +0 -0
  105. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_model_simple_response_with_tool_call.yaml +0 -0
  106. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_reasoning_effort.yaml +0 -0
  107. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_reasoning_generate_summary.yaml +0 -0
  108. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_result_type.yaml +0 -0
  109. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_stream.yaml +0 -0
  110. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_system_prompt.yaml +0 -0
  111. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/cassettes/test_openai_responses/test_openai_responses_text_document_url_input.yaml +0 -0
  112. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/mock_async_stream.py +0 -0
  113. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_anthropic.py +0 -0
  114. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_cohere.py +0 -0
  115. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_fallback.py +0 -0
  116. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_groq.py +0 -0
  117. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_instrumented.py +0 -0
  118. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_mistral.py +0 -0
  119. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_model.py +0 -0
  120. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_model_function.py +0 -0
  121. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_model_names.py +0 -0
  122. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_model_test.py +0 -0
  123. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/models/test_openai_responses.py +0 -0
  124. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/__init__.py +0 -0
  125. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/cassettes/test_azure/test_azure_provider_call.yaml +0 -0
  126. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/cassettes/test_google_vertex/test_vertexai_provider.yaml +0 -0
  127. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/test_anthropic.py +0 -0
  128. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/test_azure.py +0 -0
  129. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/test_bedrock.py +0 -0
  130. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/test_cohere.py +0 -0
  131. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/test_deepseek.py +0 -0
  132. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/test_google_gla.py +0 -0
  133. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/test_groq.py +0 -0
  134. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/test_mistral.py +0 -0
  135. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/test_openai.py +0 -0
  136. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/providers/test_provider_names.py +0 -0
  137. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_agent.py +0 -0
  138. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_cli.py +0 -0
  139. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_deps.py +0 -0
  140. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_examples.py +0 -0
  141. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_format_as_xml.py +0 -0
  142. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_json_body_serializer.py +0 -0
  143. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_live.py +0 -0
  144. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_mcp.py +0 -0
  145. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_messages.py +0 -0
  146. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_parts_manager.py +0 -0
  147. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_streaming.py +0 -0
  148. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/test_usage_limits.py +0 -0
  149. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/typed_agent.py +0 -0
  150. {pydantic_ai-0.0.52 → pydantic_ai-0.0.54}/tests/typed_graph.py +0 -0
@@ -16,3 +16,4 @@ examples/pydantic_ai_examples/.chat_app_messages.sqlite
16
16
  /question_graph_history.json
17
17
  /docs-site/.wrangler/
18
18
  /CLAUDE.md
19
+ node_modules/
@@ -8,8 +8,12 @@
8
8
  .pre-commit: ## Check that pre-commit is installed
9
9
  @pre-commit -V || echo 'Please install pre-commit: https://pre-commit.com/'
10
10
 
11
+ .PHONY: .deno
12
+ .deno: ## Check that deno is installed
13
+ @deno --version > /dev/null 2>&1 || (printf "\033[0;31m✖ Error: deno is not installed, but is needed for mcp-run-python\033[0m\n Please install deno: https://docs.deno.com/runtime/getting_started/installation/\n" && exit 1)
14
+
11
15
  .PHONY: install
12
- install: .uv .pre-commit ## Install the package, dependencies, and pre-commit for local development
16
+ install: .uv .pre-commit .deno ## Install the package, dependencies, and pre-commit for local development
13
17
  uv sync --frozen --all-extras --all-packages --group lint --group docs
14
18
  pre-commit install --install-hooks
15
19
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-ai
3
- Version: 0.0.52
3
+ Version: 0.0.54
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,evals,groq,mcp,mistral,openai,vertexai]==0.0.52
31
+ Requires-Dist: pydantic-ai-slim[anthropic,bedrock,cli,cohere,evals,groq,mcp,mistral,openai,vertexai]==0.0.54
32
32
  Provides-Extra: examples
33
- Requires-Dist: pydantic-ai-examples==0.0.52; extra == 'examples'
33
+ Requires-Dist: pydantic-ai-examples==0.0.54; extra == 'examples'
34
34
  Provides-Extra: logfire
35
35
  Requires-Dist: logfire>=3.11.0; extra == 'logfire'
36
36
  Description-Content-Type: text/markdown
@@ -0,0 +1,57 @@
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
+ - '193'
12
+ content-type:
13
+ - application/json
14
+ host:
15
+ - api.anthropic.com
16
+ method: POST
17
+ parsed_body:
18
+ max_tokens: 1024
19
+ messages:
20
+ - content:
21
+ - text: What is the capital of France?
22
+ type: text
23
+ role: user
24
+ model: claude-3-5-sonnet-latest
25
+ stop_sequences:
26
+ - Paris
27
+ stream: false
28
+ uri: https://api.anthropic.com/v1/messages
29
+ response:
30
+ headers:
31
+ connection:
32
+ - keep-alive
33
+ content-length:
34
+ - '333'
35
+ content-type:
36
+ - application/json
37
+ transfer-encoding:
38
+ - chunked
39
+ parsed_body:
40
+ content:
41
+ - text: 'The capital of France is '
42
+ type: text
43
+ id: msg_01FfkgikmbDFzn9XE1YYkJmA
44
+ model: claude-3-5-sonnet-20241022
45
+ role: assistant
46
+ stop_reason: stop_sequence
47
+ stop_sequence: Paris
48
+ type: message
49
+ usage:
50
+ cache_creation_input_tokens: 0
51
+ cache_read_input_tokens: 0
52
+ input_tokens: 14
53
+ output_tokens: 6
54
+ status:
55
+ code: 200
56
+ message: OK
57
+ version: 1
@@ -0,0 +1,43 @@
1
+ interactions:
2
+ - request:
3
+ body: '{"messages": [{"role": "user", "content": [{"text": "What is the capital of France?"}]}], "system": [], "inferenceConfig":
4
+ {"stopSequences": ["Paris"]}}'
5
+ headers:
6
+ amz-sdk-invocation-id:
7
+ - !!binary |
8
+ YzVkZjljOTMtMDQ1Zi00NWE0LWJhY2YtMDAwMjdjYTg1NmRl
9
+ amz-sdk-request:
10
+ - !!binary |
11
+ YXR0ZW1wdD0x
12
+ content-length:
13
+ - '152'
14
+ content-type:
15
+ - !!binary |
16
+ YXBwbGljYXRpb24vanNvbg==
17
+ method: POST
18
+ uri: https://bedrock-runtime.us-east-1.amazonaws.com/model/us.amazon.nova-micro-v1%3A0/converse
19
+ response:
20
+ headers:
21
+ connection:
22
+ - keep-alive
23
+ content-length:
24
+ - '209'
25
+ content-type:
26
+ - application/json
27
+ parsed_body:
28
+ metrics:
29
+ latencyMs: 179
30
+ output:
31
+ message:
32
+ content:
33
+ - text: The capital of France is Paris
34
+ role: assistant
35
+ stopReason: end_turn
36
+ usage:
37
+ inputTokens: 7
38
+ outputTokens: 6
39
+ totalTokens: 13
40
+ status:
41
+ code: 200
42
+ message: OK
43
+ version: 1
@@ -0,0 +1,66 @@
1
+ interactions:
2
+ - request:
3
+ headers:
4
+ accept:
5
+ - '*/*'
6
+ accept-encoding:
7
+ - gzip, deflate
8
+ connection:
9
+ - keep-alive
10
+ content-length:
11
+ - '140'
12
+ content-type:
13
+ - application/json
14
+ host:
15
+ - api.cohere.com
16
+ method: POST
17
+ parsed_body:
18
+ messages:
19
+ - content: What is the capital of France?
20
+ role: user
21
+ model: command-r-plus
22
+ stop_sequences:
23
+ - Paris
24
+ stream: false
25
+ uri: https://api.cohere.com/v2/chat
26
+ response:
27
+ headers:
28
+ access-control-expose-headers:
29
+ - X-Debug-Trace-ID
30
+ alt-svc:
31
+ - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
32
+ cache-control:
33
+ - no-cache, no-store, no-transform, must-revalidate, private, max-age=0
34
+ content-length:
35
+ - '280'
36
+ content-type:
37
+ - application/json
38
+ expires:
39
+ - Thu, 01 Jan 1970 00:00:00 UTC
40
+ num_chars:
41
+ - '1200'
42
+ num_tokens:
43
+ - '12'
44
+ pragma:
45
+ - no-cache
46
+ vary:
47
+ - Origin
48
+ parsed_body:
49
+ finish_reason: STOP_SEQUENCE
50
+ id: 2ed6908c-e5cb-4063-b2a3-0ac4990d1b85
51
+ message:
52
+ content:
53
+ - text: The capital of France is
54
+ type: text
55
+ role: assistant
56
+ usage:
57
+ billed_units:
58
+ input_tokens: 7
59
+ output_tokens: 5
60
+ tokens:
61
+ input_tokens: 200
62
+ output_tokens: 7
63
+ status:
64
+ code: 200
65
+ message: OK
66
+ version: 1
@@ -0,0 +1,60 @@
1
+ interactions:
2
+ - request:
3
+ headers:
4
+ accept:
5
+ - '*/*'
6
+ accept-encoding:
7
+ - gzip, deflate
8
+ connection:
9
+ - keep-alive
10
+ content-length:
11
+ - '154'
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
+ generation_config:
23
+ stop_sequences:
24
+ - Paris
25
+ safety_settings: null
26
+ uri: https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent
27
+ response:
28
+ headers:
29
+ alt-svc:
30
+ - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
31
+ content-length:
32
+ - '416'
33
+ content-type:
34
+ - application/json; charset=UTF-8
35
+ server-timing:
36
+ - gfet4t7; dur=314
37
+ transfer-encoding:
38
+ - chunked
39
+ vary:
40
+ - Origin
41
+ - X-Origin
42
+ - Referer
43
+ parsed_body:
44
+ candidates:
45
+ - content:
46
+ parts:
47
+ - text: ''
48
+ role: model
49
+ finishReason: STOP
50
+ modelVersion: gemini-1.5-flash
51
+ usageMetadata:
52
+ promptTokenCount: 7
53
+ promptTokensDetails:
54
+ - modality: TEXT
55
+ tokenCount: 7
56
+ totalTokenCount: 7
57
+ status:
58
+ code: 200
59
+ message: OK
60
+ version: 1
@@ -0,0 +1,71 @@
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
+ - '136'
12
+ content-type:
13
+ - application/json
14
+ host:
15
+ - api.groq.com
16
+ method: POST
17
+ parsed_body:
18
+ messages:
19
+ - content: What is the capital of France?
20
+ role: user
21
+ model: llama3-8b-8192
22
+ n: 1
23
+ stop:
24
+ - Paris
25
+ stream: false
26
+ uri: https://api.groq.com/openai/v1/chat/completions
27
+ response:
28
+ headers:
29
+ alt-svc:
30
+ - h3=":443"; ma=86400
31
+ cache-control:
32
+ - private, max-age=0, no-store, no-cache, must-revalidate
33
+ connection:
34
+ - keep-alive
35
+ content-length:
36
+ - '562'
37
+ content-type:
38
+ - application/json
39
+ transfer-encoding:
40
+ - chunked
41
+ vary:
42
+ - Origin, Accept-Encoding
43
+ parsed_body:
44
+ choices:
45
+ - finish_reason: stop
46
+ index: 0
47
+ logprobs: null
48
+ message:
49
+ content: 'The capital of France is '
50
+ role: assistant
51
+ created: 1744190899
52
+ id: chatcmpl-9de98446-dccf-439b-bcb8-996ee77471d8
53
+ model: llama3-8b-8192
54
+ object: chat.completion
55
+ system_fingerprint: fp_dadc9d6142
56
+ usage:
57
+ completion_time: 0.006666667
58
+ completion_tokens: 8
59
+ prompt_time: 0.003914844
60
+ prompt_tokens: 17
61
+ queue_time: 0.5322581550000001
62
+ total_time: 0.010581511
63
+ total_tokens: 25
64
+ usage_breakdown:
65
+ models: null
66
+ x_groq:
67
+ id: req_01jrcy20hceg1t9cpsg7cmj7f9
68
+ status:
69
+ code: 200
70
+ message: OK
71
+ version: 1
@@ -0,0 +1,69 @@
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
+ - '153'
12
+ content-type:
13
+ - application/json
14
+ host:
15
+ - api.mistral.ai
16
+ method: POST
17
+ parsed_body:
18
+ messages:
19
+ - content: What is the capital of France?
20
+ role: user
21
+ model: ministral-8b-latest
22
+ n: 1
23
+ stop:
24
+ - Paris
25
+ stream: false
26
+ top_p: 1.0
27
+ uri: https://api.mistral.ai/v1/chat/completions
28
+ response:
29
+ headers:
30
+ access-control-allow-origin:
31
+ - '*'
32
+ alt-svc:
33
+ - h3=":443"; ma=86400
34
+ connection:
35
+ - keep-alive
36
+ content-length:
37
+ - '322'
38
+ content-type:
39
+ - application/json
40
+ ratelimitbysize-limit:
41
+ - '500000'
42
+ ratelimitbysize-query-cost:
43
+ - '32008'
44
+ ratelimitbysize-remaining:
45
+ - '467992'
46
+ ratelimitbysize-reset:
47
+ - '42'
48
+ transfer-encoding:
49
+ - chunked
50
+ parsed_body:
51
+ choices:
52
+ - finish_reason: stop
53
+ index: 0
54
+ message:
55
+ content: 'The capital of France is '
56
+ role: assistant
57
+ tool_calls: null
58
+ created: 1744190898
59
+ id: 0bbc8cf8fc76455fae759fb9109f8547
60
+ model: ministral-8b-latest
61
+ object: chat.completion
62
+ usage:
63
+ completion_tokens: 6
64
+ prompt_tokens: 10
65
+ total_tokens: 16
66
+ status:
67
+ code: 200
68
+ message: OK
69
+ 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
+ - '129'
12
+ content-type:
13
+ - application/json
14
+ host:
15
+ - api.openai.com
16
+ method: POST
17
+ parsed_body:
18
+ messages:
19
+ - content: What is the capital of France?
20
+ role: user
21
+ model: o3-mini
22
+ n: 1
23
+ stop:
24
+ - Paris
25
+ stream: false
26
+ uri: https://api.openai.com/v1/chat/completions
27
+ response:
28
+ headers:
29
+ access-control-expose-headers:
30
+ - X-Request-ID
31
+ alt-svc:
32
+ - h3=":443"; ma=86400
33
+ connection:
34
+ - keep-alive
35
+ content-length:
36
+ - '805'
37
+ content-type:
38
+ - application/json
39
+ openai-organization:
40
+ - pydantic-28gund
41
+ openai-processing-ms:
42
+ - '3852'
43
+ openai-version:
44
+ - '2020-10-01'
45
+ strict-transport-security:
46
+ - max-age=31536000; includeSubDomains; preload
47
+ transfer-encoding:
48
+ - chunked
49
+ parsed_body:
50
+ choices:
51
+ - finish_reason: stop
52
+ index: 0
53
+ message:
54
+ annotations: []
55
+ content: 'The capital of France is '
56
+ refusal: null
57
+ role: assistant
58
+ created: 1744190892
59
+ id: chatcmpl-BKM16LEJBCFN3jeeR1O8sFXn6OMZt
60
+ model: o3-mini-2025-01-31
61
+ object: chat.completion
62
+ service_tier: default
63
+ system_fingerprint: fp_617f206dd9
64
+ usage:
65
+ completion_tokens: 80
66
+ completion_tokens_details:
67
+ accepted_prediction_tokens: 0
68
+ audio_tokens: 0
69
+ reasoning_tokens: 64
70
+ rejected_prediction_tokens: 0
71
+ prompt_tokens: 13
72
+ prompt_tokens_details:
73
+ audio_tokens: 0
74
+ cached_tokens: 0
75
+ total_tokens: 93
76
+ status:
77
+ code: 200
78
+ message: OK
79
+ version: 1
@@ -22,7 +22,7 @@ from vcr import VCR
22
22
 
23
23
  import pydantic_ai.models
24
24
  from pydantic_ai.messages import BinaryContent
25
- from pydantic_ai.models import cached_async_http_client
25
+ from pydantic_ai.models import Model, cached_async_http_client
26
26
 
27
27
  __all__ = 'IsDatetime', 'IsFloat', 'IsNow', 'IsStr', 'TestEnv', 'ClientWithHandler', 'try_import'
28
28
 
@@ -30,6 +30,7 @@ __all__ = 'IsDatetime', 'IsFloat', 'IsNow', 'IsStr', 'TestEnv', 'ClientWithHandl
30
30
  pydantic_ai.models.ALLOW_MODEL_REQUESTS = False
31
31
 
32
32
  if TYPE_CHECKING:
33
+ from pydantic_ai.providers.bedrock import BedrockProvider
33
34
 
34
35
  def IsDatetime(*args: Any, **kwargs: Any) -> datetime: ...
35
36
  def IsFloat(*args: Any, **kwargs: Any) -> float: ...
@@ -267,6 +268,77 @@ def mistral_api_key() -> str:
267
268
  return os.getenv('MISTRAL_API_KEY', 'mock-api-key')
268
269
 
269
270
 
271
+ @pytest.fixture(scope='session')
272
+ def bedrock_provider(): # pragma: no cover
273
+ try:
274
+ import boto3
275
+
276
+ from pydantic_ai.providers.bedrock import BedrockProvider
277
+
278
+ bedrock_client = boto3.client(
279
+ 'bedrock-runtime',
280
+ region_name=os.getenv('AWS_REGION', 'us-east-1'),
281
+ aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID', 'AKIA6666666666666666'),
282
+ aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY', '6666666666666666666666666666666666666666'),
283
+ )
284
+ yield BedrockProvider(bedrock_client=bedrock_client)
285
+ bedrock_client.close()
286
+ except ImportError:
287
+ pytest.skip('boto3 is not installed')
288
+
289
+
290
+ @pytest.fixture()
291
+ def model(
292
+ request: pytest.FixtureRequest,
293
+ openai_api_key: str,
294
+ anthropic_api_key: str,
295
+ mistral_api_key: str,
296
+ groq_api_key: str,
297
+ co_api_key: str,
298
+ gemini_api_key: str,
299
+ bedrock_provider: BedrockProvider,
300
+ ) -> Model: # pragma: no cover
301
+ try:
302
+ if request.param == 'openai':
303
+ from pydantic_ai.models.openai import OpenAIModel
304
+ from pydantic_ai.providers.openai import OpenAIProvider
305
+
306
+ return OpenAIModel('o3-mini', provider=OpenAIProvider(api_key=openai_api_key))
307
+ elif request.param == 'anthropic':
308
+ from pydantic_ai.models.anthropic import AnthropicModel
309
+ from pydantic_ai.providers.anthropic import AnthropicProvider
310
+
311
+ return AnthropicModel('claude-3-5-sonnet-latest', provider=AnthropicProvider(api_key=anthropic_api_key))
312
+ elif request.param == 'mistral':
313
+ from pydantic_ai.models.mistral import MistralModel
314
+ from pydantic_ai.providers.mistral import MistralProvider
315
+
316
+ return MistralModel('ministral-8b-latest', provider=MistralProvider(api_key=mistral_api_key))
317
+ elif request.param == 'groq':
318
+ from pydantic_ai.models.groq import GroqModel
319
+ from pydantic_ai.providers.groq import GroqProvider
320
+
321
+ return GroqModel('llama3-8b-8192', provider=GroqProvider(api_key=groq_api_key))
322
+ elif request.param == 'cohere':
323
+ from pydantic_ai.models.cohere import CohereModel
324
+ from pydantic_ai.providers.cohere import CohereProvider
325
+
326
+ return CohereModel('command-r-plus', provider=CohereProvider(api_key=co_api_key))
327
+ elif request.param == 'gemini':
328
+ from pydantic_ai.models.gemini import GeminiModel
329
+ from pydantic_ai.providers.google_gla import GoogleGLAProvider
330
+
331
+ return GeminiModel('gemini-1.5-flash', provider=GoogleGLAProvider(api_key=gemini_api_key))
332
+ elif request.param == 'bedrock':
333
+ from pydantic_ai.models.bedrock import BedrockConverseModel
334
+
335
+ return BedrockConverseModel('us.amazon.nova-micro-v1:0', provider=bedrock_provider)
336
+ else:
337
+ raise ValueError(f'Unknown model: {request.param}')
338
+ except ImportError:
339
+ pytest.skip(f'{request.param} is not installed')
340
+
341
+
270
342
  @pytest.fixture
271
343
  def mock_snapshot_id(mocker: MockerFixture):
272
344
  i = 0
@@ -5,7 +5,7 @@ import json
5
5
  import sys
6
6
  from dataclasses import dataclass
7
7
  from pathlib import Path
8
- from typing import TYPE_CHECKING, Any
8
+ from typing import Any
9
9
 
10
10
  import pytest
11
11
  from dirty_equals import HasRepr
@@ -16,17 +16,13 @@ from ..conftest import try_import
16
16
  from .utils import render_table
17
17
 
18
18
  with try_import() as imports_successful:
19
+ import logfire
20
+ from logfire.testing import CaptureLogfire
21
+
19
22
  from pydantic_evals import Case, Dataset
20
23
  from pydantic_evals.dataset import increment_eval_metric, set_eval_attribute
21
24
  from pydantic_evals.evaluators import EvaluationResult, Evaluator, EvaluatorOutput, LLMJudge, Python
22
25
  from pydantic_evals.evaluators.context import EvaluatorContext
23
- from pydantic_evals.reporting import ReportCase
24
-
25
- pytestmark = [pytest.mark.skipif(not imports_successful(), reason='pydantic-evals not installed'), pytest.mark.anyio]
26
-
27
- if TYPE_CHECKING or imports_successful():
28
- import logfire
29
- from logfire.testing import CaptureLogfire
30
26
 
31
27
  @dataclass
32
28
  class MockEvaluator(Evaluator[object, object, object]):
@@ -37,6 +33,10 @@ if TYPE_CHECKING or imports_successful():
37
33
  def evaluate(self, ctx: EvaluatorContext[object, object, object]) -> EvaluatorOutput:
38
34
  return self.output
39
35
 
36
+ from pydantic_evals.reporting import ReportCase
37
+
38
+ pytestmark = [pytest.mark.skipif(not imports_successful(), reason='pydantic-evals not installed'), pytest.mark.anyio]
39
+
40
40
 
41
41
  if sys.version_info < (3, 11):
42
42
  from exceptiongroup import ExceptionGroup
@@ -611,10 +611,10 @@ async def test_from_text_failure():
611
611
  '2 error(s) loading evaluators from registry',
612
612
  [
613
613
  ValueError(
614
- "Evaluator 'NotAnEvaluator' is not in the provided registry. Registered choices: ['Equals', 'EqualsExpected', 'Contains', 'IsInstance', 'MaxDuration', 'LLMJudge', 'HasMatchingSpan']"
614
+ "Evaluator 'NotAnEvaluator' is not in the provided `custom_evaluator_types`. Valid choices: ['Equals', 'EqualsExpected', 'Contains', 'IsInstance', 'MaxDuration', 'LLMJudge', 'HasMatchingSpan']. If you are trying to use a custom evaluator, you must include its type in the `custom_evaluator_types` argument."
615
615
  ),
616
616
  ValueError(
617
- "Evaluator 'NotAnEvaluator' is not in the provided registry. Registered choices: ['Equals', 'EqualsExpected', 'Contains', 'IsInstance', 'MaxDuration', 'LLMJudge', 'HasMatchingSpan']"
617
+ "Evaluator 'NotAnEvaluator' is not in the provided `custom_evaluator_types`. Valid choices: ['Equals', 'EqualsExpected', 'Contains', 'IsInstance', 'MaxDuration', 'LLMJudge', 'HasMatchingSpan']. If you are trying to use a custom evaluator, you must include its type in the `custom_evaluator_types` argument."
618
618
  ),
619
619
  ],
620
620
  )
@@ -222,10 +222,10 @@ async def test_llm_judge_evaluator(mocker: MockerFixture):
222
222
  assert result.value is True
223
223
  assert result.reason == 'Test passed'
224
224
 
225
- mock_judge_output.assert_called_once_with('Hello world', 'Content contains a greeting', 'openai:gpt-4o')
225
+ mock_judge_output.assert_called_once_with('Hello world', 'Content contains a greeting', None)
226
226
 
227
227
  # Test with input
228
- evaluator = LLMJudge(rubric='Output contains input', include_input=True)
228
+ evaluator = LLMJudge(rubric='Output contains input', include_input=True, model='openai:gpt-4o')
229
229
  result = await evaluator.evaluate(ctx)
230
230
  assert isinstance(result, EvaluationReason)
231
231
  assert result.value is True