Files
agent-framework/python/samples/getting_started/tools/failing_tools.py
T
Eduard van Valkenburg fd819c6c02 Python: Introducing AI Function approval (#1131)
* support for local function approval

* small fix

* fix mypy

* added bigger test scenario's for function calling and approvals

* updated lock

* updated return message for rejection

* fix test

* updated function result content handling
2025-10-04 15:19:16 +00:00

104 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from typing import Annotated
from agent_framework import FunctionCallContent, FunctionResultContent
from agent_framework.openai import OpenAIResponsesClient
"""
Tool exceptions handled by returning the error for the agent to recover from.
Shows how a tool that throws an exception creates gracefull recovery and can keep going.
The LLM decides whether to retry the call or to respond with something else, based on the exception.
"""
def greet(name: Annotated[str, "Name to greet"]) -> str:
"""Greet someone."""
return f"Hello, {name}!"
# we trick the AI into calling this function with 0 as denominator to trigger the exception
def safe_divide(
a: Annotated[int, "Numerator"],
b: Annotated[int, "Denominator"],
) -> str:
"""Divide two numbers can be used with 0 as denominator."""
try:
result = a / b # Will raise ZeroDivisionError
except ZeroDivisionError as exc:
print(f" Tool failed: with error: {exc}")
raise
return f"{a} / {b} = {result}"
async def main():
# tools = Tools()
agent = OpenAIResponsesClient().create_agent(
name="ToolAgent",
instructions="Use the provided tools.",
tools=[greet, safe_divide],
)
thread = agent.get_new_thread()
print("=" * 60)
print("Step 1: Call divide(10, 0) - tool raises exception")
response = await agent.run("Divide 10 by 0", thread=thread)
print(f"Response: {response.text}")
print("=" * 60)
print("Step 2: Call greet('Bob') - conversation can keep going.")
response = await agent.run("Greet Bob", thread=thread)
print(f"Response: {response.text}")
print("=" * 60)
print("Replay the conversation:")
assert thread.message_store
assert thread.message_store.list_messages
for idx, msg in enumerate(await thread.message_store.list_messages()):
if msg.text:
print(f"{idx + 1} {msg.author_name or msg.role}: {msg.text} ")
for content in msg.contents:
if isinstance(content, FunctionCallContent):
print(
f"{idx + 1} {msg.author_name}: calling function: {content.name} with arguments: {content.arguments}"
)
if isinstance(content, FunctionResultContent):
print(f"{idx + 1} {msg.role}: {content.result if content.result else content.exception}")
"""
Expected Output:
============================================================
Step 1: Call divide(10, 0) - tool raises exception
Tool failed: with error: division by zero
Response: Division by zero is undefined in standard arithmetic, so 10 ÷ 0 has no meaning.
If youre curious about limits: as x approaches 0 from the positive side, 10/x tends to +∞; from the negative side,
10/x tends to -∞.
If you want a finite result, try dividing by a nonzero number, e.g., 10 ÷ 2 = 5 or 10 ÷ 0.1 = 100. Want me to compute
something else?
============================================================
Step 2: Call greet('Bob') - conversation can keep going.
Response: Hello, Bob!
============================================================
Replay the conversation:
1 user: Divide 10 by 0
2 ToolAgent: calling function: safe_divide with arguments: {"a":10,"b":0}
3 tool: division by zero
4 ToolAgent: Division by zero is undefined in standard arithmetic, so 10 ÷ 0 has no meaning.
If youre curious about limits: as x approaches 0 from the positive side, 10/x tends to +∞; from the negative side,
10/x tends to -∞.
If you want a finite result, try dividing by a nonzero number, e.g., 10 ÷ 2 = 5 or 10 ÷ 0.1 = 100. Want me to compute
something else?
5 user: Greet Bob
6 ToolAgent: calling function: greet with arguments: {"name":"Bob"}
7 tool: Hello, Bob!
8 ToolAgent: Hello, Bob!
"""
if __name__ == "__main__":
asyncio.run(main())