@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.
- package/README.md +65 -0
- package/build.mjs +204 -0
- package/package.json +29 -0
- package/skills/pinecall-concepts/SKILL.md +41 -0
- package/skills/pinecall-concepts/references/concepts/agents-and-channels.md +155 -0
- package/skills/pinecall-concepts/references/concepts/deployment-topologies.md +120 -0
- package/skills/pinecall-concepts/references/concepts/hot-reload.md +119 -0
- package/skills/pinecall-concepts/references/concepts/philosophy.md +100 -0
- package/skills/pinecall-concepts/references/concepts/server-vs-client-llm.md +119 -0
- package/skills/pinecall-examples/SKILL.md +59 -0
- package/skills/pinecall-examples/references/examples/browser-widget.md +206 -0
- package/skills/pinecall-examples/references/examples/chat-bot.md +184 -0
- package/skills/pinecall-examples/references/examples/headless-agent.md +121 -0
- package/skills/pinecall-examples/references/examples/index.md +183 -0
- package/skills/pinecall-examples/references/examples/multi-channel-bot.md +173 -0
- package/skills/pinecall-examples/references/examples/outbound-dispatch.md +109 -0
- package/skills/pinecall-examples/references/examples/turn-detection.md +150 -0
- package/skills/pinecall-guides/SKILL.md +68 -0
- package/skills/pinecall-guides/references/guides/call-ringing.md +149 -0
- package/skills/pinecall-guides/references/guides/conversation-history.md +377 -0
- package/skills/pinecall-guides/references/guides/dev-mode.md +130 -0
- package/skills/pinecall-guides/references/guides/events.md +677 -0
- package/skills/pinecall-guides/references/guides/human-takeover.md +184 -0
- package/skills/pinecall-guides/references/guides/inbound-voice.md +201 -0
- package/skills/pinecall-guides/references/guides/knowledge-bases.md +166 -0
- package/skills/pinecall-guides/references/guides/live-listening.md +199 -0
- package/skills/pinecall-guides/references/guides/multi-tenant.md +158 -0
- package/skills/pinecall-guides/references/guides/outbound-calls.md +279 -0
- package/skills/pinecall-guides/references/guides/sse-streaming.md +207 -0
- package/skills/pinecall-guides/references/guides/testing-agents.md +272 -0
- package/skills/pinecall-guides/references/guides/tools-and-functions.md +254 -0
- package/skills/pinecall-guides/references/guides/webrtc-browser.md +200 -0
- package/skills/pinecall-guides/references/guides/whatsapp.md +370 -0
- package/skills/pinecall-guides/references/guides/ws-streaming.md +235 -0
- package/skills/pinecall-quickstart/SKILL.md +54 -0
- package/skills/pinecall-quickstart/references/index.md +123 -0
- package/skills/pinecall-quickstart/references/quickstart.md +185 -0
- package/skills/pinecall-reference/SKILL.md +43 -0
- package/skills/pinecall-reference/references/reference/cli.md +578 -0
- package/skills/pinecall-reference/references/reference/events.md +366 -0
- package/skills/pinecall-reference/references/reference/llm-providers.md +263 -0
- package/skills/pinecall-reference/references/reference/rest-api.md +122 -0
- package/skills/pinecall-reference/references/reference/session-limits.md +119 -0
- package/skills/pinecall-reference/references/reference/stt-providers.md +174 -0
- package/skills/pinecall-reference/references/reference/tts-providers.md +149 -0
- package/skills/pinecall-sdk-api/SKILL.md +56 -0
- package/skills/pinecall-sdk-api/references/api/agent.md +328 -0
- package/skills/pinecall-sdk-api/references/api/call.md +324 -0
- package/skills/pinecall-sdk-api/references/api/pinecall.md +186 -0
- package/skills/pinecall-sdk-api/references/api/reply-stream.md +148 -0
- package/skills/pinecall-security/SKILL.md +37 -0
- package/skills/pinecall-security/references/security.md +138 -0
- package/skills/pinecall-web-chat/SKILL.md +38 -0
- package/skills/pinecall-web-chat/references/web/chat/chat-session.md +178 -0
- package/skills/pinecall-web-chat/references/web/chat/overview.md +98 -0
- package/skills/pinecall-web-components/SKILL.md +37 -0
- package/skills/pinecall-web-components/references/web/components/overview.md +128 -0
- package/skills/pinecall-web-voice/SKILL.md +40 -0
- package/skills/pinecall-web-voice/references/web/core/datachannel-protocol.md +149 -0
- package/skills/pinecall-web-voice/references/web/core/overview.md +70 -0
- package/skills/pinecall-web-voice/references/web/core/state-and-phases.md +153 -0
- package/skills/pinecall-web-voice/references/web/core/voice-session.md +279 -0
- package/skills/pinecall-web-widget/SKILL.md +41 -0
- package/skills/pinecall-web-widget/references/web/widget/overview.md +67 -0
- package/skills/pinecall-web-widget/references/web/widget/props.md +291 -0
- package/skills/pinecall-web-widget/references/web/widget/theming.md +131 -0
- package/skills/pinecall-web-widget/references/web/widget/tools-api.md +381 -0
- 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
|