|
1 | 1 | import json |
2 | 2 | import re |
3 | 3 | from dataclasses import replace |
4 | | -from typing import Any, cast |
| 4 | +from typing import Any, Literal, cast |
5 | 5 |
|
6 | 6 | import pytest |
7 | 7 | from inline_snapshot import snapshot |
|
32 | 32 | ToolCallPartDelta, |
33 | 33 | ToolReturnPart, |
34 | 34 | UnexpectedModelBehavior, |
| 35 | + UserError, |
35 | 36 | UserPromptPart, |
36 | 37 | capture_run_messages, |
37 | 38 | ) |
38 | 39 | from pydantic_ai.agent import Agent |
39 | | -from pydantic_ai.builtin_tools import CodeExecutionTool, MCPServerTool, WebSearchTool |
| 40 | +from pydantic_ai.builtin_tools import CodeExecutionTool, ImageAspectRatio, MCPServerTool, WebSearchTool |
40 | 41 | from pydantic_ai.exceptions import ModelHTTPError, ModelRetry |
41 | 42 | from pydantic_ai.messages import ( |
42 | 43 | BuiltinToolCallEvent, # pyright: ignore[reportDeprecated] |
43 | 44 | BuiltinToolResultEvent, # pyright: ignore[reportDeprecated] |
44 | 45 | ) |
45 | 46 | from pydantic_ai.models import ModelRequestParameters |
| 47 | +from pydantic_ai.models.openai import _resolve_openai_image_generation_size # pyright: ignore[reportPrivateUsage] |
46 | 48 | from pydantic_ai.output import NativeOutput, PromptedOutput, TextOutput, ToolOutput |
47 | 49 | from pydantic_ai.profiles.openai import openai_model_profile |
48 | 50 | from pydantic_ai.tools import ToolDefinition |
@@ -128,6 +130,37 @@ async def test_openai_responses_image_detail_vendor_metadata(allow_model_request |
128 | 130 | assert all(part['detail'] == 'high' for part in image_parts) |
129 | 131 |
|
130 | 132 |
|
| 133 | +@pytest.mark.parametrize( |
| 134 | + ('aspect_ratio', 'explicit_size', 'expected_size'), |
| 135 | + [ |
| 136 | + ('1:1', 'auto', '1024x1024'), |
| 137 | + ('2:3', '1024x1536', '1024x1536'), |
| 138 | + ('3:2', 'auto', '1536x1024'), |
| 139 | + ], |
| 140 | +) |
| 141 | +def test_openai_responses_image_generation_tool_aspect_ratio_mapping( |
| 142 | + aspect_ratio: ImageAspectRatio, |
| 143 | + explicit_size: Literal['1024x1024', '1024x1536', '1536x1024', 'auto'], |
| 144 | + expected_size: Literal['1024x1024', '1024x1536', '1536x1024'], |
| 145 | +) -> None: |
| 146 | + tool = ImageGenerationTool(aspect_ratio=aspect_ratio, size=explicit_size) |
| 147 | + assert _resolve_openai_image_generation_size(tool) == expected_size |
| 148 | + |
| 149 | + |
| 150 | +def test_openai_responses_image_generation_tool_aspect_ratio_invalid() -> None: |
| 151 | + tool = ImageGenerationTool(aspect_ratio='16:9') |
| 152 | + |
| 153 | + with pytest.raises(UserError, match='OpenAI image generation only supports `aspect_ratio` values'): |
| 154 | + _resolve_openai_image_generation_size(tool) |
| 155 | + |
| 156 | + |
| 157 | +def test_openai_responses_image_generation_tool_aspect_ratio_conflicts_with_size() -> None: |
| 158 | + tool = ImageGenerationTool(aspect_ratio='1:1', size='1536x1024') |
| 159 | + |
| 160 | + with pytest.raises(UserError, match='cannot combine `aspect_ratio` with a conflicting `size`'): |
| 161 | + _resolve_openai_image_generation_size(tool) |
| 162 | + |
| 163 | + |
131 | 164 | async def test_openai_responses_model_simple_response_with_tool_call(allow_model_requests: None, openai_api_key: str): |
132 | 165 | model = OpenAIResponsesModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) |
133 | 166 |
|
|
0 commit comments