@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,186 @@
1
+ ---
2
+ title: "Pinecall"
3
+ description: "The WebSocket client. Manages auth, reconnection, and agent multiplexing."
4
+ ---
5
+
6
+ # Pinecall
7
+
8
+ The WebSocket client. One per process. Manages the connection to `voice.pinecall.io`, handles auth and reconnection, and multiplexes events across multiple agents.
9
+
10
+ **Auto-connects on construction.** When you create a `Pinecall` instance with an API key, it connects immediately — no need to call `connect()`.
11
+
12
+ ## Constructor
13
+
14
+ ```typescript
15
+ new Pinecall(options)
16
+ ```
17
+
18
+ | Option | Type | Default | Description |
19
+ |---|---|---|---|
20
+ | `apiKey` | `string` | `PINECALL_API_KEY` env var | Your Pinecall API key. Auto-read from env if not provided. |
21
+ | `apiUrl` | `string` | `wss://voice.pinecall.io` | Server URL |
22
+ | `autoReconnect` | `boolean` | `true` | Auto-reconnect on disconnect |
23
+ | `promptsDir` | `string` | `"prompts"` | Prompts directory for `setPromptFile` |
24
+
25
+ ### Example
26
+
27
+ ```typescript
28
+ // Reads PINECALL_API_KEY from env automatically
29
+ const pc = new Pinecall();
30
+
31
+ // Or pass explicitly
32
+ const pc = new Pinecall({ apiKey: "pk_..." });
33
+ ```
34
+
35
+ Agents can be created immediately — they queue and register when the connection is ready:
36
+
37
+ ```typescript
38
+ const pc = new Pinecall();
39
+ const agent = pc.agent("support", { /* ... */ }); // works before connected
40
+ ```
41
+
42
+ ## Methods
43
+
44
+ ### `ready`
45
+
46
+ `Promise<void>` that resolves when the connection is established. Use it when you need to wait for the connection before proceeding (e.g. before dialing an outbound call).
47
+
48
+ ```typescript
49
+ await pc.ready;
50
+ const call = await agent.dial({ to: "+14155551234" });
51
+ ```
52
+
53
+ ### `connect()`
54
+
55
+ Manually open the WebSocket connection. **Rarely needed** — the constructor auto-connects when an API key is present. Idempotent (safe to call multiple times).
56
+
57
+ ```typescript
58
+ await pc.connect();
59
+ ```
60
+
61
+ ### `disconnect()`
62
+
63
+ Gracefully close the connection.
64
+
65
+ ```typescript
66
+ await pc.disconnect();
67
+ ```
68
+
69
+ ### `agent(id, config?)`
70
+
71
+ Create or retrieve an agent. If an agent with this ID already exists, returns it (idempotent).
72
+
73
+ ```typescript
74
+ const agent = pc.agent("support", {
75
+ voice: "elevenlabs/sarah",
76
+ language: "en",
77
+ llm: "openai/gpt-5-chat-latest",
78
+ stt: "deepgram/flux",
79
+ prompt: "You are a support agent. Be concise.",
80
+ greeting: "Hi! How can I help you today?",
81
+ phoneNumber: "+13186330963",
82
+ });
83
+ ```
84
+
85
+ **`AgentConfig` fields:**
86
+
87
+ | Field | Type | Description |
88
+ |---|---|---|
89
+ | `voice` | `string \| VoiceConfig` | TTS voice shortcut (e.g. `elevenlabs/sarah`) |
90
+ | `language` | `string` | BCP-47 language code |
91
+ | `stt` | `string \| STTConfig` | STT shortcut (e.g. `deepgram/flux`) |
92
+ | `llm` | `string \| LLMConfig` | LLM shortcut (e.g. `openai/gpt-5-chat-latest`) or full config |
93
+ | `prompt` | `string` | System prompt for the LLM |
94
+ | `greeting` | `string \| { text, addToHistory? } \| (call) => string` | Greeting spoken on inbound calls. Added to LLM history by default. |
95
+ | `tools` | `Tool[]` | Declarative tool definitions created with `tool()` |
96
+ | `phoneNumber` | `string \| PhoneNumberConfig` | Phone number or SIP URI to register (Twilio) |
97
+ | `phoneNumbers` | `Array<string \| PhoneNumberConfig>` | Multiple phone numbers with per-number config (e.g. one per language) |
98
+ | `whatsapp` | `WhatsAppChannelConfig[]` | WhatsApp channels (Meta Cloud API credentials) |
99
+ | `sessionLimits` | `object` | Session timeout config (see [Session Limits](/reference/session-limits)) |
100
+ | `allowedOrigins` | `string[]` | Allowed origins for public browser token access (see [Security](/security)) |
101
+
102
+ Dynamic greetings with a function:
103
+
104
+ ```typescript
105
+ greeting: async (call) => {
106
+ const customer = await db.findByPhone(call.from);
107
+ return `Hi ${customer.name}! How can I help?`;
108
+ },
109
+ ```
110
+
111
+ Greeting without LLM history (e.g. a standalone announcement):
112
+
113
+ ```typescript
114
+ greeting: { text: "Welcome! Please hold.", addToHistory: false },
115
+ ```
116
+
117
+ See [`Agent`](/api/agent) for full API reference.
118
+
119
+ ### `getAgent(id)`
120
+
121
+ Look up an agent by ID. Returns `Agent | undefined`.
122
+
123
+ ```typescript
124
+ const mara = pc.getAgent("mara");
125
+ ```
126
+
127
+ ### `removeAgent(id)`
128
+
129
+ Unregister an agent. Returns `boolean` indicating whether the agent existed.
130
+
131
+ ```typescript
132
+ const removed = pc.removeAgent("mara");
133
+ ```
134
+
135
+ ### `createToken(channel, agentId)`
136
+
137
+ Generate a short-lived, single-use token for browser WebRTC or chat connections. Used to mint tokens for browsers.
138
+
139
+ ```typescript
140
+ const token = await pc.createToken("webrtc", "mara");
141
+ // { token, server, expiresIn }
142
+ ```
143
+
144
+ See [Security](/security) for the full token model.
145
+
146
+ ### `stream(res?, options?)`
147
+
148
+ Open an SSE stream of agent events. Works with any framework — returns a Web API `Response` or writes to a Node.js `ServerResponse`.
149
+
150
+ ```typescript
151
+ // Web API (Remix, Next.js, Hono, Bun)
152
+ app.get("/events", () => pc.stream());
153
+
154
+ // Express / Node.js
155
+ app.get("/events", (req, res) => pc.stream(res));
156
+
157
+ // Filtered to specific agents
158
+ app.get("/events", () => pc.stream({ agents: ["mara", "support"] }));
159
+ app.get("/events", (req, res) => pc.stream(res, { agents: ["mara"] }));
160
+ ```
161
+
162
+ See [Multi-tenant guide](/guides/multi-tenant) for the filtering pattern.
163
+
164
+ ## Events
165
+
166
+ Subscribe via `pc.on(event, handler)`.
167
+
168
+ | Event | Signature | When |
169
+ |---|---|---|
170
+ | `connected` | `()` | WebSocket auth succeeded |
171
+ | `disconnected` | `(reason)` | Connection closed |
172
+ | `reconnecting` | `(attempt, delay)` | Auto-reconnect attempt N |
173
+ | `error` | `(err)` | Protocol or transport error |
174
+
175
+ ```typescript
176
+ pc.on("connected", () => console.log("Live"));
177
+ pc.on("disconnected", (reason) => console.log("Down:", reason));
178
+ pc.on("reconnecting", (n) => console.log(`Retry ${n}`));
179
+ pc.on("error", (err) => console.error(err));
180
+ ```
181
+
182
+ ## What's next
183
+
184
+ - [`Agent`](/api/agent) — channels, events, hot-reload, dial
185
+ - [`Call`](/api/call) — per-session control
186
+ - [Security](/security) — token model and best practices
@@ -0,0 +1,148 @@
1
+ ---
2
+ title: "ReplyStream"
3
+ description: "Token-by-token streaming for client-side LLM responses."
4
+ ---
5
+
6
+ # ReplyStream
7
+
8
+ A streaming interface for sending LLM tokens to the server. TTS starts as soon as a sentence boundary is detected — you don't wait for the full response.
9
+
10
+ Use it when running a client-side LLM (bring your own provider). For server-side LLMs, you don't need it — the server streams TTS automatically.
11
+
12
+ ## Creating a stream
13
+
14
+ ```typescript
15
+ const stream = call.replyStream(turn);
16
+ ```
17
+
18
+ Pass the `turn` object from `turn.end` so the stream is tied to that specific user turn. If the user keeps talking, the stream auto-aborts.
19
+
20
+ ## Writing tokens
21
+
22
+ ```typescript
23
+ for await (const chunk of llm.stream(prompt)) {
24
+ if (stream.aborted) break;
25
+ const token = chunk.choices[0]?.delta?.content;
26
+ if (token) stream.write(token);
27
+ }
28
+ stream.end();
29
+ ```
30
+
31
+ | Method | Description |
32
+ |---|---|
33
+ | `stream.write(token)` | Append a token to the stream |
34
+ | `stream.end()` | Mark the stream complete — server flushes remaining TTS |
35
+ | `stream.aborted` | `true` if the user interrupted or kept talking |
36
+
37
+ Always call `stream.end()` when done, even on error — otherwise the server keeps waiting.
38
+
39
+ ## Handling interruptions
40
+
41
+ The `aborted` flag flips to `true` when:
42
+
43
+ - The user starts speaking again (`turn.continued`)
44
+ - The user explicitly cancels (`bot.interrupted`)
45
+ - The call ends (`call.ended`)
46
+
47
+ Always check `aborted` in your token loop:
48
+
49
+ ```typescript
50
+ for await (const chunk of openai.chat.completions.create({ /* ... */ })) {
51
+ if (stream.aborted) break;
52
+ const token = chunk.choices[0]?.delta?.content;
53
+ if (token) stream.write(token);
54
+ }
55
+ stream.end();
56
+ ```
57
+
58
+ If you don't, you'll keep computing tokens (and paying for them) after the user has moved on.
59
+
60
+ ## Full client-side LLM pattern
61
+
62
+ ```typescript
63
+ import OpenAI from "openai";
64
+ const openai = new OpenAI();
65
+
66
+ agent.on("turn.end", async (turn, call) => {
67
+ const stream = call.replyStream(turn);
68
+
69
+ try {
70
+ const history = await call.getHistory();
71
+ const completion = await openai.chat.completions.create({
72
+ llm: "openai/gpt-5-chat-latest",
73
+ messages: [
74
+ { role: "system", content: "You are helpful. Be concise." },
75
+ ...history,
76
+ { role: "user", content: turn.text },
77
+ ],
78
+ stream: true,
79
+ });
80
+
81
+ for await (const chunk of completion) {
82
+ if (stream.aborted) break;
83
+ const token = chunk.choices[0]?.delta?.content;
84
+ if (token) stream.write(token);
85
+ }
86
+ } catch (err) {
87
+ console.error("LLM error:", err);
88
+ } finally {
89
+ stream.end();
90
+ }
91
+ });
92
+ ```
93
+
94
+ ## With Anthropic
95
+
96
+ ```typescript
97
+ import Anthropic from "@anthropic-ai/sdk";
98
+ const anthropic = new Anthropic();
99
+
100
+ agent.on("turn.end", async (turn, call) => {
101
+ const stream = call.replyStream(turn);
102
+
103
+ try {
104
+ const response = await anthropic.messages.stream({
105
+ model: "claude-opus-4-7",
106
+ max_tokens: 1024,
107
+ system: "You are helpful. Be concise.",
108
+ messages: [{ role: "user", content: turn.text }],
109
+ });
110
+
111
+ for await (const event of response) {
112
+ if (stream.aborted) break;
113
+ if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
114
+ stream.write(event.delta.text);
115
+ }
116
+ }
117
+ } finally {
118
+ stream.end();
119
+ }
120
+ });
121
+ ```
122
+
123
+ ## With LangChain
124
+
125
+ ```typescript
126
+ import { ChatOpenAI } from "@langchain/openai";
127
+ const model = new ChatOpenAI({ model: "gpt-5-chat-latest", streaming: true });
128
+
129
+ agent.on("turn.end", async (turn, call) => {
130
+ const stream = call.replyStream(turn);
131
+
132
+ const llmStream = await model.stream([
133
+ { role: "system", content: "You are helpful." },
134
+ { role: "user", content: turn.text },
135
+ ]);
136
+
137
+ for await (const chunk of llmStream) {
138
+ if (stream.aborted) break;
139
+ if (chunk.content) stream.write(chunk.content.toString());
140
+ }
141
+ stream.end();
142
+ });
143
+ ```
144
+
145
+ ## What's next
146
+
147
+ - [Server-side vs client-side LLM](/concepts/server-vs-client-llm) — when to use each
148
+ - [Events reference](/reference/events) — `turn.end`, `turn.continued`, `bot.interrupted`
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: pinecall-security
3
+ description: >-
4
+ Security Use when the user is building, configuring, or debugging with @pinecall/sdk. Keywords: .
5
+ license: MIT
6
+ ---
7
+
8
+ # Security
9
+
10
+ Security
11
+
12
+ This skill bundles the official Pinecall documentation for **Security**. The
13
+ table below indexes every page; open the `references/…` file for the full text
14
+ (loaded on demand). Source of truth: <https://docs.pinecall.io>.
15
+
16
+ | Page | What it covers | Open |
17
+ |------|----------------|------|
18
+ | **Security** | Token security model and best practices for production deployments. | [`references/security.md`](references/security.md) · [docs](https://docs.pinecall.io/security) |
19
+
20
+
21
+ ## House rules — always apply
22
+
23
+ - **Example defaults** (use these exact strings unless the user asks otherwise):
24
+ `stt: "deepgram/flux"`, `llm: "openai/gpt-5-chat-latest"`, `voice: "elevenlabs/sarah"`.
25
+ **NEVER use `deepgram/nova-2`** — it is not supported. Use `deepgram/nova-3`
26
+ only for languages Flux doesn't support (e.g. Arabic).
27
+ - **Turn detection & VAD are auto-derived from the STT provider — never set
28
+ `turnDetection` or `vad` manually.** Flux → native turns + native VAD;
29
+ every other STT → `smart_turn` + `silero`.
30
+ - **Greeting**: inbound → `greeting` field in `pc.agent()`; outbound → `greeting`
31
+ field in `agent.dial()`. It is sugar for `call.say()` in `call.started`.
32
+ - **Auth**: `new Pinecall()` reads `PINECALL_API_KEY` from env and auto-connects.
33
+ - Full documentation: <https://docs.pinecall.io>
34
+
35
+ ---
36
+ *Generated from `sdk/docs/` by `@pinecall/skills` — do not edit by hand; edit the
37
+ docs and re-run `node build.mjs`.*
@@ -0,0 +1,138 @@
1
+ ---
2
+ title: "Security"
3
+ description: "Token security model and best practices for production deployments."
4
+ ---
5
+
6
+ # Security
7
+
8
+ This page covers how Pinecall handles browser security: the token model, why tokens are safe to expose, and when to use the convenience `allowedOrigins` mode vs full backend auth.
9
+
10
+ ## Token security model
11
+
12
+ Browser connections (WebRTC and chat) use **short-lived tokens** generated by the voice server. The recommended model:
13
+
14
+ > **Your backend generates tokens using your API key, and distributes them to browsers through your own auth layer.**
15
+
16
+ This is the same model used by LiveKit, Twilio, Daily.co, and every major real-time platform.
17
+
18
+ ![Token security flow](/assets/diagrams/token-security-flow.png)
19
+
20
+ ### Backend (Express, Next.js, Hono, etc.)
21
+
22
+ ```typescript
23
+ import { Pinecall } from "@pinecall/sdk";
24
+
25
+ const pc = new Pinecall();
26
+
27
+ const agent = pc.agent("florencia", { /* config */ });
28
+
29
+ // Token endpoint — protected by YOUR auth
30
+ app.get("/api/token", authMiddleware, async (req, res) => {
31
+ const channel = req.query.channel as "webrtc" | "chat";
32
+ const token = await agent.createToken(channel);
33
+ res.json(token);
34
+ });
35
+ ```
36
+
37
+ If the agent is in a separate process (you only have `pc` in the web server):
38
+
39
+ ```typescript
40
+ app.get("/api/token", authMiddleware, async (req, res) => {
41
+ const token = await pc.createToken("webrtc", "florencia");
42
+ res.json(token);
43
+ });
44
+ ```
45
+
46
+ ### Frontend (VoiceWidget)
47
+
48
+ ```tsx
49
+ <VoiceWidget
50
+ agent="florencia"
51
+ tokenProvider={async () => {
52
+ const res = await fetch("/api/token?channel=webrtc", {
53
+ credentials: "include", // send your session cookie
54
+ });
55
+ return res.json();
56
+ }}
57
+ />
58
+ ```
59
+
60
+ ## Why tokens are safe
61
+
62
+ Tokens have three security properties that make them safe to pass to browsers:
63
+
64
+ | Property | Value | Effect |
65
+ |---|---|---|
66
+ | **Single-use** | Consumed on first connection | Can't be reused by an attacker |
67
+ | **Short-lived** | 60 second TTL | Expires before anyone can steal it |
68
+ | **Scoped** | Locked to agent + org | Can't be used for a different agent |
69
+
70
+ The token is **not** the security boundary — **your backend is**. The token is a short-lived capability that proves "someone authorized gave me permission to connect." The security question is: who can call your `/api/token` endpoint?
71
+
72
+ - **Requires login** → only authenticated users get tokens
73
+ - **Rate limited** → can't bulk-generate tokens
74
+ - **Permission-checked** → only authorized users connect
75
+
76
+ Think of it like a movie ticket: the theater (your backend) verifies your identity and gives you a ticket. The ticket works once, for one screen, for a limited time. Even if someone steals the ticket, they get one session — and they'd need to break TLS to intercept it.
77
+
78
+ ## `allowedOrigins` (convenience mode)
79
+
80
+ For simple deployments without a backend (demos, prototypes, CodePen), you can opt-in to public token access by configuring `allowedOrigins`:
81
+
82
+ ```typescript
83
+ const agent = pc.agent("demo-bot", {
84
+ allowedOrigins: [
85
+ "https://demo.mysite.com", // exact match
86
+ "https://*.mysite.com", // subdomain wildcard
87
+ "http://localhost:*", // any port (dev)
88
+ ],
89
+ });
90
+ ```
91
+
92
+ When `allowedOrigins` is set, the token endpoint accepts browser requests from matching origins **without** an API key. The `Origin` header is browser-enforced (real browsers can't spoof it).
93
+
94
+ ```tsx
95
+ <VoiceWidget agent="demo-bot" />
96
+ ```
97
+
98
+ > **Warning:** `allowedOrigins` protects against casual embedding but **not** against a determined attacker — Origin headers can be spoofed from scripts/curl. For production with real users, always use `tokenProvider` with your backend auth.
99
+
100
+ ## Mode comparison
101
+
102
+ | Mode | Security level | Use case |
103
+ |---|---|---|
104
+ | `tokenProvider` (backend) | ✅ Full auth control | Production apps |
105
+ | `allowedOrigins` (public) | ⚠️ Origin-based only | Demos, prototypes |
106
+ | Neither (default) | ❌ Rejected | — |
107
+
108
+ ## API key handling
109
+
110
+ Your `PINECALL_API_KEY` is the master credential. Treat it like a database password:
111
+
112
+ - **Never** ship it in browser code, mobile apps, or public repos
113
+ - **Always** load it from environment variables on the server
114
+ - **Rotate** it if you suspect exposure (via the dashboard)
115
+ - **Scope** it per-environment (separate keys for dev, staging, prod)
116
+
117
+ The SDK never exposes the API key over the wire in browser-bound responses — `createToken` returns only the short-lived token.
118
+
119
+ ## Webhook signature verification (WhatsApp)
120
+
121
+ For WhatsApp, set `appSecret` so the server verifies the HMAC signature on every incoming webhook:
122
+
123
+ ```typescript
124
+ agent.addWhatsapp({
125
+ phoneNumberId: "...",
126
+ accessToken: "...",
127
+ verifyToken: "...",
128
+ appSecret: process.env.WA_APP_SECRET, // HMAC verification
129
+ });
130
+ ```
131
+
132
+ Without `appSecret`, the webhook accepts any request — anyone who finds your endpoint URL can inject fake messages. Always set it in production.
133
+
134
+ ## What's next
135
+
136
+ - [WebRTC in the browser](/guides/webrtc-browser) — full setup
137
+ - [Multi-tenant](/guides/multi-tenant) — per-tenant token isolation
138
+ - [WhatsApp](/guides/whatsapp) — webhook verification
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: pinecall-web-chat
3
+ description: >-
4
+ @pinecall/web/chat — browser text chat (ChatSession, ChatView). Use when the user is building, configuring, or debugging with @pinecall/sdk. Keywords: chat, chatsession, text chat, @pinecall/web/chat.
5
+ license: MIT
6
+ ---
7
+
8
+ # @pinecall/web/chat (Chat)
9
+
10
+ @pinecall/web/chat — browser text chat (ChatSession, ChatView).
11
+
12
+ This skill bundles the official Pinecall documentation for **@pinecall/web/chat (Chat)**. The
13
+ table below indexes every page; open the `references/…` file for the full text
14
+ (loaded on demand). Source of truth: <https://docs.pinecall.io>.
15
+
16
+ | Page | What it covers | Open |
17
+ |------|----------------|------|
18
+ | **@pinecall/web/chat** | Text chat client for Pinecall voice agents. Framework-agnostic core + React hook. | [`references/web/chat/overview.md`](references/web/chat/overview.md) · [docs](https://docs.pinecall.io/web/chat/overview) |
19
+ | **ChatSession API** | Full reference for ChatSession (vanilla) and usePinecallChat (React). | [`references/web/chat/chat-session.md`](references/web/chat/chat-session.md) · [docs](https://docs.pinecall.io/web/chat/chat-session) |
20
+
21
+
22
+ ## House rules — always apply
23
+
24
+ - **Example defaults** (use these exact strings unless the user asks otherwise):
25
+ `stt: "deepgram/flux"`, `llm: "openai/gpt-5-chat-latest"`, `voice: "elevenlabs/sarah"`.
26
+ **NEVER use `deepgram/nova-2`** — it is not supported. Use `deepgram/nova-3`
27
+ only for languages Flux doesn't support (e.g. Arabic).
28
+ - **Turn detection & VAD are auto-derived from the STT provider — never set
29
+ `turnDetection` or `vad` manually.** Flux → native turns + native VAD;
30
+ every other STT → `smart_turn` + `silero`.
31
+ - **Greeting**: inbound → `greeting` field in `pc.agent()`; outbound → `greeting`
32
+ field in `agent.dial()`. It is sugar for `call.say()` in `call.started`.
33
+ - **Auth**: `new Pinecall()` reads `PINECALL_API_KEY` from env and auto-connects.
34
+ - Full documentation: <https://docs.pinecall.io>
35
+
36
+ ---
37
+ *Generated from `sdk/docs/` by `@pinecall/skills` — do not edit by hand; edit the
38
+ docs and re-run `node build.mjs`.*