pydantic-ai 0.2.10__tar.gz → 0.2.12__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.
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/PKG-INFO +3 -3
- pydantic_ai-0.2.12/tests/models/cassettes/test_anthropic/test_anthropic_model_empty_message_on_history.yaml +73 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_anthropic.py +28 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_bedrock.py +95 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_gemini.py +52 -9
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_google.py +60 -8
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_openai.py +125 -16
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_openai_responses.py +43 -0
- pydantic_ai-0.2.12/tests/providers/test_azure.py +141 -0
- pydantic_ai-0.2.12/tests/providers/test_bedrock.py +95 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/providers/test_deepseek.py +8 -1
- pydantic_ai-0.2.12/tests/providers/test_fireworks.py +104 -0
- pydantic_ai-0.2.12/tests/providers/test_grok.py +57 -0
- pydantic_ai-0.2.12/tests/providers/test_groq.py +107 -0
- pydantic_ai-0.2.12/tests/providers/test_openrouter.py +154 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/providers/test_provider_names.py +6 -0
- pydantic_ai-0.2.12/tests/providers/test_together.py +100 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_agent.py +601 -3
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_examples.py +94 -1
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_tools.py +1 -1
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/typed_agent.py +50 -22
- pydantic_ai-0.2.10/tests/providers/test_azure.py +0 -72
- pydantic_ai-0.2.10/tests/providers/test_bedrock.py +0 -34
- pydantic_ai-0.2.10/tests/providers/test_groq.py +0 -57
- pydantic_ai-0.2.10/tests/providers/test_openrouter.py +0 -67
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/.gitignore +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/LICENSE +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/Makefile +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/README.md +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/pyproject.toml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/__init__.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/assets/dummy.pdf +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/assets/kiwi.png +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/assets/marcelo.mp3 +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/assets/small_video.mp4 +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_mcp/test_agent_with_stdio_server.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_mcp/test_tool_returning_dict.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_mcp/test_tool_returning_error.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_mcp/test_tool_returning_image.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_mcp/test_tool_returning_image_resource.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_mcp/test_tool_returning_multiple_items.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_mcp/test_tool_returning_none.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_mcp/test_tool_returning_str.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_mcp/test_tool_returning_text_resource.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_settings/test_stop_settings[anthropic].yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_settings/test_stop_settings[bedrock].yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_settings/test_stop_settings[cohere].yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_settings/test_stop_settings[gemini].yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_settings/test_stop_settings[groq].yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_settings/test_stop_settings[mistral].yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/cassettes/test_settings/test_stop_settings[openai].yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/conftest.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/__init__.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/test_dataset.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/test_evaluator_base.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/test_evaluator_common.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/test_evaluator_context.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/test_evaluator_spec.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/test_evaluators.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/test_llm_as_a_judge.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/test_otel.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/test_render_numbers.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/test_reporting.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/test_reports.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/test_utils.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/evals/utils.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/example_modules/README.md +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/example_modules/bank_database.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/example_modules/fake_database.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/example_modules/weather_service.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/fasta2a/__init__.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/fasta2a/test_applications.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/graph/__init__.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/graph/test_file_persistence.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/graph/test_graph.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/graph/test_mermaid.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/graph/test_persistence.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/graph/test_state.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/graph/test_utils.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/import_examples.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/json_body_serializer.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/mcp_server.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/__init__.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_anthropic/test_anthropic_model_instructions.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_anthropic/test_document_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_anthropic/test_document_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_anthropic/test_extra_headers.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_anthropic/test_image_as_binary_content_tool_response.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_anthropic/test_image_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_anthropic/test_image_url_input_invalid_mime_type.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_anthropic/test_multiple_parallel_tool_calls.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_anthropic/test_text_document_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_empty_system_prompt.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_model.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_model_anthropic_model_without_tools.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_model_guardrail_config.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_model_instructions.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_model_iter_stream.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_model_max_tokens.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_model_other_parameters.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_model_performance_config.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_model_retry.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_model_stream.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_model_structured_response.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_model_top_p.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_bedrock_multiple_documents_in_history.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_document_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_image_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_image_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_text_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_text_document_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_video_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_bedrock/test_video_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_cohere/test_cohere_model_instructions.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_cohere/test_request_simple_success_with_vcr.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_gemini/test_document_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_gemini/test_gemini_additional_properties_is_false.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_gemini/test_gemini_additional_properties_is_true.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_gemini/test_gemini_drop_exclusive_maximum.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_gemini/test_gemini_exclusive_minimum_and_maximum.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_gemini/test_gemini_model_instructions.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_gemini/test_image_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_gemini/test_image_as_binary_content_tool_response.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_gemini/test_image_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_gemini/test_labels_are_ignored_with_gla_provider.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_gemini/test_video_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_gemini/test_video_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_gemini_vertexai/test_labels.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_document_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_image_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_image_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_instructions.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_iter_stream.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_max_tokens.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_multiple_documents_in_history.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_retry.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_safety_settings.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_stream.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_structured_response.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_text_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_text_document_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_thinking_config.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_top_p.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_vertex_labels.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_vertex_provider.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_video_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_google/test_google_model_video_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_groq/test_extra_headers.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_groq/test_groq_model_instructions.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_groq/test_image_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_groq/test_image_as_binary_content_tool_response.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_groq/test_image_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_mistral/test_image_as_binary_content_tool_response.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_mistral/test_mistral_model_instructions.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_audio_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_document_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_document_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_extra_headers.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_image_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_image_as_binary_content_tool_response.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_image_url_tool_response.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_max_completion_tokens[gpt-4.5-preview].yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_max_completion_tokens[gpt-4o-mini].yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_max_completion_tokens[o3-mini].yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_multiple_agent_tool_calls.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_openai_audio_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_openai_instructions.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_openai_instructions_with_tool_calls_keep_instructions.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_openai_model_without_system_prompt.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_openai_o1_mini_system_role[developer].yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_openai_o1_mini_system_role[system].yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai/test_user_id.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_audio_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_image_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_image_as_binary_content_tool_response.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_document_as_binary_content_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_document_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_image_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_model_builtin_tools.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_model_http_error.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_model_instructions.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_model_retry.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_model_simple_response.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_model_simple_response_with_tool_call.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_output_type.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_reasoning_effort.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_reasoning_generate_summary.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_stream.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_system_prompt.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/cassettes/test_openai_responses/test_openai_responses_text_document_url_input.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/mock_async_stream.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_cohere.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_fallback.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_gemini_vertexai.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_groq.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_instrumented.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_mistral.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_model.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_model_function.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_model_names.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_model_request_parameters.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/models/test_model_test.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/providers/__init__.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/providers/cassettes/test_azure/test_azure_provider_call.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/providers/cassettes/test_google_vertex/test_vertexai_provider.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/providers/cassettes/test_openrouter/test_openrouter_with_google_model.yaml +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/providers/test_anthropic.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/providers/test_cohere.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/providers/test_google_gla.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/providers/test_google_vertex.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/providers/test_mistral.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/providers/test_openai.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_a2a.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_cli.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_deps.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_direct.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_format_as_xml.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_json_body_serializer.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_live.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_logfire.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_mcp.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_messages.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_parts_manager.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_settings.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_streaming.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_usage_limits.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/test_utils.py +0 -0
- {pydantic_ai-0.2.10 → pydantic_ai-0.2.12}/tests/typed_graph.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydantic-ai
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.12
|
|
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[a2a,anthropic,bedrock,cli,cohere,evals,google,groq,mcp,mistral,openai,vertexai]==0.2.
|
|
31
|
+
Requires-Dist: pydantic-ai-slim[a2a,anthropic,bedrock,cli,cohere,evals,google,groq,mcp,mistral,openai,vertexai]==0.2.12
|
|
32
32
|
Provides-Extra: examples
|
|
33
|
-
Requires-Dist: pydantic-ai-examples==0.2.
|
|
33
|
+
Requires-Dist: pydantic-ai-examples==0.2.12; 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,73 @@
|
|
|
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
|
+
- '281'
|
|
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: Hello, how can I help you?
|
|
22
|
+
type: text
|
|
23
|
+
role: assistant
|
|
24
|
+
- content:
|
|
25
|
+
- text: I need a potato!
|
|
26
|
+
type: text
|
|
27
|
+
role: user
|
|
28
|
+
model: claude-3-5-sonnet-latest
|
|
29
|
+
stream: false
|
|
30
|
+
system: |+
|
|
31
|
+
You are a helpful assistant.
|
|
32
|
+
|
|
33
|
+
uri: https://api.anthropic.com/v1/messages?beta=true
|
|
34
|
+
response:
|
|
35
|
+
headers:
|
|
36
|
+
connection:
|
|
37
|
+
- keep-alive
|
|
38
|
+
content-length:
|
|
39
|
+
- '671'
|
|
40
|
+
content-type:
|
|
41
|
+
- application/json
|
|
42
|
+
strict-transport-security:
|
|
43
|
+
- max-age=31536000; includeSubDomains; preload
|
|
44
|
+
transfer-encoding:
|
|
45
|
+
- chunked
|
|
46
|
+
parsed_body:
|
|
47
|
+
content:
|
|
48
|
+
- text: |-
|
|
49
|
+
I can't physically give you a potato since I'm a computer program. However, I can:
|
|
50
|
+
|
|
51
|
+
1. Help you find recipes that use potatoes
|
|
52
|
+
2. Give you tips on how to select, store, or cook potatoes
|
|
53
|
+
3. Share information about different potato varieties
|
|
54
|
+
4. Provide guidance on growing potatoes
|
|
55
|
+
|
|
56
|
+
What specifically would you like to know about potatoes?
|
|
57
|
+
type: text
|
|
58
|
+
id: msg_01UjnDmX3B57Drosu49sMteT
|
|
59
|
+
model: claude-3-5-sonnet-20241022
|
|
60
|
+
role: assistant
|
|
61
|
+
stop_reason: end_turn
|
|
62
|
+
stop_sequence: null
|
|
63
|
+
type: message
|
|
64
|
+
usage:
|
|
65
|
+
cache_creation_input_tokens: 0
|
|
66
|
+
cache_read_input_tokens: 0
|
|
67
|
+
input_tokens: 41
|
|
68
|
+
output_tokens: 82
|
|
69
|
+
service_tier: standard
|
|
70
|
+
status:
|
|
71
|
+
code: 200
|
|
72
|
+
message: OK
|
|
73
|
+
version: 1
|
|
@@ -1035,3 +1035,31 @@ def anth_msg(usage: BetaUsage) -> BetaMessage:
|
|
|
1035
1035
|
)
|
|
1036
1036
|
def test_usage(message_callback: Callable[[], BetaMessage | BetaRawMessageStreamEvent], usage: Usage):
|
|
1037
1037
|
assert _map_usage(message_callback()) == usage
|
|
1038
|
+
|
|
1039
|
+
|
|
1040
|
+
@pytest.mark.vcr()
|
|
1041
|
+
async def test_anthropic_model_empty_message_on_history(allow_model_requests: None, anthropic_api_key: str):
|
|
1042
|
+
"""The Anthropic API will error if you send an empty message on the history.
|
|
1043
|
+
|
|
1044
|
+
Check <https://github.com/pydantic/pydantic-ai/pull/1027> for more details.
|
|
1045
|
+
"""
|
|
1046
|
+
m = AnthropicModel('claude-3-5-sonnet-latest', provider=AnthropicProvider(api_key=anthropic_api_key))
|
|
1047
|
+
agent = Agent(m, instructions='You are a helpful assistant.')
|
|
1048
|
+
|
|
1049
|
+
result = await agent.run(
|
|
1050
|
+
'I need a potato!',
|
|
1051
|
+
message_history=[
|
|
1052
|
+
ModelRequest(parts=[], instructions='You are a helpful assistant.', kind='request'),
|
|
1053
|
+
ModelResponse(parts=[TextPart(content='Hello, how can I help you?')], kind='response'),
|
|
1054
|
+
],
|
|
1055
|
+
)
|
|
1056
|
+
assert result.output == snapshot("""\
|
|
1057
|
+
I can't physically give you a potato since I'm a computer program. However, I can:
|
|
1058
|
+
|
|
1059
|
+
1. Help you find recipes that use potatoes
|
|
1060
|
+
2. Give you tips on how to select, store, or cook potatoes
|
|
1061
|
+
3. Share information about different potato varieties
|
|
1062
|
+
4. Provide guidance on growing potatoes
|
|
1063
|
+
|
|
1064
|
+
What specifically would you like to know about potatoes?\
|
|
1065
|
+
""")
|
|
@@ -31,6 +31,8 @@ from pydantic_ai.messages import (
|
|
|
31
31
|
UserPromptPart,
|
|
32
32
|
VideoUrl,
|
|
33
33
|
)
|
|
34
|
+
from pydantic_ai.models import ModelRequestParameters
|
|
35
|
+
from pydantic_ai.tools import ToolDefinition
|
|
34
36
|
from pydantic_ai.usage import Usage
|
|
35
37
|
|
|
36
38
|
from ..conftest import IsDatetime, try_import
|
|
@@ -631,3 +633,96 @@ async def test_bedrock_group_consecutive_tool_return_parts(bedrock_provider: Bed
|
|
|
631
633
|
},
|
|
632
634
|
]
|
|
633
635
|
)
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
async def test_bedrock_mistral_tool_result_format(bedrock_provider: BedrockProvider):
|
|
639
|
+
now = datetime.datetime.now()
|
|
640
|
+
req = [
|
|
641
|
+
ModelRequest(
|
|
642
|
+
parts=[
|
|
643
|
+
ToolReturnPart(tool_name='tool1', content={'foo': 'bar'}, tool_call_id='id1', timestamp=now),
|
|
644
|
+
]
|
|
645
|
+
),
|
|
646
|
+
]
|
|
647
|
+
|
|
648
|
+
# Models other than Mistral support toolResult.content with text, not json
|
|
649
|
+
model = BedrockConverseModel('us.amazon.nova-micro-v1:0', provider=bedrock_provider)
|
|
650
|
+
# Call the mapping function directly
|
|
651
|
+
_, bedrock_messages = await model._map_messages(req) # type: ignore[reportPrivateUsage]
|
|
652
|
+
|
|
653
|
+
assert bedrock_messages == snapshot(
|
|
654
|
+
[
|
|
655
|
+
{
|
|
656
|
+
'role': 'user',
|
|
657
|
+
'content': [
|
|
658
|
+
{'toolResult': {'toolUseId': 'id1', 'content': [{'text': '{"foo":"bar"}'}], 'status': 'success'}},
|
|
659
|
+
],
|
|
660
|
+
},
|
|
661
|
+
]
|
|
662
|
+
)
|
|
663
|
+
|
|
664
|
+
# Mistral requires toolResult.content to hold json, not text
|
|
665
|
+
model = BedrockConverseModel('mistral.mistral-7b-instruct-v0:2', provider=bedrock_provider)
|
|
666
|
+
# Call the mapping function directly
|
|
667
|
+
_, bedrock_messages = await model._map_messages(req) # type: ignore[reportPrivateUsage]
|
|
668
|
+
|
|
669
|
+
assert bedrock_messages == snapshot(
|
|
670
|
+
[
|
|
671
|
+
{
|
|
672
|
+
'role': 'user',
|
|
673
|
+
'content': [
|
|
674
|
+
{'toolResult': {'toolUseId': 'id1', 'content': [{'json': {'foo': 'bar'}}], 'status': 'success'}},
|
|
675
|
+
],
|
|
676
|
+
},
|
|
677
|
+
]
|
|
678
|
+
)
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
async def test_bedrock_anthropic_no_tool_choice(bedrock_provider: BedrockProvider):
|
|
682
|
+
my_tool = ToolDefinition(
|
|
683
|
+
'my_tool',
|
|
684
|
+
'This is my tool',
|
|
685
|
+
{'type': 'object', 'title': 'Result', 'properties': {'spam': {'type': 'number'}}},
|
|
686
|
+
)
|
|
687
|
+
mrp = ModelRequestParameters(function_tools=[my_tool], allow_text_output=False, output_tools=[])
|
|
688
|
+
|
|
689
|
+
# Models other than Anthropic support tool_choice
|
|
690
|
+
model = BedrockConverseModel('us.amazon.nova-micro-v1:0', provider=bedrock_provider)
|
|
691
|
+
tool_config = model._map_tool_config(mrp) # type: ignore[reportPrivateUsage]
|
|
692
|
+
|
|
693
|
+
assert tool_config == snapshot(
|
|
694
|
+
{
|
|
695
|
+
'tools': [
|
|
696
|
+
{
|
|
697
|
+
'toolSpec': {
|
|
698
|
+
'name': 'my_tool',
|
|
699
|
+
'description': 'This is my tool',
|
|
700
|
+
'inputSchema': {
|
|
701
|
+
'json': {'type': 'object', 'title': 'Result', 'properties': {'spam': {'type': 'number'}}}
|
|
702
|
+
},
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
],
|
|
706
|
+
'toolChoice': {'any': {}},
|
|
707
|
+
}
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
# Anthropic models don't support tool_choice
|
|
711
|
+
model = BedrockConverseModel('us.anthropic.claude-3-7-sonnet-20250219-v1:0', provider=bedrock_provider)
|
|
712
|
+
tool_config = model._map_tool_config(mrp) # type: ignore[reportPrivateUsage]
|
|
713
|
+
|
|
714
|
+
assert tool_config == snapshot(
|
|
715
|
+
{
|
|
716
|
+
'tools': [
|
|
717
|
+
{
|
|
718
|
+
'toolSpec': {
|
|
719
|
+
'name': 'my_tool',
|
|
720
|
+
'description': 'This is my tool',
|
|
721
|
+
'inputSchema': {
|
|
722
|
+
'json': {'type': 'object', 'title': 'Result', 'properties': {'spam': {'type': 'number'}}}
|
|
723
|
+
},
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
]
|
|
727
|
+
}
|
|
728
|
+
)
|
|
@@ -540,6 +540,7 @@ async def test_text_success(get_gemini_client: GetGeminiClient):
|
|
|
540
540
|
usage=Usage(requests=1, request_tokens=1, response_tokens=2, total_tokens=3, details={}),
|
|
541
541
|
model_name='gemini-1.5-flash-123',
|
|
542
542
|
timestamp=IsNow(tz=timezone.utc),
|
|
543
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
543
544
|
),
|
|
544
545
|
]
|
|
545
546
|
)
|
|
@@ -555,6 +556,7 @@ async def test_text_success(get_gemini_client: GetGeminiClient):
|
|
|
555
556
|
usage=Usage(requests=1, request_tokens=1, response_tokens=2, total_tokens=3, details={}),
|
|
556
557
|
model_name='gemini-1.5-flash-123',
|
|
557
558
|
timestamp=IsNow(tz=timezone.utc),
|
|
559
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
558
560
|
),
|
|
559
561
|
ModelRequest(parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))]),
|
|
560
562
|
ModelResponse(
|
|
@@ -562,6 +564,7 @@ async def test_text_success(get_gemini_client: GetGeminiClient):
|
|
|
562
564
|
usage=Usage(requests=1, request_tokens=1, response_tokens=2, total_tokens=3, details={}),
|
|
563
565
|
model_name='gemini-1.5-flash-123',
|
|
564
566
|
timestamp=IsNow(tz=timezone.utc),
|
|
567
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
565
568
|
),
|
|
566
569
|
]
|
|
567
570
|
)
|
|
@@ -585,6 +588,7 @@ async def test_request_structured_response(get_gemini_client: GetGeminiClient):
|
|
|
585
588
|
usage=Usage(requests=1, request_tokens=1, response_tokens=2, total_tokens=3, details={}),
|
|
586
589
|
model_name='gemini-1.5-flash-123',
|
|
587
590
|
timestamp=IsNow(tz=timezone.utc),
|
|
591
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
588
592
|
),
|
|
589
593
|
ModelRequest(
|
|
590
594
|
parts=[
|
|
@@ -647,6 +651,7 @@ async def test_request_tool_call(get_gemini_client: GetGeminiClient):
|
|
|
647
651
|
usage=Usage(requests=1, request_tokens=1, response_tokens=2, total_tokens=3, details={}),
|
|
648
652
|
model_name='gemini-1.5-flash-123',
|
|
649
653
|
timestamp=IsNow(tz=timezone.utc),
|
|
654
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
650
655
|
),
|
|
651
656
|
ModelRequest(
|
|
652
657
|
parts=[
|
|
@@ -666,6 +671,7 @@ async def test_request_tool_call(get_gemini_client: GetGeminiClient):
|
|
|
666
671
|
usage=Usage(requests=1, request_tokens=1, response_tokens=2, total_tokens=3, details={}),
|
|
667
672
|
model_name='gemini-1.5-flash-123',
|
|
668
673
|
timestamp=IsNow(tz=timezone.utc),
|
|
674
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
669
675
|
),
|
|
670
676
|
ModelRequest(
|
|
671
677
|
parts=[
|
|
@@ -688,6 +694,7 @@ async def test_request_tool_call(get_gemini_client: GetGeminiClient):
|
|
|
688
694
|
usage=Usage(requests=1, request_tokens=1, response_tokens=2, total_tokens=3, details={}),
|
|
689
695
|
model_name='gemini-1.5-flash-123',
|
|
690
696
|
timestamp=IsNow(tz=timezone.utc),
|
|
697
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
691
698
|
),
|
|
692
699
|
]
|
|
693
700
|
)
|
|
@@ -732,12 +739,12 @@ async def test_stream_text(get_gemini_client: GetGeminiClient):
|
|
|
732
739
|
'Hello world',
|
|
733
740
|
]
|
|
734
741
|
)
|
|
735
|
-
assert result.usage() == snapshot(Usage(requests=1, request_tokens=
|
|
742
|
+
assert result.usage() == snapshot(Usage(requests=1, request_tokens=1, response_tokens=2, total_tokens=3))
|
|
736
743
|
|
|
737
744
|
async with agent.run_stream('Hello') as result:
|
|
738
745
|
chunks = [chunk async for chunk in result.stream_text(delta=True, debounce_by=None)]
|
|
739
746
|
assert chunks == snapshot(['Hello ', 'world'])
|
|
740
|
-
assert result.usage() == snapshot(Usage(requests=1, request_tokens=
|
|
747
|
+
assert result.usage() == snapshot(Usage(requests=1, request_tokens=1, response_tokens=2, total_tokens=3))
|
|
741
748
|
|
|
742
749
|
|
|
743
750
|
async def test_stream_invalid_unicode_text(get_gemini_client: GetGeminiClient):
|
|
@@ -769,7 +776,7 @@ async def test_stream_invalid_unicode_text(get_gemini_client: GetGeminiClient):
|
|
|
769
776
|
async with agent.run_stream('Hello') as result:
|
|
770
777
|
chunks = [chunk async for chunk in result.stream(debounce_by=None)]
|
|
771
778
|
assert chunks == snapshot(['abc', 'abc€def', 'abc€def'])
|
|
772
|
-
assert result.usage() == snapshot(Usage(requests=1, request_tokens=
|
|
779
|
+
assert result.usage() == snapshot(Usage(requests=1, request_tokens=1, response_tokens=2, total_tokens=3))
|
|
773
780
|
|
|
774
781
|
|
|
775
782
|
async def test_stream_text_no_data(get_gemini_client: GetGeminiClient):
|
|
@@ -840,7 +847,7 @@ async def test_stream_structured_tool_calls(get_gemini_client: GetGeminiClient):
|
|
|
840
847
|
async with agent.run_stream('Hello') as result:
|
|
841
848
|
response = await result.get_output()
|
|
842
849
|
assert response == snapshot((1, 2))
|
|
843
|
-
assert result.usage() == snapshot(Usage(requests=2, request_tokens=
|
|
850
|
+
assert result.usage() == snapshot(Usage(requests=2, request_tokens=2, response_tokens=4, total_tokens=6))
|
|
844
851
|
assert result.all_messages() == snapshot(
|
|
845
852
|
[
|
|
846
853
|
ModelRequest(parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))]),
|
|
@@ -849,7 +856,7 @@ async def test_stream_structured_tool_calls(get_gemini_client: GetGeminiClient):
|
|
|
849
856
|
ToolCallPart(tool_name='foo', args={'x': 'a'}, tool_call_id=IsStr()),
|
|
850
857
|
ToolCallPart(tool_name='bar', args={'y': 'b'}, tool_call_id=IsStr()),
|
|
851
858
|
],
|
|
852
|
-
usage=Usage(request_tokens=
|
|
859
|
+
usage=Usage(request_tokens=1, response_tokens=2, total_tokens=3, details={}),
|
|
853
860
|
model_name='gemini-1.5-flash',
|
|
854
861
|
timestamp=IsNow(tz=timezone.utc),
|
|
855
862
|
),
|
|
@@ -865,7 +872,7 @@ async def test_stream_structured_tool_calls(get_gemini_client: GetGeminiClient):
|
|
|
865
872
|
),
|
|
866
873
|
ModelResponse(
|
|
867
874
|
parts=[ToolCallPart(tool_name='final_result', args={'response': [1, 2]}, tool_call_id=IsStr())],
|
|
868
|
-
usage=Usage(request_tokens=1, response_tokens=2, total_tokens=3),
|
|
875
|
+
usage=Usage(request_tokens=1, response_tokens=2, total_tokens=3, details={}),
|
|
869
876
|
model_name='gemini-1.5-flash',
|
|
870
877
|
timestamp=IsNow(tz=timezone.utc),
|
|
871
878
|
),
|
|
@@ -1096,9 +1103,16 @@ I need to use the `get_image` tool to see the image first.
|
|
|
1096
1103
|
),
|
|
1097
1104
|
ToolCallPart(tool_name='get_image', args={}, tool_call_id=IsStr()),
|
|
1098
1105
|
],
|
|
1099
|
-
usage=Usage(
|
|
1106
|
+
usage=Usage(
|
|
1107
|
+
requests=1,
|
|
1108
|
+
request_tokens=38,
|
|
1109
|
+
response_tokens=28,
|
|
1110
|
+
total_tokens=427,
|
|
1111
|
+
details={'thoughts_tokens': 361, 'text_prompt_tokens': 38},
|
|
1112
|
+
),
|
|
1100
1113
|
model_name='gemini-2.5-pro-preview-03-25',
|
|
1101
1114
|
timestamp=IsDatetime(),
|
|
1115
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
1102
1116
|
),
|
|
1103
1117
|
ModelRequest(
|
|
1104
1118
|
parts=[
|
|
@@ -1119,9 +1133,16 @@ I need to use the `get_image` tool to see the image first.
|
|
|
1119
1133
|
),
|
|
1120
1134
|
ModelResponse(
|
|
1121
1135
|
parts=[TextPart(content='The image shows a kiwi fruit, sliced in half.')],
|
|
1122
|
-
usage=Usage(
|
|
1136
|
+
usage=Usage(
|
|
1137
|
+
requests=1,
|
|
1138
|
+
request_tokens=360,
|
|
1139
|
+
response_tokens=11,
|
|
1140
|
+
total_tokens=572,
|
|
1141
|
+
details={'thoughts_tokens': 201, 'text_prompt_tokens': 102, 'image_prompt_tokens': 258},
|
|
1142
|
+
),
|
|
1123
1143
|
model_name='gemini-2.5-pro-preview-03-25',
|
|
1124
1144
|
timestamp=IsDatetime(),
|
|
1145
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
1125
1146
|
),
|
|
1126
1147
|
]
|
|
1127
1148
|
)
|
|
@@ -1241,9 +1262,16 @@ async def test_gemini_model_instructions(allow_model_requests: None, gemini_api_
|
|
|
1241
1262
|
),
|
|
1242
1263
|
ModelResponse(
|
|
1243
1264
|
parts=[TextPart(content='The capital of France is Paris.\n')],
|
|
1244
|
-
usage=Usage(
|
|
1265
|
+
usage=Usage(
|
|
1266
|
+
requests=1,
|
|
1267
|
+
request_tokens=13,
|
|
1268
|
+
response_tokens=8,
|
|
1269
|
+
total_tokens=21,
|
|
1270
|
+
details={'text_prompt_tokens': 13, 'text_candidates_tokens': 8},
|
|
1271
|
+
),
|
|
1245
1272
|
model_name='gemini-1.5-flash',
|
|
1246
1273
|
timestamp=IsDatetime(),
|
|
1274
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
1247
1275
|
),
|
|
1248
1276
|
]
|
|
1249
1277
|
)
|
|
@@ -1284,3 +1312,18 @@ async def test_gemini_additional_properties_is_true(allow_model_requests: None,
|
|
|
1284
1312
|
assert result.output == snapshot(
|
|
1285
1313
|
'I need a location dictionary to use the `get_temperature` function. I cannot provide the temperature in Tokyo without more information.\n'
|
|
1286
1314
|
)
|
|
1315
|
+
|
|
1316
|
+
|
|
1317
|
+
async def test_gemini_no_finish_reason(get_gemini_client: GetGeminiClient):
|
|
1318
|
+
response = gemini_response(
|
|
1319
|
+
_content_model_response(ModelResponse(parts=[TextPart('Hello world')])), finish_reason=None
|
|
1320
|
+
)
|
|
1321
|
+
gemini_client = get_gemini_client(response)
|
|
1322
|
+
m = GeminiModel('gemini-1.5-flash', provider=GoogleGLAProvider(http_client=gemini_client))
|
|
1323
|
+
agent = Agent(m)
|
|
1324
|
+
|
|
1325
|
+
result = await agent.run('Hello World')
|
|
1326
|
+
|
|
1327
|
+
for message in result.all_messages():
|
|
1328
|
+
if isinstance(message, ModelResponse):
|
|
1329
|
+
assert message.vendor_details is None
|
|
@@ -65,7 +65,15 @@ async def test_google_model(allow_model_requests: None, google_provider: GoogleP
|
|
|
65
65
|
|
|
66
66
|
result = await agent.run('Hello!')
|
|
67
67
|
assert result.output == snapshot('Hello there! How can I help you today?\n')
|
|
68
|
-
assert result.usage() == snapshot(
|
|
68
|
+
assert result.usage() == snapshot(
|
|
69
|
+
Usage(
|
|
70
|
+
requests=1,
|
|
71
|
+
request_tokens=7,
|
|
72
|
+
response_tokens=11,
|
|
73
|
+
total_tokens=18,
|
|
74
|
+
details={'text_prompt_tokens': 7, 'text_candidates_tokens': 11},
|
|
75
|
+
)
|
|
76
|
+
)
|
|
69
77
|
assert result.all_messages() == snapshot(
|
|
70
78
|
[
|
|
71
79
|
ModelRequest(
|
|
@@ -82,9 +90,16 @@ async def test_google_model(allow_model_requests: None, google_provider: GoogleP
|
|
|
82
90
|
),
|
|
83
91
|
ModelResponse(
|
|
84
92
|
parts=[TextPart(content='Hello there! How can I help you today?\n')],
|
|
85
|
-
usage=Usage(
|
|
93
|
+
usage=Usage(
|
|
94
|
+
requests=1,
|
|
95
|
+
request_tokens=7,
|
|
96
|
+
response_tokens=11,
|
|
97
|
+
total_tokens=18,
|
|
98
|
+
details={'text_prompt_tokens': 7, 'text_candidates_tokens': 11},
|
|
99
|
+
),
|
|
86
100
|
model_name='gemini-1.5-flash',
|
|
87
101
|
timestamp=IsDatetime(),
|
|
102
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
88
103
|
),
|
|
89
104
|
]
|
|
90
105
|
)
|
|
@@ -114,7 +129,15 @@ async def test_google_model_structured_response(allow_model_requests: None, goog
|
|
|
114
129
|
|
|
115
130
|
result = await agent.run('What was the temperature in London 1st January 2022?', output_type=Response)
|
|
116
131
|
assert result.output == snapshot({'temperature': '30°C', 'date': datetime.date(2022, 1, 1), 'city': 'London'})
|
|
117
|
-
assert result.usage() == snapshot(
|
|
132
|
+
assert result.usage() == snapshot(
|
|
133
|
+
Usage(
|
|
134
|
+
requests=2,
|
|
135
|
+
request_tokens=224,
|
|
136
|
+
response_tokens=35,
|
|
137
|
+
total_tokens=259,
|
|
138
|
+
details={'text_prompt_tokens': 224, 'text_candidates_tokens': 35},
|
|
139
|
+
)
|
|
140
|
+
)
|
|
118
141
|
assert result.all_messages() == snapshot(
|
|
119
142
|
[
|
|
120
143
|
ModelRequest(
|
|
@@ -135,9 +158,16 @@ async def test_google_model_structured_response(allow_model_requests: None, goog
|
|
|
135
158
|
tool_name='temperature', args={'date': '2022-01-01', 'city': 'London'}, tool_call_id=IsStr()
|
|
136
159
|
)
|
|
137
160
|
],
|
|
138
|
-
usage=Usage(
|
|
161
|
+
usage=Usage(
|
|
162
|
+
requests=1,
|
|
163
|
+
request_tokens=101,
|
|
164
|
+
response_tokens=14,
|
|
165
|
+
total_tokens=115,
|
|
166
|
+
details={'text_prompt_tokens': 101, 'text_candidates_tokens': 14},
|
|
167
|
+
),
|
|
139
168
|
model_name='gemini-1.5-flash',
|
|
140
169
|
timestamp=IsDatetime(),
|
|
170
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
141
171
|
),
|
|
142
172
|
ModelRequest(
|
|
143
173
|
parts=[
|
|
@@ -154,9 +184,16 @@ async def test_google_model_structured_response(allow_model_requests: None, goog
|
|
|
154
184
|
tool_call_id=IsStr(),
|
|
155
185
|
)
|
|
156
186
|
],
|
|
157
|
-
usage=Usage(
|
|
187
|
+
usage=Usage(
|
|
188
|
+
requests=1,
|
|
189
|
+
request_tokens=123,
|
|
190
|
+
response_tokens=21,
|
|
191
|
+
total_tokens=144,
|
|
192
|
+
details={'text_prompt_tokens': 123, 'text_candidates_tokens': 21},
|
|
193
|
+
),
|
|
158
194
|
model_name='gemini-1.5-flash',
|
|
159
195
|
timestamp=IsDatetime(),
|
|
196
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
160
197
|
),
|
|
161
198
|
ModelRequest(
|
|
162
199
|
parts=[
|
|
@@ -211,10 +248,11 @@ async def test_google_model_retry(allow_model_requests: None, google_provider: G
|
|
|
211
248
|
request_tokens=57,
|
|
212
249
|
response_tokens=15,
|
|
213
250
|
total_tokens=173,
|
|
214
|
-
details={'
|
|
251
|
+
details={'thoughts_tokens': 101, 'text_prompt_tokens': 57},
|
|
215
252
|
),
|
|
216
253
|
model_name='models/gemini-2.5-pro-preview-05-06',
|
|
217
254
|
timestamp=IsDatetime(),
|
|
255
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
218
256
|
),
|
|
219
257
|
ModelRequest(
|
|
220
258
|
parts=[
|
|
@@ -232,9 +270,16 @@ async def test_google_model_retry(allow_model_requests: None, google_provider: G
|
|
|
232
270
|
content='I am sorry, I cannot fulfill this request. The country you provided is not supported.'
|
|
233
271
|
)
|
|
234
272
|
],
|
|
235
|
-
usage=Usage(
|
|
273
|
+
usage=Usage(
|
|
274
|
+
requests=1,
|
|
275
|
+
request_tokens=104,
|
|
276
|
+
response_tokens=18,
|
|
277
|
+
total_tokens=122,
|
|
278
|
+
details={'text_prompt_tokens': 104},
|
|
279
|
+
),
|
|
236
280
|
model_name='models/gemini-2.5-pro-preview-05-06',
|
|
237
281
|
timestamp=IsDatetime(),
|
|
282
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
238
283
|
),
|
|
239
284
|
]
|
|
240
285
|
)
|
|
@@ -488,9 +533,16 @@ async def test_google_model_instructions(allow_model_requests: None, google_prov
|
|
|
488
533
|
),
|
|
489
534
|
ModelResponse(
|
|
490
535
|
parts=[TextPart(content='The capital of France is Paris.\n')],
|
|
491
|
-
usage=Usage(
|
|
536
|
+
usage=Usage(
|
|
537
|
+
requests=1,
|
|
538
|
+
request_tokens=13,
|
|
539
|
+
response_tokens=8,
|
|
540
|
+
total_tokens=21,
|
|
541
|
+
details={'text_prompt_tokens': 13, 'text_candidates_tokens': 8},
|
|
542
|
+
),
|
|
492
543
|
model_name='gemini-2.0-flash',
|
|
493
544
|
timestamp=IsDatetime(),
|
|
545
|
+
vendor_details={'finish_reason': 'STOP'},
|
|
494
546
|
),
|
|
495
547
|
]
|
|
496
548
|
)
|