agent.on("call.started", (call) => {
// call is a Call instance
});Properties#
call.id // "CA7ec979f5..." — unique call ID
call.from // "+13186330963" or "sip:..."
call.to // destination number / URI
call.direction // "inbound" | "outbound"
call.transport // "phone" | "webrtc" | "chat" | "whatsapp" | "unknown"
call.metadata // custom metadata from the channel or dial()
call.transcript // [{ role: "user", content: "..." }, ...] — user + assistant only
call.messages // full LLM history (populated on call.ended)
call.duration // seconds (populated on call.ended)
call.startedAt // epoch seconds
call.endedAt // epoch seconds
call.reason // "hangup" | "timeout" | ...Speech#
say(text)#
Speak text immediately. Standalone — no in_reply_to tracking. Use for greetings and proactive announcements.
call.say("Hello! How can I help?");reply(text)#
Reply to the latest user message. Auto-tracks in_reply_to. Use when responding to what the user just said.
call.reply("Sure, let me look that up for you.");replyStream(turn?)#
Open a token-by-token stream for LLM responses. TTS starts as soon as a sentence boundary is detected.
const stream = call.replyStream(turn);
for await (const token of llm.stream(prompt)) {
if (stream.aborted) break; // user interrupted
stream.write(token);
}
stream.end();See ReplyStream for details.
toolResult(msgId, results)#
Respond to a server-side LLM tool call. Always called from within an llm.tool_call handler.
agent.on("llm.tool_call", async (data, call) => {
const results = [];
for (const tc of data.toolCalls) {
const args = JSON.parse(tc.arguments);
const result = await myToolHandler(tc.name, args);
results.push({ toolCallId: tc.id, result });
}
call.toolResult(data.msgId, results);
});cancel(msgId?)#
Cancel a specific bot message (by ID) or the current one (if no ID).
call.cancel(); // cancel current
call.cancel("msg_abc123"); // cancel specificclear()#
Flush all queued TTS audio. Stops the bot mid-speech.
call.clear();Call control#
hangup()#
End the call.
call.hangup();forward(to, opts?)#
Transfer the call to another number.
call.forward("+15558675309");sendDTMF(digits)#
Send DTMF tones. Use 0-9, *, #.
call.sendDTMF("1234#");hold() / unhold()#
Put the call on hold (plays hold music, mutes mic) and resume.
call.hold();
// ...later
call.unhold();mute() / unmute()#
Mute and unmute the mic. Transcripts are buffered while muted; on unmute(), call.unmuted fires with the buffered transcript.
call.mute();
call.unmute();Mid-call configuration#
configure(opts)#
Change voice, STT, or language. Takes effect on the next LLM turn or TTS output.
call.configure({ voice: "elevenlabs:spanishVoiceId", language: "es" });setPrompt(text)#
Replace the system prompt for this call only. The agent's default prompt is unchanged.
call.setPrompt("You are now in escalation mode. Be more formal.");setPromptVars(vars)#
Set {{variable}} values in the prompt template.
await call.setPromptVars({
customer_name: "Maria",
tier: "premium",
});addContext(text)#
Append context after the system prompt. Useful for injecting CRM data, tool results, or live state.
await call.addContext(`Recent orders:\n- ORD-001: shipped\n- ORD-002: pending`);You can call addContext multiple times during a call — each call appends.
setPromptFile(path)#
Load a prompt from a file and set it. Equivalent to readFile + setPrompt.
await call.setPromptFile("./prompts/escalation.md");Conversation history#
getHistory()#
Fetch the current conversation messages in OpenAI format.
const messages = await call.getHistory();
// [{ role: "system", content: "..." }, { role: "user", content: "..." }, ...]addHistory(msgs)#
Inject messages into the history. Useful for CRM context or seeding past conversation.
await call.addHistory([
{ role: "user", content: "I called yesterday about my order" },
{ role: "assistant", content: "Yes, I see it shipped this morning." },
]);setHistory(msgs)#
Replace the entire conversation history.
await call.setHistory([
{ role: "system", content: "You are now in escalation mode." },
]);clearHistory()#
Clear all messages. The system prompt is preserved.
call.clearHistory();Common patterns#
Greet on call.started#
agent.on("call.started", (call) => {
if (call.direction === "inbound") {
call.say("Hello! How can I help?");
}
});Persist transcripts on call.ended#
agent.on("call.ended", async (call, reason) => {
await db.calls.create({
id: call.id,
from: call.from,
to: call.to,
direction: call.direction,
transport: call.transport,
duration: call.duration,
reason,
transcript: call.transcript,
messages: call.messages,
});
});Transfer when escalation requested#
agent.on("llm.tool_call", async (data, call) => {
for (const tc of data.toolCalls) {
if (tc.name === "transferToHuman") {
call.say("Connecting you now.");
call.forward("+15558675309");
}
}
});What's next#
ReplyStream— for client-side LLMs- Events reference — all events the call emits
- Hot-reload —
configure,setPrompt,addContextpatterns
