Tool Status Cards
Live cards that show callers what your agent is doing when it runs a tool.
When your agent calls an HTTP tool (check weather, book appointment, lookup order status, etc.) there's usually a 1-5 second silent gap while the API call runs. Without feedback, callers think the app froze.
osmTalk's voice widget shows live tool status cards during these gaps so the caller can see what's happening in real-time.
No configuration needed — cards appear automatically during voice calls whenever an HTTP tool runs.
What the User Sees
State 1 — Tool is running
┌──────────────────────────────────────┐
│ 🔄 get_weather Running… │
└──────────────────────────────────────┘The card appears the moment the LLM calls the tool. A spinner animates next to the tool name.
State 2 — Tool completed successfully
┌──────────────────────────────────────┐
│ ✅ get_weather Done 2.3s │
└──────────────────────────────────────┘Green checkmark + duration. Auto-dismisses after 3 seconds.
State 3 — Tool failed
┌──────────────────────────────────────┐
│ ❌ get_weather Failed │
└──────────────────────────────────────┘Red X stays visible until call ends or next tool succeeds.
Example 1: Weather Agent
Scenario
User on the web widget asks "What's the weather in Madurai?"
What happens
- User speaks the question
- LLM decides to call
get_weather(city="Madurai")tool - Tool card appears:
🔄 get_weather Running… - API returns 1.8s later
- Card updates:
✅ get_weather Done 1.8s - Bot speaks: "It's 32°C and sunny in Madurai."
- 3 seconds later, the card fades out
Example 2: Booking Flow with Multiple Tools
Scenario
"Book me a dentist appointment for tomorrow afternoon."
What happens
Turn 1: LLM calls check_availability(date="2026-04-22", time_range="afternoon")
┌──────────────────────────────────────┐
│ 🔄 check_availability Running… │
└──────────────────────────────────────┘
(card stays ~2s)
┌──────────────────────────────────────┐
│ ✅ check_availability Done 2.1s │
└──────────────────────────────────────┘
Bot: "I have 2:30 and 4:00 PM available. Which works for you?"
User: "2:30 please"
Turn 2: LLM calls create_appointment(date="2026-04-22", time="14:30")
┌──────────────────────────────────────┐
│ 🔄 create_appointment Running… │
└──────────────────────────────────────┘
Bot: "You're booked for 2:30 PM tomorrow. See you then!"Example 3: Parallel Tool Calls
The osmTalk voice runtime runs independent tool calls in parallel. If the LLM calls 3 tools at once, you see 3 cards simultaneously:
┌──────────────────────────────────────┐
│ 🔄 get_weather Running… │
├──────────────────────────────────────┤
│ 🔄 get_traffic Running… │
├──────────────────────────────────────┤
│ 🔄 get_news Running… │
└──────────────────────────────────────┘Each card updates independently as its API call returns. The bot waits for all 3 to finish before responding.
Customizing the Per-Tool Wait Message
The status card shows generic "Running…" text by default. You can customize per-tool via waitMessage in the tool config:
{
"httpTools": [
{
"name": "check_order_status",
"url": "https://api.shop.com/orders/{order_id}",
"method": "GET",
"parameters": [
{"name": "order_id", "type": "string", "required": true}
],
"waitMessage": "Looking up your order — one moment please…",
"errorMessage": "Sorry, I couldn't find that order. Could you double-check the number?",
"waitDelaySecs": 3
}
]
}| Field | Description |
|---|---|
waitMessage | What the bot speaks if the tool takes > waitDelaySecs |
errorMessage | What the bot speaks if the tool fails |
waitDelaySecs | How long to wait before speaking the wait message (default 3s) |
The card always appears instantly. The spoken wait message only plays if the tool is slow.
Design Decisions for Good UX
Card text
- Use the tool's
nameas the primary label (users see technical names, which is fine for transparency) - Consider renaming tools to user-friendly labels:
check_orderinstead ofcheck_order_status_v2_beta
Wait message
- Good: "Looking up your order" (informs + promises progress)
- Good: "One moment while I check the inventory"
- Bad: "Processing" (vague)
- Bad: "Please wait" (feels robotic)
Error message
- Always offer a next step — don't leave the user stuck
- Good: "Sorry, that order number isn't in our system. Can you check the 8-digit ID from your confirmation email?"
- Bad: "Error" or "Something went wrong"
Technical Flow
┌─────────────┐ ┌─────────────┐
│ Widget │ │ Bot │
└──────┬──────┘ └──────┬──────┘
│ LLM emits function_call │
│◄──────────────────────────────────────┤
│ tool-status: {tool:"X", status:"started"}
│ │
│ (Widget shows 🔄 card) │
│ │
│ [HTTP tool runs 1-5s] │
│ │
│ tool-status: {tool:"X", status:"completed"}
│◄──────────────────────────────────────┤
│ │
│ (Widget shows ✅ 2.3s, auto-dismiss)│
│ │
│ LLM speaks the result │
│◄──────────────────────────────────────┤Messages are sent over osmTalk's real-time data channel as JSON. The widget auto-handles display and dismissal.
Troubleshooting
| Problem | Likely cause | Fix |
|---|---|---|
| Cards don't appear | Widget not subscribed to RoomEvent.DataReceived | Check browser console for errors |
| Card says "Running…" forever | Tool handler didn't call result_callback | Check bot logs for exceptions |
| Card appears but immediately disappears | Tool completed before the card rendered (< 50ms) | Rare, usually for cached responses — harmless |
| Error state doesn't show | Handler silently swallows exceptions | Re-raise exceptions in handler so error frame propagates |