1- from __future__ import annotations as _annotations
1+ from __future__ import annotations
22
33import asyncio
44import random
55import uuid
66
77from pydantic import BaseModel
88
9- from agents import (
9+ from src . agents import (
1010 Agent ,
1111 HandoffOutputItem ,
1212 ItemHelpers ,
1313 MessageOutputItem ,
14+ ModelSettings ,
1415 RunContextWrapper ,
16+ RunConfig ,
1517 Runner ,
1618 ToolCallItem ,
1719 ToolCallOutputItem ,
2022 handoff ,
2123 trace ,
2224)
23- from agents .extensions .handoff_prompt import RECOMMENDED_PROMPT_PREFIX
25+ from src . agents .extensions .handoff_prompt import RECOMMENDED_PROMPT_PREFIX
2426
2527### CONTEXT
2628
@@ -74,9 +76,13 @@ async def update_seat(
7476 assert context .context .flight_number is not None , "Flight number is required"
7577 return f"Updated seat to { new_seat } for confirmation number { confirmation_number } "
7678
77-
78- ### HOOKS
79-
79+ @function_tool
80+ async def respond_to_user (response : str ) -> str :
81+ """
82+ Use this function to send a message back to the end user. The agent should call this whenever
83+ you want to produce a user-facing response.
84+ """
85+ return response
8086
8187async def on_seat_booking_handoff (context : RunContextWrapper [AirlineAgentContext ]) -> None :
8288 flight_number = f"FLT-{ random .randint (100 , 999 )} "
@@ -95,7 +101,7 @@ async def on_seat_booking_handoff(context: RunContextWrapper[AirlineAgentContext
95101 1. Identify the last question asked by the customer.
96102 2. Use the faq lookup tool to answer the question. Do not rely on your own knowledge.
97103 3. If you cannot answer the question, transfer back to the triage agent.""" ,
98- tools = [faq_lookup_tool ],
104+ tools = [faq_lookup_tool , respond_to_user ],
99105)
100106
101107seat_booking_agent = Agent [AirlineAgentContext ](
@@ -109,7 +115,7 @@ async def on_seat_booking_handoff(context: RunContextWrapper[AirlineAgentContext
109115 2. Ask the customer what their desired seat number is.
110116 3. Use the update seat tool to update the seat on the flight.
111117 If the customer asks a question that is not related to the routine, transfer back to the triage agent. """ ,
112- tools = [update_seat ],
118+ tools = [update_seat , respond_to_user ],
113119)
114120
115121triage_agent = Agent [AirlineAgentContext ](
@@ -122,7 +128,12 @@ async def on_seat_booking_handoff(context: RunContextWrapper[AirlineAgentContext
122128 handoffs = [
123129 faq_agent ,
124130 handoff (agent = seat_booking_agent , on_handoff = on_seat_booking_handoff ),
131+ respond_to_user
125132 ],
133+ tools = [respond_to_user ],
134+ model_settings = ModelSettings (tool_choice = "required" ),
135+ tool_use_behavior = {"stop_at_tool_names" : ["respond_to_user" ]},
136+
126137)
127138
128139faq_agent .handoffs .append (triage_agent )
@@ -145,20 +156,30 @@ async def main():
145156 user_input = input ("Enter your message: " )
146157 with trace ("Customer service" , group_id = conversation_id ):
147158 input_items .append ({"content" : user_input , "role" : "user" })
148- result = await Runner .run (current_agent , input_items , context = context )
159+ result = await Runner .run (current_agent , input_items , context = context , run_config = RunConfig ( tracing_disabled = True ) )
149160
161+ last_tool_name : str | None = None
150162 for new_item in result .new_items :
151163 agent_name = new_item .agent .name
152164 if isinstance (new_item , MessageOutputItem ):
165+ # In tool_choice="required" scenarios, the agent won't produce bare messages;
166+ # instead it will call `respond_to_user`. But if the example is run without
167+ # requiring tool_choice, this branch will handle direct messages.
153168 print (f"{ agent_name } : { ItemHelpers .text_message_output (new_item )} " )
154169 elif isinstance (new_item , HandoffOutputItem ):
155170 print (
156171 f"Handed off from { new_item .source_agent .name } to { new_item .target_agent .name } "
157172 )
158173 elif isinstance (new_item , ToolCallItem ):
159- print (f"{ agent_name } : Calling a tool" )
174+ # Stash the name of the tool call so we can treat respond_to_user specially
175+ last_tool_name = getattr (new_item .raw_item , "name" , None )
176+ print (f"{ agent_name } called tool:{ f' { last_tool_name } ' if last_tool_name else '' } " )
160177 elif isinstance (new_item , ToolCallOutputItem ):
161- print (f"{ agent_name } : Tool call output: { new_item .output } " )
178+ # If the tool call was respond_to_user, treat its output as the message to display.
179+ if last_tool_name == "respond_to_user" :
180+ print (f"{ agent_name } : { new_item .output } " )
181+ else :
182+ print (f"{ agent_name } : Tool call output: { new_item .output } " )
162183 else :
163184 print (f"{ agent_name } : Skipping item: { new_item .__class__ .__name__ } " )
164185 input_items = result .to_input_list ()
0 commit comments