|
5 | 5 | import inspect |
6 | 6 | from collections.abc import Awaitable |
7 | 7 | from dataclasses import dataclass, field |
8 | | -from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, cast |
| 8 | +from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, cast, get_args |
9 | 9 |
|
10 | 10 | from openai.types.responses.response_prompt_param import ResponsePromptParam |
11 | 11 | from typing_extensions import NotRequired, TypeAlias, TypedDict |
12 | 12 |
|
13 | 13 | from .agent_output import AgentOutputSchemaBase |
| 14 | +from .exceptions import UserError |
14 | 15 | from .guardrail import InputGuardrail, OutputGuardrail |
15 | 16 | from .handoffs import Handoff |
16 | 17 | from .items import ItemHelpers |
@@ -246,6 +247,21 @@ def __post_init__(self): |
246 | 247 | if not isinstance(self.tools, list): |
247 | 248 | raise TypeError(f"Agent tools must be a list, got {type(self.tools).__name__}") |
248 | 249 |
|
| 250 | + # Validate each tool is a valid Tool type |
| 251 | + # Tool is a Union type, so we need to get the valid types from it |
| 252 | + valid_tool_types = get_args(Tool) + (Handoff,) |
| 253 | + |
| 254 | + for i, tool in enumerate(self.tools): |
| 255 | + if not isinstance(tool, valid_tool_types): |
| 256 | + # Generate a friendly list of valid types for the error message |
| 257 | + type_names = ", ".join(t.__name__ for t in valid_tool_types) |
| 258 | + raise UserError( |
| 259 | + f"tools[{i}] must be a valid Tool object ({type_names}), " |
| 260 | + f"got {type(tool).__name__}. " |
| 261 | + f"Did you forget to use @function_tool decorator or pass the function itself " |
| 262 | + f"instead of a tool?" |
| 263 | + ) |
| 264 | + |
249 | 265 | if not isinstance(self.mcp_servers, list): |
250 | 266 | raise TypeError( |
251 | 267 | f"Agent mcp_servers must be a list, got {type(self.mcp_servers).__name__}" |
|
0 commit comments