|
| 1 | +"""Example: tool progress via on_tool_progress hooks. |
| 2 | +
|
| 3 | +Demonstrates how tools can emit intermediate progress updates using |
| 4 | +await ctx.send_progress(data), consumed via RunHooks.on_tool_progress. |
| 5 | +""" |
| 6 | + |
| 7 | +import asyncio |
| 8 | + |
| 9 | +from agents import Agent, RunHooks, Runner, function_tool |
| 10 | +from agents.tool import Tool |
| 11 | +from agents.tool_context import ToolContext |
| 12 | + |
| 13 | + |
| 14 | +@function_tool |
| 15 | +async def analyze_data(ctx: ToolContext, query: str) -> str: |
| 16 | + """Simulate a long-running data analysis task with progress updates.""" |
| 17 | + await ctx.send_progress({"status": "starting", "query": query}) |
| 18 | + await asyncio.sleep(1) |
| 19 | + |
| 20 | + await ctx.send_progress({"status": "fetching_data", "progress": 0.25}) |
| 21 | + await asyncio.sleep(1) |
| 22 | + |
| 23 | + await ctx.send_progress({"status": "processing", "progress": 0.5}) |
| 24 | + await asyncio.sleep(1) |
| 25 | + |
| 26 | + await ctx.send_progress({"status": "finalizing", "progress": 1.0}) |
| 27 | + await asyncio.sleep(0.5) |
| 28 | + |
| 29 | + return f"Analysis complete for '{query}': found 42 results with 95% confidence." |
| 30 | + |
| 31 | + |
| 32 | +@function_tool |
| 33 | +async def quick_lookup(ctx: ToolContext, term: str) -> str: |
| 34 | + """A faster tool that also emits progress.""" |
| 35 | + await ctx.send_progress({"status": "searching", "term": term}) |
| 36 | + await asyncio.sleep(0.5) |
| 37 | + return f"Found definition for '{term}': a common search term." |
| 38 | + |
| 39 | + |
| 40 | +class ProgressHooks(RunHooks): |
| 41 | + async def on_tool_progress(self, ctx, agent, tool: Tool, data): |
| 42 | + print(f" [progress] {tool.name}: {data}") |
| 43 | + |
| 44 | + |
| 45 | +async def main(): |
| 46 | + agent = Agent( |
| 47 | + name="Analyst", |
| 48 | + instructions=( |
| 49 | + "You are a data analyst. Use the analyze_data tool for complex queries " |
| 50 | + "and quick_lookup for simple lookups. Always use the tools when asked." |
| 51 | + ), |
| 52 | + tools=[analyze_data, quick_lookup], |
| 53 | + ) |
| 54 | + |
| 55 | + hooks = ProgressHooks() |
| 56 | + |
| 57 | + print("Interactive tool progress example (hooks-based).") |
| 58 | + print("Type a message to chat, or 'quit' to exit.\n") |
| 59 | + |
| 60 | + while True: |
| 61 | + user_input = input("You: ").strip() |
| 62 | + if not user_input or user_input.lower() == "quit": |
| 63 | + print("Goodbye!") |
| 64 | + break |
| 65 | + |
| 66 | + result = Runner.run_streamed(agent, input=user_input, hooks=hooks) |
| 67 | + async for event in result.stream_events(): |
| 68 | + if event.type == "raw_response_event": |
| 69 | + data = event.data |
| 70 | + if getattr(data, "type", None) == "response.output_text.delta": |
| 71 | + print(getattr(data, "delta", ""), end="", flush=True) |
| 72 | + elif event.type == "agent_updated_stream_event": |
| 73 | + print(f"Agent: {event.new_agent.name}") |
| 74 | + elif event.type == "run_item_stream_event": |
| 75 | + if event.item.type == "tool_call_item": |
| 76 | + print(f"\n-- Tool called: {getattr(event.item.raw_item, 'name', '?')}") |
| 77 | + elif event.item.type == "tool_call_output_item": |
| 78 | + print(f"\n-- Tool output: {event.item.output}") |
| 79 | + elif event.item.type == "message_output_item": |
| 80 | + print() # newline after streamed tokens |
| 81 | + |
| 82 | + print() |
| 83 | + |
| 84 | + |
| 85 | +if __name__ == "__main__": |
| 86 | + asyncio.run(main()) |
0 commit comments