osmTalk Docs
Widget

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

  1. User speaks the question
  2. LLM decides to call get_weather(city="Madurai") tool
  3. Tool card appears: 🔄 get_weather Running…
  4. API returns 1.8s later
  5. Card updates: ✅ get_weather Done 1.8s
  6. Bot speaks: "It's 32°C and sunny in Madurai."
  7. 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
    }
  ]
}
FieldDescription
waitMessageWhat the bot speaks if the tool takes > waitDelaySecs
errorMessageWhat the bot speaks if the tool fails
waitDelaySecsHow 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 name as the primary label (users see technical names, which is fine for transparency)
  • Consider renaming tools to user-friendly labels: check_order instead of check_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

ProblemLikely causeFix
Cards don't appearWidget not subscribed to RoomEvent.DataReceivedCheck browser console for errors
Card says "Running…" foreverTool handler didn't call result_callbackCheck bot logs for exceptions
Card appears but immediately disappearsTool completed before the card rendered (< 50ms)Rare, usually for cached responses — harmless
Error state doesn't showHandler silently swallows exceptionsRe-raise exceptions in handler so error frame propagates