Skip to content

Add error function example in tools #1371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,3 +320,18 @@ When you create a function tool via `@function_tool`, you can pass a `failure_er
- If you explicitly pass `None`, then any tool call errors will be re-raised for you to handle. This could be a `ModelBehaviorError` if the model produced invalid JSON, or a `UserError` if your code crashed, etc.

If you are manually creating a `FunctionTool` object, then you must handle errors inside the `on_invoke_tool` function.

```python
def sync_error_handler(ctx: RunContextWrapper[Any], error: Exception) -> str:
"""Custom error handler that provides a formatted error message."""
return f"An error occurred: {error.__class__.__name__} - {str(error)}"

@function_tool(failure_error_function=sync_error_handler)
def get_latest_news():
"""Get the latest news from the web."""
# This function might fail due to network issues, API limits, etc.
raise ConnectionError("Failed to connect to news service")

# The error handler will be called if the tool fails
# and will return: "An error occurred: ConnectionError - Failed to connect to news service"
```
Comment on lines +323 to +337
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put it before If you are manually creating a FunctionToolobject, then you must handle errors inside theon_invoke_tool function. line?

With this example, it will be even harder to notice that line for class FunctionTool

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its duplicate #1354 Add a comprehensive example for handling function tool errors and you made more comlicated it's hard for beginner

6 changes: 3 additions & 3 deletions src/agents/handoffs.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ class Handoff(Generic[TContext, TAgent]):
True, as it increases the likelihood of correct JSON input.
"""

is_enabled: bool | Callable[
[RunContextWrapper[Any], AgentBase[Any]], MaybeAwaitable[bool]
] = True
is_enabled: bool | Callable[[RunContextWrapper[Any], AgentBase[Any]], MaybeAwaitable[bool]] = (
True
)
"""Whether the handoff is enabled. Either a bool or a Callable that takes the run context and
agent and returns whether the handoff is enabled. You can use this to dynamically enable/disable
a handoff based on your context/state."""
Expand Down
1 change: 0 additions & 1 deletion src/agents/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,6 @@ async def _get_single_step_result_from_streamed_response(
run_config: RunConfig,
tool_use_tracker: AgentToolUseTracker,
) -> SingleStepResult:

original_input = streamed_result.input
pre_step_items = streamed_result.new_items
event_queue = streamed_result._event_queue
Expand Down
4 changes: 2 additions & 2 deletions src/agents/tracing/processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ def set_api_key(self, api_key: str):
client.
"""
# Clear the cached property if it exists
if 'api_key' in self.__dict__:
del self.__dict__['api_key']
if "api_key" in self.__dict__:
del self.__dict__["api_key"]

# Update the private attribute
self._api_key = api_key
Expand Down
5 changes: 2 additions & 3 deletions tests/test_agent_clone_shallow_copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
def greet(name: str) -> str:
return f"Hello, {name}!"


def test_agent_clone_shallow_copy():
"""Test that clone creates shallow copy with tools.copy() workaround"""
target_agent = Agent(name="Target")
Expand All @@ -16,9 +17,7 @@ def test_agent_clone_shallow_copy():
)

cloned = original.clone(
name="Cloned",
tools=original.tools.copy(),
handoffs=original.handoffs.copy()
name="Cloned", tools=original.tools.copy(), handoffs=original.handoffs.copy()
)

# Basic assertions
Expand Down
1 change: 1 addition & 0 deletions tests/test_stream_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ async def foo() -> str:
await asyncio.sleep(3)
return "success!"


@pytest.mark.asyncio
async def test_stream_events_main():
model = FakeModel()
Expand Down