120 lines
3.4 KiB
Python
120 lines
3.4 KiB
Python
"""Human-in-the-loop example with streaming.
|
|
|
|
This example demonstrates the human-in-the-loop (HITL) pattern with streaming.
|
|
The agent will pause execution when a tool requiring approval is called,
|
|
allowing you to approve or reject the tool call before continuing.
|
|
|
|
The streaming version provides real-time feedback as the agent processes
|
|
the request, then pauses for approval when needed.
|
|
"""
|
|
|
|
import asyncio
|
|
|
|
from agents import Agent, Runner, function_tool
|
|
from examples.auto_mode import confirm_with_fallback
|
|
|
|
|
|
async def _needs_temperature_approval(_ctx, params, _call_id) -> bool:
|
|
"""Check if temperature tool needs approval."""
|
|
return "Oakland" in params.get("city", "")
|
|
|
|
|
|
@function_tool(
|
|
# Dynamic approval: only require approval for Oakland
|
|
needs_approval=_needs_temperature_approval
|
|
)
|
|
async def get_temperature(city: str) -> str:
|
|
"""Get the temperature for a given city.
|
|
|
|
Args:
|
|
city: The city to get temperature for.
|
|
|
|
Returns:
|
|
Temperature information for the city.
|
|
"""
|
|
return f"The temperature in {city} is 20° Celsius"
|
|
|
|
|
|
@function_tool
|
|
async def get_weather(city: str) -> str:
|
|
"""Get the weather for a given city.
|
|
|
|
Args:
|
|
city: The city to get weather for.
|
|
|
|
Returns:
|
|
Weather information for the city.
|
|
"""
|
|
return f"The weather in {city} is sunny."
|
|
|
|
|
|
async def confirm(question: str) -> bool:
|
|
"""Prompt user for yes/no confirmation.
|
|
|
|
Args:
|
|
question: The question to ask.
|
|
|
|
Returns:
|
|
True if user confirms, False otherwise.
|
|
"""
|
|
return confirm_with_fallback(f"{question} (y/n): ", default=True)
|
|
|
|
|
|
async def main():
|
|
"""Run the human-in-the-loop example."""
|
|
main_agent = Agent(
|
|
name="Weather Assistant",
|
|
instructions=(
|
|
"You are a helpful weather assistant. "
|
|
"Answer questions about weather and temperature using the available tools."
|
|
),
|
|
tools=[get_temperature, get_weather],
|
|
)
|
|
|
|
# Run the agent with streaming
|
|
result = Runner.run_streamed(
|
|
main_agent,
|
|
"What is the weather and temperature in Oakland?",
|
|
)
|
|
async for _ in result.stream_events():
|
|
pass # Process streaming events silently or could print them
|
|
|
|
# Handle interruptions
|
|
while len(result.interruptions) > 0:
|
|
print("\n" + "=" * 80)
|
|
print("Human-in-the-loop: approval required for the following tool calls:")
|
|
print("=" * 80)
|
|
|
|
state = result.to_state()
|
|
|
|
for interruption in result.interruptions:
|
|
print("\nTool call details:")
|
|
print(f" Agent: {interruption.agent.name}")
|
|
print(f" Tool: {interruption.name}")
|
|
print(f" Arguments: {interruption.arguments}")
|
|
|
|
confirmed = await confirm("\nDo you approve this tool call?")
|
|
|
|
if confirmed:
|
|
print(f"✓ Approved: {interruption.name}")
|
|
state.approve(interruption)
|
|
else:
|
|
print(f"✗ Rejected: {interruption.name}")
|
|
state.reject(interruption)
|
|
|
|
# Resume execution with streaming
|
|
print("\nResuming agent execution...")
|
|
result = Runner.run_streamed(main_agent, state)
|
|
async for _ in result.stream_events():
|
|
pass # Process streaming events silently or could print them
|
|
|
|
print("\n" + "=" * 80)
|
|
print("Final Output:")
|
|
print("=" * 80)
|
|
print(result.final_output)
|
|
print("\nDone!")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|