Skip to content

Commit 225ede0

Browse files
committed
removed hosted image gen
1 parent 9fc29e0 commit 225ede0

File tree

6 files changed

+142
-274
lines changed

6 files changed

+142
-274
lines changed

python/packages/main/agent_framework/_tools.py

Lines changed: 1 addition & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
)
2323

2424
from opentelemetry import metrics
25-
from pydantic import AnyUrl, BaseModel, ConfigDict, Field, PrivateAttr, ValidationError, create_model, field_validator
25+
from pydantic import AnyUrl, BaseModel, Field, PrivateAttr, ValidationError, create_model, field_validator
2626

2727
from ._logging import get_logger
2828
from ._pydantic import AFBaseModel
@@ -58,7 +58,6 @@
5858
"AIFunction",
5959
"HostedCodeInterpreterTool",
6060
"HostedFileSearchTool",
61-
"HostedImageGenerationTool",
6261
"HostedMCPSpecificApproval",
6362
"HostedMCPTool",
6463
"HostedWebSearchTool",
@@ -236,93 +235,6 @@ def __init__(
236235
super().__init__(**args, **kwargs)
237236

238237

239-
class HostedImageGenerationTool(BaseTool):
240-
"""Represents an image generation tool that can be specified to an AI service to enable it to generate images."""
241-
242-
# Allow extra fields for provider-specific parameters
243-
model_config = ConfigDict(extra="allow")
244-
245-
# Image generation parameters
246-
size: Literal["1024x1024", "1536x1024", "1024x1536", "auto"] | None = None
247-
quality: Literal["low", "medium", "high", "auto"] | None = None
248-
format: Literal["png", "jpeg", "webp"] | None = None
249-
compression: int | None = None
250-
background: Literal["transparent", "opaque", "auto"] | None = None
251-
252-
def __init__(
253-
self,
254-
description: str | None = None,
255-
size: Literal["1024x1024", "1536x1024", "1024x1536", "auto"] | None = None,
256-
quality: Literal["low", "medium", "high", "auto"] | None = None,
257-
format: Literal["png", "jpeg", "webp"] | None = None,
258-
compression: int | None = None,
259-
background: Literal["transparent", "opaque", "auto"] | None = None,
260-
additional_properties: dict[str, Any] | None = None,
261-
**kwargs: Any,
262-
):
263-
"""Initialize a HostedImageGenerationTool.
264-
265-
Args:
266-
description: A description of the tool.
267-
size: Image dimensions. Defaults to "auto".
268-
- "1024x1024": Square format
269-
- "1536x1024": Landscape format
270-
- "1024x1536": Portrait format
271-
- "auto": Model automatically selects best size based on prompt
272-
quality: Rendering quality. Defaults to "auto".
273-
- "low": Low quality, fastest generation
274-
- "medium": Medium quality
275-
- "high": High quality, slower generation
276-
- "auto": Model automatically selects best quality based on prompt
277-
format: File output format. Defaults to "png".
278-
- "png": PNG format (default)
279-
- "jpeg": JPEG format
280-
- "webp": WebP format
281-
compression: Compression level (0-100%) for JPEG and WebP formats only.
282-
Higher values mean more compression (smaller file, lower quality).
283-
Only applicable when format is "jpeg" or "webp".
284-
background: Background type. Defaults to "auto". (only supported by 'gpt-image-1' and with png and webp)
285-
- "transparent": Transparent background
286-
- "opaque": Opaque background
287-
- "auto": Model automatically selects based on prompt
288-
additional_properties: Additional properties associated with the tool.
289-
**kwargs: Additional keyword arguments to pass to the base class.
290-
Provider-specific parameters can be passed as kwargs.
291-
"""
292-
# Validate compression parameter
293-
if compression is not None:
294-
if not isinstance(compression, int) or not (0 <= compression <= 100):
295-
raise ValueError("compression must be an integer between 0 and 100")
296-
if format not in ("jpeg", "webp"):
297-
raise ValueError("compression parameter only applies to 'jpeg' and 'webp' formats")
298-
299-
if "name" in kwargs:
300-
raise ValueError("The 'name' argument is reserved for the HostedImageGenerationTool and cannot be set.")
301-
302-
# Pass all parameters to the parent class
303-
args: dict[str, Any] = {
304-
"name": "image_generation",
305-
"size": size,
306-
"quality": quality,
307-
"format": format,
308-
"compression": compression,
309-
"background": background,
310-
}
311-
312-
if description is not None:
313-
args["description"] = description
314-
if additional_properties is not None:
315-
args["additional_properties"] = additional_properties
316-
317-
super().__init__(**args)
318-
319-
# Handle OpenAI-specific parameters as attributes
320-
openai_params = ["model", "moderation", "partial_images", "input_fidelity", "input_image_mask"]
321-
for param in openai_params:
322-
if param in kwargs:
323-
setattr(self, param, kwargs[param])
324-
325-
326238
class HostedMCPSpecificApproval(TypedDict, total=False):
327239
"""Represents the `specific` mode for a hosted tool.
328240

python/packages/main/agent_framework/_types.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2108,14 +2108,6 @@ async def from_agent_response_generator(
21082108
def __str__(self) -> str:
21092109
return self.text
21102110

2111-
def try_parse_value(self, output_format_type: type[BaseModel]) -> None:
2112-
"""If there is a value, does nothing, otherwise tries to parse the text into the value."""
2113-
if self.value is None:
2114-
try:
2115-
self.value = output_format_type.model_validate_json(self.text) # type: ignore[reportUnknownMemberType]
2116-
except ValidationError as ex:
2117-
logger.debug("Failed to parse value from agent run response text: %s", ex)
2118-
21192111

21202112
# region AgentRunResponseUpdate
21212113

python/packages/main/agent_framework/openai/_responses_client.py

Lines changed: 93 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
AIFunction,
3131
HostedCodeInterpreterTool,
3232
HostedFileSearchTool,
33-
HostedImageGenerationTool,
3433
HostedMCPTool,
3534
HostedWebSearchTool,
3635
ToolProtocol,
@@ -270,59 +269,102 @@ def _tools_to_response_tools(
270269
else None,
271270
)
272271
)
273-
case HostedImageGenerationTool():
274-
image_tool: dict[str, Any] = {"type": "image_generation"}
275-
276-
# Handle base parameters as direct attributes
277-
if tool.size is not None:
278-
image_tool["size"] = tool.size
279-
if tool.quality is not None:
280-
image_tool["quality"] = tool.quality
281-
if tool.background is not None:
282-
image_tool["background"] = tool.background
283-
284-
# Map developer-friendly parameter names to OpenAI API names
285-
if tool.format is not None:
286-
image_tool["output_format"] = tool.format
287-
if tool.compression is not None:
288-
image_tool["output_compression"] = tool.compression
289-
290-
# Handle OpenAI Responses-specific parameters
291-
openai_param_names = [
292-
"model",
293-
"moderation",
294-
"partial_images",
295-
"input_fidelity",
296-
"input_image_mask",
297-
]
298-
for param in openai_param_names:
299-
value = getattr(tool, param, None)
300-
if value is not None:
301-
# Validate OpenAI Responses-specific parameters
302-
if param == "partial_images" and (not isinstance(value, int) or not (0 <= value <= 3)):
303-
raise ValueError("partial_images must be an integer between 0 and 3")
304-
if param == "input_fidelity" and value not in ("high", "low"):
305-
raise ValueError("input_fidelity must be 'high' or 'low'")
306-
if param == "input_image_mask":
307-
if not isinstance(value, dict):
308-
raise ValueError("input_image_mask must be a dictionary")
309-
# Validate that it has at least one of the required fields
310-
if not any(key in value for key in ["file_id", "image_url"]):
311-
raise ValueError(
312-
"input_image_mask must contain at least one of 'file_id' or 'image_url'"
313-
)
314-
# Validate field types if present
315-
if "file_id" in value and not isinstance(value["file_id"], str):
316-
raise ValueError("input_image_mask.file_id must be a string")
317-
if "image_url" in value and not isinstance(value["image_url"], str):
318-
raise ValueError("input_image_mask.image_url must be a string")
319-
image_tool[param] = value
320-
321-
response_tools.append(image_tool)
272+
322273
case _:
323274
logger.debug("Unsupported tool passed (type: %s)", type(tool))
324275
else:
325-
response_tools.append(tool if isinstance(tool, dict) else dict(tool))
276+
# Handle raw dictionary tools
277+
tool_dict = tool if isinstance(tool, dict) else dict(tool)
278+
279+
# Special handling for image_generation tools
280+
if tool_dict.get("type") == "image_generation":
281+
# Create a copy to avoid modifying the original
282+
mapped_tool = tool_dict.copy()
283+
284+
# Map user-friendly parameter names to OpenAI API parameter names
285+
parameter_mapping = {
286+
"format": "output_format",
287+
"compression": "output_compression",
288+
}
289+
290+
for user_param, api_param in parameter_mapping.items():
291+
if user_param in mapped_tool:
292+
# Map the parameter name and remove the old one
293+
mapped_tool[api_param] = mapped_tool.pop(user_param)
294+
295+
# Validate all OpenAI image generation parameters
296+
297+
# Background validation
298+
if "background" in mapped_tool:
299+
value = mapped_tool["background"]
300+
if value not in ("transparent", "opaque", "auto"):
301+
raise ValueError("background must be one of: 'transparent', 'opaque', 'auto'")
302+
303+
# Input fidelity validation
304+
if "input_fidelity" in mapped_tool:
305+
value = mapped_tool["input_fidelity"]
306+
if value not in ("high", "low"):
307+
raise ValueError("input_fidelity must be 'high' or 'low'")
308+
309+
# Input image mask validation
310+
if "input_image_mask" in mapped_tool:
311+
value = mapped_tool["input_image_mask"]
312+
if not isinstance(value, dict):
313+
raise ValueError("input_image_mask must be a dictionary")
314+
# Validate that it has at least one of the required fields
315+
if not any(key in value for key in ["file_id", "image_url"]):
316+
raise ValueError("input_image_mask must contain at least one of 'file_id' or 'image_url'")
317+
# Validate field types if present
318+
if "file_id" in value and not isinstance(value["file_id"], str):
319+
raise ValueError("input_image_mask.file_id must be a string")
320+
if "image_url" in value and not isinstance(value["image_url"], str):
321+
raise ValueError("input_image_mask.image_url must be a string")
322+
323+
# Model validation
324+
if "model" in mapped_tool:
325+
value = mapped_tool["model"]
326+
if not isinstance(value, str):
327+
raise ValueError("model must be a string")
328+
329+
# Moderation validation
330+
if "moderation" in mapped_tool:
331+
value = mapped_tool["moderation"]
332+
if not isinstance(value, str):
333+
raise ValueError("moderation must be a string")
334+
335+
# Output compression validation
336+
if "output_compression" in mapped_tool:
337+
value = mapped_tool["output_compression"]
338+
if not isinstance(value, int) or not (1 <= value <= 100):
339+
raise ValueError("output_compression must be an integer between 1 and 100")
340+
341+
# Output format validation
342+
if "output_format" in mapped_tool:
343+
value = mapped_tool["output_format"]
344+
if value not in ("png", "webp", "jpeg"):
345+
raise ValueError("output_format must be one of: 'png', 'webp', 'jpeg'")
346+
347+
# Partial images validation
348+
if "partial_images" in mapped_tool:
349+
value = mapped_tool["partial_images"]
350+
if not isinstance(value, int) or not (0 <= value <= 3):
351+
raise ValueError("partial_images must be an integer between 0 and 3")
352+
353+
# Quality validation
354+
if "quality" in mapped_tool:
355+
value = mapped_tool["quality"]
356+
if value not in ("low", "medium", "high", "auto"):
357+
raise ValueError("quality must be one of: 'low', 'medium', 'high', 'auto'")
358+
359+
# Size validation
360+
if "size" in mapped_tool:
361+
value = mapped_tool["size"]
362+
if value not in ("1024x1024", "1024x1536", "1536x1024", "auto"):
363+
raise ValueError("size must be one of: '1024x1024', '1024x1536', '1536x1024', 'auto'")
364+
365+
response_tools.append(mapped_tool)
366+
else:
367+
response_tools.append(tool_dict)
326368
return response_tools
327369

328370
def _prepare_options(self, messages: MutableSequence[ChatMessage], chat_options: ChatOptions) -> dict[str, Any]:

python/packages/main/tests/main/test_tools.py

Lines changed: 0 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from agent_framework import (
1010
AIFunction,
1111
HostedCodeInterpreterTool,
12-
HostedImageGenerationTool,
1312
HostedMCPTool,
1413
ToolProtocol,
1514
ai_function,
@@ -625,86 +624,3 @@ def test_hosted_mcp_tool_with_dict_of_allowed_tools():
625624
url="https://mcp.example",
626625
allowed_tools={"toolA": "Tool A", "toolC": "Tool C"},
627626
)
628-
629-
630-
# region HostedImageGenerationTool tests
631-
632-
633-
def test_hosted_image_generation_tool_default():
634-
"""Test HostedImageGenerationTool with default parameters."""
635-
tool = HostedImageGenerationTool()
636-
637-
assert tool.name == "image_generation"
638-
assert tool.description == ""
639-
assert tool.additional_properties is None
640-
assert tool.size is None
641-
assert tool.quality is None
642-
assert tool.format is None
643-
assert tool.compression is None
644-
assert tool.background is None
645-
646-
647-
def test_hosted_image_generation_tool_with_all_parameters():
648-
"""Test HostedImageGenerationTool with all parameters specified."""
649-
tool = HostedImageGenerationTool(
650-
description="Generate high-quality images",
651-
size="1536x1024",
652-
quality="high",
653-
format="webp",
654-
compression=75,
655-
background="transparent",
656-
additional_properties={"version": "2.0"},
657-
)
658-
659-
assert tool.name == "image_generation"
660-
assert tool.description == "Generate high-quality images"
661-
assert tool.size == "1536x1024"
662-
assert tool.quality == "high"
663-
assert tool.format == "webp"
664-
assert tool.compression == 75
665-
assert tool.background == "transparent"
666-
assert tool.additional_properties == {"version": "2.0"}
667-
assert str(tool) == "HostedImageGenerationTool(name=image_generation, description=Generate high-quality images)"
668-
669-
670-
def test_hosted_image_generation_tool_compression_validation_invalid_range():
671-
"""Test HostedImageGenerationTool compression validation with invalid range."""
672-
with pytest.raises(ValueError, match="compression must be an integer between 0 and 100"):
673-
HostedImageGenerationTool(compression=150, format="jpeg")
674-
675-
with pytest.raises(ValueError, match="compression must be an integer between 0 and 100"):
676-
HostedImageGenerationTool(compression=-10, format="webp")
677-
678-
679-
def test_hosted_image_generation_tool_compression_validation_invalid_format():
680-
"""Test HostedImageGenerationTool compression validation with invalid format."""
681-
with pytest.raises(ValueError, match="compression parameter only applies to 'jpeg' and 'webp' formats"):
682-
HostedImageGenerationTool(compression=50, format="png")
683-
684-
685-
def test_hosted_image_generation_tool_with_openai_kwargs():
686-
"""Test HostedImageGenerationTool with OpenAI-specific parameters via kwargs."""
687-
tool = HostedImageGenerationTool(
688-
size="1024x1024",
689-
model="gpt-image-1",
690-
input_fidelity="high",
691-
moderation="strict",
692-
partial_images=True,
693-
)
694-
695-
assert tool.size == "1024x1024"
696-
# Check that OpenAI Responses-specific parameters are set as attributes
697-
assert hasattr(tool, "model")
698-
assert tool.model == "gpt-image-1" # type: ignore
699-
assert hasattr(tool, "input_fidelity")
700-
assert tool.input_fidelity == "high" # type: ignore
701-
assert hasattr(tool, "moderation")
702-
assert tool.moderation == "strict" # type: ignore
703-
assert hasattr(tool, "partial_images")
704-
assert tool.partial_images is True # type: ignore
705-
706-
707-
def test_hosted_image_generation_tool_reserved_name_validation():
708-
"""Test HostedImageGenerationTool validation of reserved 'name' parameter."""
709-
with pytest.raises(ValueError, match="The 'name' argument is reserved for the HostedImageGenerationTool"):
710-
HostedImageGenerationTool(name="custom_name")

0 commit comments

Comments
 (0)