@pinecall/skills 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +65 -0
  2. package/build.mjs +204 -0
  3. package/package.json +29 -0
  4. package/skills/pinecall-concepts/SKILL.md +41 -0
  5. package/skills/pinecall-concepts/references/concepts/agents-and-channels.md +155 -0
  6. package/skills/pinecall-concepts/references/concepts/deployment-topologies.md +120 -0
  7. package/skills/pinecall-concepts/references/concepts/hot-reload.md +119 -0
  8. package/skills/pinecall-concepts/references/concepts/philosophy.md +100 -0
  9. package/skills/pinecall-concepts/references/concepts/server-vs-client-llm.md +119 -0
  10. package/skills/pinecall-examples/SKILL.md +59 -0
  11. package/skills/pinecall-examples/references/examples/browser-widget.md +206 -0
  12. package/skills/pinecall-examples/references/examples/chat-bot.md +184 -0
  13. package/skills/pinecall-examples/references/examples/headless-agent.md +121 -0
  14. package/skills/pinecall-examples/references/examples/index.md +183 -0
  15. package/skills/pinecall-examples/references/examples/multi-channel-bot.md +173 -0
  16. package/skills/pinecall-examples/references/examples/outbound-dispatch.md +109 -0
  17. package/skills/pinecall-examples/references/examples/turn-detection.md +150 -0
  18. package/skills/pinecall-guides/SKILL.md +68 -0
  19. package/skills/pinecall-guides/references/guides/call-ringing.md +149 -0
  20. package/skills/pinecall-guides/references/guides/conversation-history.md +377 -0
  21. package/skills/pinecall-guides/references/guides/dev-mode.md +130 -0
  22. package/skills/pinecall-guides/references/guides/events.md +677 -0
  23. package/skills/pinecall-guides/references/guides/human-takeover.md +184 -0
  24. package/skills/pinecall-guides/references/guides/inbound-voice.md +201 -0
  25. package/skills/pinecall-guides/references/guides/knowledge-bases.md +166 -0
  26. package/skills/pinecall-guides/references/guides/live-listening.md +199 -0
  27. package/skills/pinecall-guides/references/guides/multi-tenant.md +158 -0
  28. package/skills/pinecall-guides/references/guides/outbound-calls.md +279 -0
  29. package/skills/pinecall-guides/references/guides/sse-streaming.md +207 -0
  30. package/skills/pinecall-guides/references/guides/testing-agents.md +272 -0
  31. package/skills/pinecall-guides/references/guides/tools-and-functions.md +254 -0
  32. package/skills/pinecall-guides/references/guides/webrtc-browser.md +200 -0
  33. package/skills/pinecall-guides/references/guides/whatsapp.md +370 -0
  34. package/skills/pinecall-guides/references/guides/ws-streaming.md +235 -0
  35. package/skills/pinecall-quickstart/SKILL.md +54 -0
  36. package/skills/pinecall-quickstart/references/index.md +123 -0
  37. package/skills/pinecall-quickstart/references/quickstart.md +185 -0
  38. package/skills/pinecall-reference/SKILL.md +43 -0
  39. package/skills/pinecall-reference/references/reference/cli.md +578 -0
  40. package/skills/pinecall-reference/references/reference/events.md +366 -0
  41. package/skills/pinecall-reference/references/reference/llm-providers.md +263 -0
  42. package/skills/pinecall-reference/references/reference/rest-api.md +122 -0
  43. package/skills/pinecall-reference/references/reference/session-limits.md +119 -0
  44. package/skills/pinecall-reference/references/reference/stt-providers.md +174 -0
  45. package/skills/pinecall-reference/references/reference/tts-providers.md +149 -0
  46. package/skills/pinecall-sdk-api/SKILL.md +56 -0
  47. package/skills/pinecall-sdk-api/references/api/agent.md +328 -0
  48. package/skills/pinecall-sdk-api/references/api/call.md +324 -0
  49. package/skills/pinecall-sdk-api/references/api/pinecall.md +186 -0
  50. package/skills/pinecall-sdk-api/references/api/reply-stream.md +148 -0
  51. package/skills/pinecall-security/SKILL.md +37 -0
  52. package/skills/pinecall-security/references/security.md +138 -0
  53. package/skills/pinecall-web-chat/SKILL.md +38 -0
  54. package/skills/pinecall-web-chat/references/web/chat/chat-session.md +178 -0
  55. package/skills/pinecall-web-chat/references/web/chat/overview.md +98 -0
  56. package/skills/pinecall-web-components/SKILL.md +37 -0
  57. package/skills/pinecall-web-components/references/web/components/overview.md +128 -0
  58. package/skills/pinecall-web-voice/SKILL.md +40 -0
  59. package/skills/pinecall-web-voice/references/web/core/datachannel-protocol.md +149 -0
  60. package/skills/pinecall-web-voice/references/web/core/overview.md +70 -0
  61. package/skills/pinecall-web-voice/references/web/core/state-and-phases.md +153 -0
  62. package/skills/pinecall-web-voice/references/web/core/voice-session.md +279 -0
  63. package/skills/pinecall-web-widget/SKILL.md +41 -0
  64. package/skills/pinecall-web-widget/references/web/widget/overview.md +67 -0
  65. package/skills/pinecall-web-widget/references/web/widget/props.md +291 -0
  66. package/skills/pinecall-web-widget/references/web/widget/theming.md +131 -0
  67. package/skills/pinecall-web-widget/references/web/widget/tools-api.md +381 -0
  68. package/skills/pinecall-web-widget/references/web/widget/use-voice-session-hook.md +130 -0
@@ -0,0 +1,328 @@
1
+ ---
2
+ title: "Agent"
3
+ description: "Owns channels, routes call events, stores defaults, dials outbound calls."
4
+ ---
5
+
6
+ # Agent
7
+
8
+ Created via `pc.agent(id, config?)`. Owns channels, routes call events, stores defaults, dials outbound calls.
9
+
10
+ ## Creation
11
+
12
+ ```typescript
13
+ import { tool } from "@pinecall/sdk";
14
+ import { z } from "zod";
15
+
16
+ const lookupOrder = tool({
17
+ name: "lookupOrder",
18
+ description: "Look up an order by ID",
19
+ schema: z.object({ id: z.string() }),
20
+ execute: async ({ id }) => ({ status: "shipped", eta: "today" }),
21
+ });
22
+
23
+ const agent = pc.agent("my-agent", {
24
+ voice: "elevenlabs/sarah",
25
+ language: "es",
26
+ stt: "deepgram/flux",
27
+ llm: "openai/gpt-5-chat-latest",
28
+ prompt: "System prompt with {{template_vars}}.",
29
+ greeting: "Hello! How can I help you today?",
30
+ phoneNumber: "+13186330963",
31
+ tools: [lookupOrder],
32
+ });
33
+ ```
34
+
35
+ | Config field | Type | Description |
36
+ |---|---|---|
37
+ | `voice` | `string \| VoiceConfig` | TTS provider — shortcut or full config |
38
+ | `language` | `string` | BCP-47 language code |
39
+ | `stt` | `string \| STTConfig` | STT provider — shortcut or full config |
40
+ | `llm` | `LLMConfig` | LLM provider, model, prompt, enabled flag |
41
+ | `tools` | `Tool[]` | Declarative tools created with `tool()` + Zod schemas (auto-executed) |
42
+ | `phoneNumber` | `string \| PhoneNumberConfig` | Phone number to register (E.164 or SIP URI) |
43
+ | `phoneNumbers` | `Array<string \| PhoneNumberConfig>` | Multiple numbers with per-number config |
44
+ | `whatsapp` | `WhatsAppChannelConfig[]` | WhatsApp channels to register |
45
+ | `history` | `HistoryStore` | Conversation persistence (see [History](/guides/conversation-history)) |
46
+ | `sessionLimits` | `SessionLimits` | Duration / idle timeout config |
47
+ | `interruption` | `InterruptionConfig` | Energy thresholds for barge-in |
48
+ | `analysis` | `AnalysisConfig` | Audio metrics streaming |
49
+ | `allowedOrigins` | `string[]` | Public token access (see [Security](/security)) |
50
+
51
+ See [Reference → Providers](/reference/stt-providers) for full provider configs.
52
+
53
+ ## Phone numbers
54
+
55
+ ### `addPhoneNumber(number, config?)`
56
+
57
+ Register a phone number or SIP URI. Idempotent — calling again with the same number updates its config.
58
+
59
+ ```typescript
60
+ agent.addPhoneNumber("+13186330963");
61
+ agent.addPhoneNumber("sip:bot@trunk.twilio.com");
62
+
63
+ // Per-number config overrides
64
+ agent.addPhoneNumber("+34911234567", {
65
+ voice: "elevenlabs/valentina",
66
+ language: "es",
67
+ });
68
+ ```
69
+
70
+ ### `removePhone(number)`
71
+
72
+ Unregister a phone number.
73
+
74
+ ```typescript
75
+ agent.removePhone("+34911234567");
76
+ ```
77
+
78
+ ## WhatsApp
79
+
80
+ ### `addWhatsapp(config)`
81
+
82
+ Register a WhatsApp channel. Idempotent.
83
+
84
+ ```typescript
85
+ agent.addWhatsapp({
86
+ phoneNumberId: "123456789012345",
87
+ accessToken: "EAABx...",
88
+ verifyToken: "my-secret",
89
+ appSecret: "abc123...",
90
+ });
91
+ ```
92
+
93
+ See [WhatsApp guide](/guides/whatsapp) for full config.
94
+
95
+ ### `removeWhatsapp(phoneNumberId)`
96
+
97
+ Unregister a WhatsApp channel.
98
+
99
+ ```typescript
100
+ agent.removeWhatsapp("123456789012345");
101
+ ```
102
+
103
+ ## Config & hot-reload
104
+
105
+ ### `update(opts)`
106
+
107
+ Hot-reload the agent's defaults. Affects all **future** calls — existing calls keep their current config.
108
+
109
+ ```typescript
110
+ agent.update({ voice: "elevenlabs/claire", language: "fr" });
111
+ agent.update({ stt: "gladia" });
112
+ agent.update({ llm: "openai/gpt-5-chat-latest", prompt: "..." });
113
+ ```
114
+
115
+ ### `configureSession(callId, opts)`
116
+
117
+ Update config for a live call (equivalent to `call.update()`).
118
+
119
+ ```typescript
120
+ agent.configureSession("CA7ec...", { language: "es" });
121
+ ```
122
+
123
+ ### `getConfig()`
124
+
125
+ Returns the current `AgentConfig`.
126
+
127
+ ```typescript
128
+ const cfg = agent.getConfig();
129
+ ```
130
+
131
+ ## Outbound calls
132
+
133
+ ### `dial(options)`
134
+
135
+ Make an outbound call. Returns `Promise<Call>`.
136
+
137
+ ```typescript
138
+ const call = await agent.dial({
139
+ to: "+14155551234",
140
+ from: "+13186330963",
141
+ greeting: "Hi! This is a follow-up call.",
142
+ metadata: { appointmentId: "appt_001" },
143
+ config: { voice: "cartesia/yumiko", language: "ar" },
144
+ });
145
+ ```
146
+
147
+ | Field | Type | Required | Description |
148
+ |---|---|---|---|
149
+ | `to` | `string` | ✅ | Destination number (E.164) |
150
+ | `from` | `string` | — | Caller ID — auto-resolved if agent has one phone channel. Required when multiple. |
151
+ | `greeting` | `string` | — | Text the server speaks when callee picks up |
152
+ | `metadata` | `object` | — | Custom data attached to the call |
153
+ | `config` | `object` | — | Per-call config override (voice, STT, language) |
154
+
155
+ See [Outbound Calls guide](/guides/outbound-calls) for the full pattern.
156
+
157
+ ## Tokens
158
+
159
+ ### `createToken(channel)`
160
+
161
+ Mint a short-lived token for browser WebRTC or chat. Scoped to this agent.
162
+
163
+ ```typescript
164
+ const token = await agent.createToken("webrtc");
165
+ // { token, server, expiresIn }
166
+ ```
167
+
168
+ ## Dev mode
169
+
170
+ ### `routeCallers(numbers)`
171
+
172
+ Route phone and WhatsApp messages from these numbers to this agent (instead of any other agent registered on the same channel). Used for dev mode isolation.
173
+
174
+ ```typescript
175
+ agent.routeCallers(["+34600123456", "+34612345678"]);
176
+ ```
177
+
178
+ See [Dev mode guide](/guides/dev-mode).
179
+
180
+ ## Human-in-the-loop
181
+
182
+ Pause the AI so a human can take over the conversation. Works on WhatsApp and (soon) voice/chat channels.
183
+
184
+ ### `pause(target?)`
185
+
186
+ Pause the agent. While paused, incoming messages are forwarded to the SDK but the LLM doesn't respond.
187
+
188
+ ```typescript
189
+ // Pause a specific session
190
+ agent.pause("wa-abc123");
191
+
192
+ // Pause all sessions with a contact
193
+ agent.pause({ contact: "+34612345678" });
194
+
195
+ // Pause the entire agent
196
+ agent.pause();
197
+ ```
198
+
199
+ ### `resume(target?)`
200
+
201
+ Resume the AI after a pause. Global resume clears all session and contact pauses.
202
+
203
+ ```typescript
204
+ agent.resume("wa-abc123");
205
+ agent.resume({ contact: "+34612345678" });
206
+ agent.resume();
207
+ ```
208
+
209
+ ### `sendMessage(opts)`
210
+
211
+ Send a message as the human operator. The message is delivered through the channel (e.g. WhatsApp) and added to LLM history so the AI has context when resumed.
212
+
213
+ ```typescript
214
+ agent.sendMessage({
215
+ sessionId: "wa-abc123",
216
+ text: "Hi, I'm taking over this conversation.",
217
+ });
218
+ ```
219
+
220
+ | Field | Type | Required | Description |
221
+ |---|---|---|---|
222
+ | `sessionId` | `string` | ✅ | Target session ID (e.g. `wa-abc123`) |
223
+ | `text` | `string` | ✅ | Message body |
224
+
225
+ See [Human Takeover guide](/guides/human-takeover) for the full pattern.
226
+
227
+ ## Calls
228
+
229
+ ### `call(callId)`
230
+
231
+ Look up a live `Call` by ID. Returns `Call | undefined`.
232
+
233
+ ```typescript
234
+ const call = agent.call("CA7ec...");
235
+ ```
236
+
237
+ ## Observability
238
+
239
+ ### `stream(res?)`
240
+
241
+ Open an SSE stream of this agent's events. Same shape as `pc.stream()` but scoped to one agent.
242
+
243
+ ```typescript
244
+ app.get("/events", () => agent.stream());
245
+ app.get("/events", (req, res) => agent.stream(res));
246
+ ```
247
+
248
+ ## Events
249
+
250
+ Subscribe via `agent.on(event, handler)`. All call-scoped events include `call` as the last argument.
251
+
252
+ ### Lifecycle
253
+
254
+ | Event | Signature | When |
255
+ |---|---|---|
256
+ | `call.started` | `(call)` | New call connected |
257
+ | `call.ended` | `(call, reason)` | Call disconnected |
258
+
259
+ ### User speech
260
+
261
+ | Event | Signature | When |
262
+ |---|---|---|
263
+ | `speech.started` | `(event, call)` | User began speaking (VAD) |
264
+ | `speech.ended` | `(event, call)` | User stopped speaking (VAD) |
265
+ | `user.speaking` | `(event, call)` | Interim STT transcript (updates live) |
266
+ | `user.message` | `(event, call)` | Final confirmed user text |
267
+
268
+ ### Turns
269
+
270
+ | Event | Signature | When |
271
+ |---|---|---|
272
+ | `eager.turn` | `(turn, call)` | Early turn signal (low-latency response) |
273
+ | `turn.end` | `(turn, call)` | Final turn signal |
274
+ | `turn.continued` | `(event, call)` | User kept talking (auto-aborts active streams) |
275
+
276
+ ### Bot speech
277
+
278
+ | Event | Signature | When |
279
+ |---|---|---|
280
+ | `bot.speaking` | `(event, call)` | Bot started speaking a message |
281
+ | `bot.word` | `(event, call)` | Individual word as TTS plays it |
282
+ | `bot.finished` | `(event, call)` | Bot finished speaking a message |
283
+ | `bot.interrupted` | `(event, call)` | Bot was cut off by user |
284
+
285
+ ### Protocol
286
+
287
+ | Event | Signature | When |
288
+ |---|---|---|
289
+ | `message.confirmed` | `(event, call)` | Server acknowledged bot message |
290
+ | `llm.toolCall` | `(data, call)` | Server-side LLM requests a tool call |
291
+ | `session.idleWarning` | `(event, call)` | Warning — user hasn't spoken, call will timeout soon |
292
+ | `session.timeout` | `(event, call)` | Session timeout fired (max duration / idle) |
293
+
294
+ ### WhatsApp
295
+
296
+ | Event | Signature | When |
297
+ |---|---|---|
298
+ | `whatsapp.sessionStarted` | `(event)` | New WhatsApp conversation started |
299
+ | `whatsapp.message` | `(event)` | Incoming WhatsApp message received |
300
+ | `whatsapp.response` | `(event)` | Agent sent a WhatsApp response |
301
+ | `whatsapp.status` | `(event)` | Message delivery status |
302
+
303
+ See [Events reference](/reference/events) for full event data shapes.
304
+
305
+ ### Human-in-the-loop
306
+
307
+ | Event | Signature | When |
308
+ |---|---|---|
309
+ | `session.paused` | `(event)` | AI paused for a session, contact, or globally |
310
+ | `session.resumed` | `(event)` | AI resumed |
311
+
312
+ See [Human Takeover guide](/guides/human-takeover).
313
+
314
+ ## Escape hatch
315
+
316
+ ### `send(data)`
317
+
318
+ Send a raw protocol message. Use only when no higher-level method covers your case.
319
+
320
+ ```typescript
321
+ agent.send({ type: "custom.command", payload: { /* ... */ } });
322
+ ```
323
+
324
+ ## What's next
325
+
326
+ - [`Call`](/api/call) — per-session methods
327
+ - [Events reference](/reference/events) — full event data shapes
328
+ - [Hot-reload](/concepts/hot-reload) — patterns for `configure()` and `setPrompt()`
@@ -0,0 +1,324 @@
1
+ ---
2
+ title: "Call"
3
+ description: "Per-session handle. Speak, control, update, read state."
4
+ ---
5
+
6
+ # Call
7
+
8
+ A live call session. Created automatically and passed to your `call.started` handler. Use it to speak, control the call, update it mid-flight, and read its state.
9
+
10
+ ```typescript
11
+ agent.on("call.started", (call) => {
12
+ // call is a Call instance
13
+ });
14
+ ```
15
+
16
+ ## Properties
17
+
18
+ ```typescript
19
+ call.id // "CA7ec979f5..." — unique call ID
20
+ call.from // "+13186330963" or "sip:..."
21
+ call.to // destination number / URI
22
+ call.direction // "inbound" | "outbound"
23
+ call.transport // "phone" | "webrtc" | "chat" | "whatsapp" | "unknown"
24
+ call.metadata // custom metadata from the channel or dial()
25
+ call.transcript // [{ role: "user", content: "..." }, ...] — user + assistant only
26
+ call.messages // full LLM history (populated on call.ended)
27
+ call.currentBotText // live preview of what the bot is saying (accumulated bot.word events)
28
+ call.duration // seconds (populated on call.ended)
29
+ call.startedAt // epoch seconds
30
+ call.endedAt // epoch seconds
31
+ call.reason // "hangup" | "timeout" | ...
32
+ ```
33
+
34
+ ### `currentBotText`
35
+
36
+ A live preview of what the bot is currently saying. Built automatically from `bot.word` events — grows word-by-word as TTS plays, resets on each new `bot.speaking`, clears after `bot.finished` or `bot.interrupted`.
37
+
38
+ ```typescript
39
+ agent.on("bot.word", (event, call) => {
40
+ updateSubtitle(call.currentBotText); // "¡Hola!" → "¡Hola! Estoy" → "¡Hola! Estoy bien,"
41
+ });
42
+ ```
43
+
44
+ ## Speech
45
+
46
+ ### `say(text, opts?)`
47
+
48
+ Speak text immediately. Standalone — no `in_reply_to` tracking. Use for greetings and proactive announcements.
49
+
50
+ ```typescript
51
+ call.say("Hello! How can I help?");
52
+ ```
53
+
54
+ Pass `{ addToHistory: true }` to inject the text into the server-side LLM conversation history as an assistant message. This way the model knows what was said and won't repeat it.
55
+
56
+ ```typescript
57
+ agent.on("call.started", async (call) => {
58
+ const customer = await db.findByPhone(call.from);
59
+ call.say(`Hi ${customer.name}! How can I help?`, { addToHistory: true });
60
+ });
61
+ ```
62
+
63
+ > **Tip:** The `greeting` field in `pc.agent()` is syntactic sugar for `call.say(text, { addToHistory })` inside a `call.started` handler. Use `greeting` for convenience, or `call.say()` directly for full control.
64
+
65
+ ### `reply(text)`
66
+
67
+ Reply to the latest user message. Auto-tracks `in_reply_to`. Use when responding to what the user just said.
68
+
69
+ ```typescript
70
+ call.reply("Sure, let me look that up for you.");
71
+ ```
72
+
73
+ ### `replyStream(turn?)`
74
+
75
+ Open a token-by-token stream for LLM responses. TTS starts as soon as a sentence boundary is detected.
76
+
77
+ ```typescript
78
+ const stream = call.replyStream(turn);
79
+
80
+ for await (const token of llm.stream(prompt)) {
81
+ if (stream.aborted) break; // user interrupted
82
+ stream.write(token);
83
+ }
84
+ stream.end();
85
+ ```
86
+
87
+ See [`ReplyStream`](/api/reply-stream) for details.
88
+
89
+ ### `toolResult(msgId, results)`
90
+
91
+ Send tool results back to the server-side LLM. When using `tool()`, the SDK calls this automatically — you don't need to call it yourself.
92
+
93
+ ```typescript
94
+ // Auto-called by tool() — you rarely need this directly.
95
+ // Only use for advanced cases where you bypass tool() auto-execution.
96
+ call.toolResult(msgId, [
97
+ { toolCallId: "tc_abc", result: { status: "shipped" } },
98
+ ]);
99
+ ```
100
+
101
+ ### `cancel(msgId?)`
102
+
103
+ Cancel a specific bot message (by ID) or the current one (if no ID).
104
+
105
+ ```typescript
106
+ call.cancel(); // cancel current
107
+ call.cancel("msg_abc123"); // cancel specific
108
+ ```
109
+
110
+ ### `clear()`
111
+
112
+ Flush all queued TTS audio. Stops the bot mid-speech.
113
+
114
+ ```typescript
115
+ call.clear();
116
+ ```
117
+
118
+ ## Call control
119
+
120
+ ### `hangup()`
121
+
122
+ End the call.
123
+
124
+ ```typescript
125
+ call.hangup();
126
+ ```
127
+
128
+ ### `forward(to, opts?)`
129
+
130
+ Transfer the call to another number.
131
+
132
+ ```typescript
133
+ call.forward("+15558675309");
134
+ ```
135
+
136
+ ### `sendDTMF(digits)`
137
+
138
+ Send DTMF tones. Use `0-9`, `*`, `#`.
139
+
140
+ ```typescript
141
+ call.sendDTMF("1234#");
142
+ ```
143
+
144
+ ### `hold()` / `unhold()`
145
+
146
+ Put the call on hold (plays hold music, mutes mic) and resume.
147
+
148
+ ```typescript
149
+ call.hold();
150
+ // ...later
151
+ call.unhold();
152
+ ```
153
+
154
+ ### `mute()` / `unmute()`
155
+
156
+ Mute and unmute the mic. Transcripts are buffered while muted; on `unmute()`, `call.unmuted` fires with the buffered transcript.
157
+
158
+ ```typescript
159
+ call.mute();
160
+ call.unmute();
161
+ ```
162
+
163
+ ### `streamSSE(res, opts?)`
164
+
165
+ Stream call events as Server-Sent Events to an HTTP response. Used for "Call Me" flows where the browser needs a live transcript of an outbound call.
166
+
167
+ ```typescript
168
+ app.post("/api/call-me", async (req, res) => {
169
+ const call = await agent.dial({
170
+ to: req.body.phone,
171
+ greeting: "Hi! You asked me to call you.",
172
+ });
173
+ call.streamSSE(res);
174
+ });
175
+ ```
176
+
177
+ Sets SSE headers automatically. Streams: `call.started`, `bot.word`, `bot.confirmed`, `user.speaking`, `user.message`, `tool.call`, `call.ended`. Sends `:ping` keepalives every 25s. Cleans up listeners on client disconnect.
178
+
179
+ | Option | Type | Description |
180
+ |---|---|---|
181
+ | `greeting` | `string` | Override the greeting text sent as first `bot.confirmed`. Defaults to `call.greeting` (set by `dial()`). |
182
+
183
+ See [Voice Widget → Call Me](/web/widget/props#callmeendpoint--outbound-calls) for the full pattern.
184
+
185
+ ## Mid-call configuration
186
+
187
+ ### `update(opts)`
188
+
189
+ Change voice, STT, or language. Takes effect on the next LLM turn or TTS output.
190
+
191
+ ```typescript
192
+ call.update({ voice: "elevenlabs/valentina", language: "es" });
193
+ ```
194
+
195
+ ### `setPrompt(text)`
196
+
197
+ Replace the system prompt for this call only. The agent's default prompt is unchanged.
198
+
199
+ ```typescript
200
+ call.setPrompt("You are now in escalation mode. Be more formal.");
201
+ ```
202
+
203
+ ### `setPromptVars(vars)`
204
+
205
+ Set `{{variable}}` values in the prompt template.
206
+
207
+ ```typescript
208
+ await call.setPromptVars({
209
+ customer_name: "Maria",
210
+ tier: "premium",
211
+ });
212
+ ```
213
+
214
+ ### `addContext(text)`
215
+
216
+ Append context after the system prompt. Useful for injecting CRM data, tool results, or live state.
217
+
218
+ ```typescript
219
+ await call.addContext(`Recent orders:\n- ORD-001: shipped\n- ORD-002: pending`);
220
+ ```
221
+
222
+ You can call `addContext` multiple times during a call — each call appends.
223
+
224
+ ### `setPromptFile(path)`
225
+
226
+ Load a prompt from a file and set it. Equivalent to `readFile + setPrompt`.
227
+
228
+ ```typescript
229
+ await call.setPromptFile("./prompts/escalation.md");
230
+ ```
231
+
232
+ ## Conversation history
233
+
234
+ ### `getHistory()`
235
+
236
+ Fetch the current conversation messages in OpenAI format.
237
+
238
+ ```typescript
239
+ const messages = await call.getHistory();
240
+ // [{ role: "system", content: "..." }, { role: "user", content: "..." }, ...]
241
+ ```
242
+
243
+ ### `addHistory(msgs)`
244
+
245
+ Inject messages into the history. Useful for CRM context or seeding past conversation.
246
+
247
+ ```typescript
248
+ await call.addHistory([
249
+ { role: "user", content: "I called yesterday about my order" },
250
+ { role: "assistant", content: "Yes, I see it shipped this morning." },
251
+ ]);
252
+ ```
253
+
254
+ ### `setHistory(msgs)`
255
+
256
+ Replace the entire conversation history.
257
+
258
+ ```typescript
259
+ await call.setHistory([
260
+ { role: "system", content: "You are now in escalation mode." },
261
+ ]);
262
+ ```
263
+
264
+ ### `clearHistory()`
265
+
266
+ Clear all messages. The system prompt is preserved.
267
+
268
+ ```typescript
269
+ call.clearHistory();
270
+ ```
271
+
272
+ ## Common patterns
273
+
274
+ ### Greet on `call.started`
275
+
276
+ ```typescript
277
+ agent.on("call.started", (call) => {
278
+ if (call.direction === "inbound") {
279
+ call.say("Hello! How can I help?");
280
+ }
281
+ });
282
+ ```
283
+
284
+ ### Persist transcripts on `call.ended`
285
+
286
+ ```typescript
287
+ agent.on("call.ended", async (call, reason) => {
288
+ await db.calls.create({
289
+ id: call.id,
290
+ from: call.from,
291
+ to: call.to,
292
+ direction: call.direction,
293
+ transport: call.transport,
294
+ duration: call.duration,
295
+ reason,
296
+ transcript: call.transcript,
297
+ messages: call.messages,
298
+ });
299
+ });
300
+ ```
301
+
302
+ ### Transfer when escalation requested
303
+
304
+ ```typescript
305
+ import { tool } from "@pinecall/sdk";
306
+ import { z } from "zod";
307
+
308
+ const transferToHuman = tool({
309
+ name: "transferToHuman",
310
+ description: "Escalate to a human agent.",
311
+ schema: z.object({}),
312
+ execute: async (_, call) => {
313
+ call.say("Connecting you now.");
314
+ call.forward("+15558675309");
315
+ return { transferred: true };
316
+ },
317
+ });
318
+ ```
319
+
320
+ ## What's next
321
+
322
+ - [`ReplyStream`](/api/reply-stream) — for client-side LLMs
323
+ - [Events reference](/reference/events) — all events the call emits
324
+ - [Hot-reload](/concepts/hot-reload) — `update`, `setPrompt`, `addContext` patterns