120 lines
3.7 KiB
Python
120 lines
3.7 KiB
Python
"""
|
|
Example demonstrating OpenAI Conversations session with human-in-the-loop (HITL) tool approval.
|
|
|
|
This example shows how to use OpenAI Conversations session memory combined with
|
|
human-in-the-loop tool approval. The session maintains conversation history while
|
|
requiring approval for specific tool calls.
|
|
"""
|
|
|
|
import asyncio
|
|
|
|
from agents import Agent, OpenAIConversationsSession, Runner, function_tool
|
|
from examples.auto_mode import confirm_with_fallback, input_with_fallback, is_auto_mode
|
|
|
|
|
|
async def _needs_approval(_ctx, _params, _call_id) -> bool:
|
|
"""Always require approval for weather tool."""
|
|
return True
|
|
|
|
|
|
@function_tool(needs_approval=_needs_approval)
|
|
def get_weather(location: str) -> str:
|
|
"""Get weather for a location.
|
|
|
|
Args:
|
|
location: The location to get weather for
|
|
|
|
Returns:
|
|
Weather information as a string
|
|
"""
|
|
# Simulated weather data
|
|
weather_data = {
|
|
"san francisco": "Foggy, 58°F",
|
|
"oakland": "Sunny, 72°F",
|
|
"new york": "Rainy, 65°F",
|
|
}
|
|
# Check if any city name is in the provided location string
|
|
location_lower = location.lower()
|
|
for city, weather in weather_data.items():
|
|
if city in location_lower:
|
|
return weather
|
|
return f"Weather data not available for {location}"
|
|
|
|
|
|
async def prompt_yes_no(question: str) -> bool:
|
|
"""Prompt user for yes/no answer.
|
|
|
|
Args:
|
|
question: The question to ask
|
|
|
|
Returns:
|
|
True if user answered yes, False otherwise
|
|
"""
|
|
return confirm_with_fallback(f"\n{question} (y/n): ", default=True)
|
|
|
|
|
|
async def main():
|
|
# Create an agent with a tool that requires approval
|
|
agent = Agent(
|
|
name="HITL Assistant",
|
|
instructions="You help users with information. Always use available tools when appropriate. Keep responses concise.",
|
|
tools=[get_weather],
|
|
)
|
|
|
|
# Create a session instance that will persist across runs
|
|
session = OpenAIConversationsSession()
|
|
|
|
print("=== OpenAI Session + HITL Example ===")
|
|
print("Enter a message to chat with the agent. Submit an empty line to exit.")
|
|
print("The agent will ask for approval before using tools.\n")
|
|
|
|
auto_mode = is_auto_mode()
|
|
|
|
while True:
|
|
# Get user input
|
|
if auto_mode:
|
|
user_message = input_with_fallback("You: ", "What's the weather in Oakland?")
|
|
else:
|
|
print("You: ", end="", flush=True)
|
|
loop = asyncio.get_event_loop()
|
|
user_message = await loop.run_in_executor(None, input)
|
|
|
|
if not user_message.strip():
|
|
break
|
|
|
|
# Run the agent
|
|
result = await Runner.run(agent, user_message, session=session)
|
|
|
|
# Handle interruptions (tool approvals)
|
|
while result.interruptions:
|
|
# Get the run state
|
|
state = result.to_state()
|
|
|
|
for interruption in result.interruptions:
|
|
tool_name = interruption.name or "Unknown tool"
|
|
args = interruption.arguments or "(no arguments)"
|
|
|
|
approved = await prompt_yes_no(
|
|
f"Agent {interruption.agent.name} wants to call '{tool_name}' with {args}. Approve?"
|
|
)
|
|
|
|
if approved:
|
|
state.approve(interruption)
|
|
print("Approved tool call.")
|
|
else:
|
|
state.reject(interruption)
|
|
print("Rejected tool call.")
|
|
|
|
# Resume the run with the updated state
|
|
result = await Runner.run(agent, state, session=session)
|
|
|
|
# Display the response
|
|
reply = result.final_output or "[No final output produced]"
|
|
print(f"Assistant: {reply}\n")
|
|
if auto_mode:
|
|
break
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|