You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(call): surface tool calls, handoffs, and status events in TTY
Previously `handleControlMessage` in `src/call.ts` handled only
`transcript`, `speech-update`, and `call-ended`, silently dropping
every other WebSocket control message via `default: break;`. Tool
invocations, squad handoffs, tool errors, and call-status transitions
were all invisible, forcing developers to switch to the Vapi dashboard
to debug KB routing, handoff decisions, or tool failures during a
`npm run call` session.
Add targeted formatters and cases for the high-signal event types
while keeping the default output clean:
- `tool-calls` → `🔧 Tool call: <name>(<args-preview>)` for regular
tools, or `🔀 Handoff → <Target Name>` when the function name
matches the `handoff_to_<Target_Name>` convention used by squad
handoff tools. Underscores in the captured target are converted
back to spaces so `handoff_to_FAQ_Specialist` renders as
`🔀 Handoff → FAQ Specialist`. Handles both the flat
`toolCallList[]` shape and the nested `toolWithToolCallList[].toolCall`
shape, and tolerates both top-level `name`/`arguments` and the older
`function.name`/`function.arguments` nesting.
- `tool-call-result` → `✅ Tool result: <name> → <preview>` for
successes and `❌ Tool failed: <name> → <preview>` for errors,
truncating long payloads to 200 characters with a
`[truncated, N chars]` suffix so KB lookups don't overwhelm the
terminal.
- `status-update` → `📞 Status: <state>[+reason]` for the useful
lifecycle transitions (`in-progress`, `forwarding`, `ended`).
`queued`, `ringing`, and `scheduled` are dropped because they never
apply to a WebSocket-transport developer call.
- `hang` → `⚠️ Hang warning` so impending silence-timeout termination
is visible while still-audible content is still on screen.
- `transfer-update` → `🔀 Transfer → <assistantName|number|sipUri>`
so phone / SIP / cross-assistant transfers register in the log.
High-frequency events (`conversation-update`, `model-output`,
`function-call`, `user-interrupted`) are still silently dropped
because they fire several times per second during a normal call and
would drown out real transcript content. Developers who want to
enumerate unknown events (for future workstream additions) can set
`VAPI_CALL_DEBUG=1` in the environment to emit a compact
`🔍 [debug] <type>: <json-preview>` line for each otherwise-ignored
message.
All formatters are defensive: every JSON preview goes through a
try/catch that falls back to `<unserializable>` on circular refs or
non-serializable values, arguments supplied as JSON strings are
re-parsed so the preview shows structured content instead of
escape-riddled single-line strings, and the `tool-calls` /
`tool-call-result` cases swallow formatter exceptions so an
unfamiliar payload shape never crashes the CLI. Each event flows
through a new `printEvent` helper that flushes any pending coalesced
final buffer and clears the partial-transcript overwrite region
before writing, keeping the TTY output coherent when tool calls
arrive mid-utterance.
No runtime behavior change for the voice agent itself — only
surfacing WebSocket events that were already being sent but dropped
in the CLI.
0 commit comments