Hands
Read tools are safe. Write tools are where things get real. A booking, a cancellation, a taxi request. These change state and you cannot undo a hallucinated confirmation.
SESSION_BOOKINGS = {}
def book_hotel(
hotel_name: str,
city: str,
check_in: str,
check_out: str,
guest_name: str,
) -> str:
"""Books a hotel room."""
booking_id = f"BK{random.randint(100000, 999999)}"
SESSION_BOOKINGS[booking_id] = {
"booking_id": booking_id,
"customer_name": guest_name,
"hotel": hotel_name,
"city": city,
"check_in": check_in,
"check_out": check_out,
"status": "confirmed",
}
return f"Hotel booking confirmed! ID: {booking_id}"Write tools mutate state. Here it is an in-memory dict for the workshop, but in production this is where you talk to a database, a payment gateway, or an external booking API.
def cancel_booking(
booking_id: str,
reason: Optional[str] = None,
) -> str:
"""Cancels a booking."""
booking_id = booking_id.upper().strip()
bookings = _get_all_bookings()
if booking_id not in bookings:
return f"Booking {booking_id} not found."
if booking_id in SESSION_BOOKINGS:
SESSION_BOOKINGS[booking_id]["status"] = "cancelled"
return f"Booking {booking_id} cancelled."
return (
f"Booking {booking_id} cancellation processed. "
f"Refund initiated."
)Notice the defensive checks. The model will confidently pass in garbage. Validate inputs, return clear errors, and never silently succeed.
Matching exercise: Match the tool to its shape
Loading practice…