@pinecall/web 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.
@@ -0,0 +1,434 @@
1
+ import * as React$1 from 'react';
2
+ import React__default, { ReactNode } from 'react';
3
+ import { c as ToolUI, S as SessionStatus, V as VoiceSessionOptions, C as CallPhase, d as TranscriptMessage } from './types-CKfTJcH8.js';
4
+ export { T as ToolCallEvent, b as ToolResultEvent, a as VoiceSessionState } from './types-CKfTJcH8.js';
5
+
6
+ /**
7
+ * Theme overrides for the Voice Widget.
8
+ *
9
+ * Colors that need alpha variants (accent, ring, speaking, etc.)
10
+ * should be passed as **RGB triplets** so the widget can combine
11
+ * them with `rgba()`. Example: `"124, 58, 237"`.
12
+ *
13
+ * Single-value colors (labelBg, panelBg, etc.) accept any valid
14
+ * CSS color string.
15
+ */
16
+ interface VoiceWidgetTheme {
17
+ /** Gradient highlight (center). Default: `"255, 255, 255"` */
18
+ orbFrom?: string;
19
+ /** Gradient midtone (35%). Default: `"240, 238, 231"` */
20
+ orbMid?: string;
21
+ /** Gradient outer edge (70–100%). Default: `"184, 181, 168"` */
22
+ orbTo?: string;
23
+ /** Connecting state — amber. Default: `"245, 158, 11"` */
24
+ colorConnecting?: string;
25
+ /** Active/connected state — green. Default: `"76, 175, 80"` */
26
+ colorActive?: string;
27
+ /** User speaking state — emerald. Default: `"52, 211, 153"` */
28
+ colorUserSpeaking?: string;
29
+ /** Agent speaking state — rose. Default: `"248, 113, 113"` */
30
+ colorSpeaking?: string;
31
+ /** Thinking/processing state — violet. Default: `"139, 92, 246"` */
32
+ colorThinking?: string;
33
+ /** Idle warning state — amber/orange. Default: `"255, 160, 0"` */
34
+ colorWarning?: string;
35
+ /** User bubble accent — violet. Default: `"124, 58, 237"` */
36
+ colorAccent?: string;
37
+ /** Idle ring border — warm. Default: `"216, 65, 44"` */
38
+ ringColor?: string;
39
+ /** Transcript panel background. Default: `"rgba(16, 14, 20, .92)"` */
40
+ panelBg?: string;
41
+ /** Transcript panel border. Default: `"rgba(255, 255, 255, .08)"` */
42
+ panelBorder?: string;
43
+ /** Bot bubble background. Default: `"rgba(18, 16, 22, .9)"` */
44
+ bubbleBotBg?: string;
45
+ /** Bot bubble text color. Default: `"#e8e4f0"` */
46
+ bubbleBotColor?: string;
47
+ /** User bubble text color. Default: `"#e0d4f7"` */
48
+ bubbleUserColor?: string;
49
+ /** Label tooltip background. Default: `"#181818"` */
50
+ labelBg?: string;
51
+ /** Label tooltip text color. Default: `"#fff"` */
52
+ labelColor?: string;
53
+ }
54
+ /**
55
+ * Built-in theme presets.
56
+ *
57
+ * - `"dark"` — Pearl orb on dark bg (default, refined)
58
+ * - `"midnight"` — Deep sapphire orb, ice-blue accents
59
+ * - `"aurora"` — Emerald/teal orb, northern lights feel
60
+ * - `"sunset"` — Warm coral/amber tones
61
+ * - `"light"` — Clean light theme for light-bg sites
62
+ */
63
+ type VoiceWidgetPreset = "dark" | "midnight" | "aurora" | "sunset" | "light";
64
+ /**
65
+ * A language preset defining voice/STT/language config for a specific locale.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * const spanish: LanguagePreset = {
70
+ * label: "Español",
71
+ * flag: "🇪🇸",
72
+ * voice: "elevenlabs:abc",
73
+ * stt: { provider: "deepgram-flux" },
74
+ * language: "es",
75
+ * };
76
+ * ```
77
+ */
78
+ interface LanguagePreset {
79
+ /** Display label (e.g. "Español", "English") */
80
+ label?: string;
81
+ /** Flag emoji (e.g. "🇪🇸", "🇺🇸") */
82
+ flag?: string;
83
+ /** Voice ID override (e.g. "elevenlabs:abc123") */
84
+ voice?: string;
85
+ /**
86
+ * STT override — string shortcut or full config object.
87
+ * @example "deepgram-flux"
88
+ * @example { provider: "deepgram-flux" }
89
+ */
90
+ stt?: string | Record<string, unknown>;
91
+ /** Language code for STT (e.g. "es", "en") */
92
+ language?: string;
93
+ }
94
+ /**
95
+ * Context passed to tool render functions.
96
+ * Provides methods for interacting with the conversation from tool UI.
97
+ */
98
+ interface ToolRenderContext {
99
+ /**
100
+ * Inject text into the conversation as if the user spoke it.
101
+ * Use this for click-based interactions (e.g., selecting a calendar slot).
102
+ * The agent processes the text exactly as if the user said it out loud.
103
+ */
104
+ respond: (text: string) => void;
105
+ /** Dismiss the tool UI from the transcript. */
106
+ dismiss: () => void;
107
+ }
108
+ /**
109
+ * Render function for a tool result.
110
+ *
111
+ * Called when a server-side tool with a matching name completes.
112
+ * Return a React element to render inline in the transcript.
113
+ *
114
+ * @param result - The parsed tool result from the server (any JSON value).
115
+ * @param context - Interaction helpers (`respond`, `dismiss`).
116
+ * @param toolCall - The full ToolUI entry with name, arguments, and metadata.
117
+ */
118
+ type ToolRenderer = (result: any, context: ToolRenderContext, toolCall: ToolUI) => React.ReactNode;
119
+ interface VoiceWidgetProps {
120
+ /** Agent ID to connect to */
121
+ agent: string;
122
+ /**
123
+ * Pinecall API base URL for token exchange.
124
+ * Default: `"https://voice.pinecall.io"`.
125
+ * Only override for self-hosted deployments.
126
+ */
127
+ server?: string;
128
+ /** Display name shown in status label. Default: "Agent" */
129
+ name?: string;
130
+ /** Idle label shown on hover. Default: "Talk to {name}" */
131
+ label?: string;
132
+ /**
133
+ * Initial session config overrides (language, voice, stt).
134
+ * Merged with the selected language preset if `languages` is provided.
135
+ */
136
+ config?: Record<string, unknown>;
137
+ /** Call metadata sent to the server. */
138
+ metadata?: Record<string, unknown>;
139
+ /**
140
+ * Language presets for multi-language support.
141
+ * Keys are language codes (e.g. "es", "en"), values are preset configs.
142
+ * When provided with ≥2 entries, a language selector appears in the widget panel.
143
+ *
144
+ * @example
145
+ * ```tsx
146
+ * <VoiceWidget
147
+ * languages={{
148
+ * en: { label: "English", flag: "🇺🇸", voice: "alloy", language: "en" },
149
+ * es: { label: "Español", flag: "🇪🇸", voice: "coral", language: "es" },
150
+ * }}
151
+ * defaultLanguage="en"
152
+ * />
153
+ * ```
154
+ */
155
+ languages?: Record<string, LanguagePreset>;
156
+ /** Default language key (must match a key in `languages`). Uses the first key if omitted. */
157
+ defaultLanguage?: string;
158
+ /** Called when the user selects a different language. */
159
+ onLanguageChange?: (lang: string, preset: LanguagePreset) => void;
160
+ /** Extra class name on the root wrapper */
161
+ className?: string;
162
+ /**
163
+ * Theme preset name. Sets all colors at once.
164
+ * Individual `theme` overrides take precedence over the preset.
165
+ * Default: "dark"
166
+ */
167
+ preset?: VoiceWidgetPreset;
168
+ /** Custom theme overrides — all fields optional, merged on top of preset */
169
+ theme?: Partial<VoiceWidgetTheme>;
170
+ /** Called when session status changes */
171
+ onStatusChange?: (status: SessionStatus) => void;
172
+ /**
173
+ * Map of tool names → render functions for interactive tool UI.
174
+ *
175
+ * When a server-side tool with a matching name completes, the render
176
+ * function is called and the result is shown inline in the transcript.
177
+ * The user can interact via voice (normal speech) or via the rendered
178
+ * UI (e.g., clicking a calendar slot calls `respond(text)`).
179
+ *
180
+ * @example
181
+ * ```tsx
182
+ * <VoiceWidget
183
+ * agent="mara"
184
+ * tools={{
185
+ * getAvailableSlots: (result, { respond }) => (
186
+ * <div>
187
+ * {result.slots.map((slot: string) => (
188
+ * <button key={slot} onClick={() => respond(`I'd like ${slot}`)}>
189
+ * {slot}
190
+ * </button>
191
+ * ))}
192
+ * </div>
193
+ * ),
194
+ * }}
195
+ * />
196
+ * ```
197
+ */
198
+ tools?: Record<string, ToolRenderer>;
199
+ /**
200
+ * Tool names to track (alternative to `tools` for external rendering via `useVoice()`).
201
+ * When provided, these tools are tracked in session state but NOT rendered in the transcript.
202
+ * Use `useVoice().toolCalls` to render them anywhere in your component tree.
203
+ *
204
+ * @example
205
+ * ```tsx
206
+ * <VoiceWidget agent="mara" trackedTools={["getSlots", "confirmBooking"]}>
207
+ * <MyCustomToolUI />
208
+ * </VoiceWidget>
209
+ * ```
210
+ */
211
+ trackedTools?: string[];
212
+ /**
213
+ * Custom token provider — call your backend to generate tokens instead
214
+ * of hitting /webrtc/token directly. Keeps API keys server-side.
215
+ *
216
+ * @example
217
+ * ```tsx
218
+ * <VoiceWidget
219
+ * agent="mara"
220
+ * tokenProvider={async () => {
221
+ * const res = await fetch("/api/token?channel=webrtc");
222
+ * return res.json();
223
+ * }}
224
+ * />
225
+ * ```
226
+ */
227
+ tokenProvider?: () => Promise<{
228
+ token: string;
229
+ server: string;
230
+ expires_in?: number;
231
+ }>;
232
+ }
233
+ /**
234
+ * All localizable strings used by the widget.
235
+ * Keys use dot-notation namespacing.
236
+ */
237
+ interface LocaleStrings {
238
+ "hub.title": string;
239
+ "hub.subtitle": string;
240
+ "hub.voice": string;
241
+ "hub.voiceDesc": string;
242
+ "hub.chat": string;
243
+ "hub.chatDesc": string;
244
+ "hub.whatsapp": string;
245
+ "hub.whatsappDesc": string;
246
+ "hub.callMe": string;
247
+ "hub.callMeDesc": string;
248
+ "callMe.title": string;
249
+ "callMe.placeholder": string;
250
+ "callMe.submit": string;
251
+ "callMe.formNote": string;
252
+ "callMe.calling": string;
253
+ "callMe.ended": string;
254
+ "callMe.error": string;
255
+ "callMe.back": string;
256
+ }
257
+ interface AgentChannel {
258
+ type: "webrtc" | "phone" | "whatsapp" | "chat" | "mic";
259
+ numbers?: string[];
260
+ phone?: string;
261
+ }
262
+ interface AgentInfo {
263
+ agent: string;
264
+ channels: AgentChannel[];
265
+ }
266
+ interface ChatQuickOption {
267
+ /** Button label displayed to the user. */
268
+ label: string;
269
+ /** Message text sent when clicked. */
270
+ query: string;
271
+ }
272
+ interface ChatConfig {
273
+ /** Initial greeting shown when the chat opens. Supports markdown. */
274
+ greeting?: string;
275
+ /** Quick-reply buttons shown before the user sends a message. */
276
+ quickOptions?: ChatQuickOption[];
277
+ /**
278
+ * Custom token provider for chat. If not set, falls back to the
279
+ * widget-level tokenProvider (which should handle channel=chat).
280
+ */
281
+ tokenProvider?: () => Promise<{
282
+ token: string;
283
+ server: string;
284
+ }>;
285
+ }
286
+
287
+ /**
288
+ * Hook to access the VoiceWidget session from any child component.
289
+ *
290
+ * Must be used inside a `<VoiceWidget>` tree. Returns the full session
291
+ * state (toolCalls, messages, status, etc.) plus action methods
292
+ * (sendText, dismissTool, connect, disconnect, etc.).
293
+ *
294
+ * @example
295
+ * ```tsx
296
+ * function SlotPicker() {
297
+ * const { toolCalls, sendText, dismissTool } = useVoice();
298
+ * const slots = toolCalls.find(tc => tc.name === "getSlots" && tc.result);
299
+ * if (!slots) return null;
300
+ * return slots.result.map(s => (
301
+ * <button onClick={() => { sendText(`Book ${s}`); dismissTool(slots.toolCallId); }}>{s}</button>
302
+ * ));
303
+ * }
304
+ * ```
305
+ */
306
+ declare function useVoice(): {
307
+ connect: () => Promise<void>;
308
+ disconnect: () => void;
309
+ toggleMute: () => void;
310
+ setMuted: (muted: boolean) => void;
311
+ configure: (config: Record<string, unknown>) => void;
312
+ updateOptions: (patch: Partial<Pick<VoiceSessionOptions, "config" | "metadata">>) => void;
313
+ sendText: (text: string) => void;
314
+ dismissTool: (toolCallId: string) => void;
315
+ setContext: (key: string, value: string | null) => void;
316
+ status: SessionStatus;
317
+ error: string | null;
318
+ isMuted: boolean;
319
+ phase: CallPhase;
320
+ userSpeaking: boolean;
321
+ agentSpeaking: boolean;
322
+ duration: number;
323
+ messages: TranscriptMessage[];
324
+ toolCalls: ToolUI[];
325
+ idleWarning: number | null;
326
+ };
327
+ declare function VoiceWidget({ agent, server, name, label, config: userConfig, metadata, className, preset, theme, onStatusChange, tools, trackedTools: trackedToolsProp, languages, defaultLanguage, onLanguageChange, tokenProvider, children, }: VoiceWidgetProps & {
328
+ children?: ReactNode;
329
+ }): React$1.JSX.Element;
330
+
331
+ /**
332
+ * React hook wrapping VoiceSession. Re-exports the entire state plus
333
+ * bound action methods. The underlying session is created once and
334
+ * destroyed on unmount.
335
+ */
336
+ declare function useVoiceSession(opts: VoiceSessionOptions): {
337
+ connect: () => Promise<void>;
338
+ disconnect: () => void;
339
+ toggleMute: () => void;
340
+ setMuted: (muted: boolean) => void;
341
+ configure: (config: Record<string, unknown>) => void;
342
+ updateOptions: (patch: Partial<Pick<VoiceSessionOptions, "config" | "metadata">>) => void;
343
+ sendText: (text: string) => void;
344
+ dismissTool: (toolCallId: string) => void;
345
+ setContext: (key: string, value: string | null) => void;
346
+ status: SessionStatus;
347
+ error: string | null;
348
+ isMuted: boolean;
349
+ phase: CallPhase;
350
+ userSpeaking: boolean;
351
+ agentSpeaking: boolean;
352
+ duration: number;
353
+ messages: TranscriptMessage[];
354
+ toolCalls: ToolUI[];
355
+ idleWarning: number | null;
356
+ };
357
+
358
+ interface CallMeState {
359
+ status: "dialing" | "connected" | "ended" | "error";
360
+ messages: TranscriptMessage[];
361
+ duration: number;
362
+ phone: string;
363
+ error?: string;
364
+ }
365
+ interface ContactHubProps {
366
+ open: boolean;
367
+ onClose: () => void;
368
+ channels: AgentChannel[];
369
+ name: string;
370
+ locale: string;
371
+ labels?: Partial<LocaleStrings>;
372
+ avatar?: string;
373
+ callMeEndpoint?: string;
374
+ agent: string;
375
+ server?: string;
376
+ chat?: ChatConfig;
377
+ tokenProvider?: () => Promise<{
378
+ token: string;
379
+ server: string;
380
+ expires_in?: number;
381
+ }>;
382
+ /** Called when Call Me state changes */
383
+ onCallMeState?: (state: CallMeState | null) => void;
384
+ /** Connect to WebRTC voice session. Passed explicitly instead of using useVoice(). */
385
+ connect: () => Promise<void>;
386
+ }
387
+ declare function ContactHub({ open, onClose, channels, name, locale, labels, avatar, callMeEndpoint, agent, server, chat, tokenProvider, onCallMeState, connect, }: ContactHubProps): React__default.JSX.Element | null;
388
+
389
+ /**
390
+ * ChatView — LLM text chat inside the ContactHub popover.
391
+ *
392
+ * Uses @pinecall/web/chat for WebSocket chat + marked for markdown.
393
+ * StreamingText uses rAF-based character reveal (ported from blossom Chat.jsx).
394
+ */
395
+
396
+ interface ChatViewProps {
397
+ agent: string;
398
+ server?: string;
399
+ name: string;
400
+ locale: string;
401
+ labels?: Partial<LocaleStrings>;
402
+ chat: ChatConfig;
403
+ tokenProvider?: () => Promise<{
404
+ token: string;
405
+ server: string;
406
+ expires_in?: number;
407
+ }>;
408
+ onBack: () => void;
409
+ onVoiceCall: () => void;
410
+ }
411
+ declare function ChatView({ agent, server, name, locale, labels, chat, tokenProvider, onBack, onVoiceCall, }: ChatViewProps): React__default.JSX.Element;
412
+
413
+ /**
414
+ * Fetch agent channel info from the server for auto-discovery.
415
+ * Caches results per agent+server combo to avoid re-fetching.
416
+ */
417
+ declare function useAgentInfo(agentId: string, server?: string): {
418
+ info: AgentInfo | null;
419
+ loading: boolean;
420
+ };
421
+
422
+ /**
423
+ * Get a locale string with variable interpolation.
424
+ *
425
+ * @param locale - Locale code ("en", "es", "de", "pt")
426
+ * @param key - Dot-notated string key
427
+ * @param overrides - User-provided label overrides
428
+ * @param vars - Variables to interpolate (e.g. { name: "Florencia" })
429
+ */
430
+ declare function t(locale: string, key: keyof LocaleStrings, overrides?: Partial<LocaleStrings>, vars?: Record<string, string>): string;
431
+
432
+ declare const PRESETS: Record<VoiceWidgetPreset, Required<VoiceWidgetTheme>>;
433
+
434
+ export { type AgentChannel, type AgentInfo, type CallMeState, CallPhase, type ChatConfig, type ChatQuickOption, ChatView, ContactHub, type LanguagePreset, type LocaleStrings, PRESETS, SessionStatus, type ToolRenderContext, type ToolRenderer, ToolUI, TranscriptMessage, VoiceSessionOptions, VoiceWidget, type VoiceWidgetPreset, type VoiceWidgetProps, type VoiceWidgetTheme, t, useAgentInfo, useVoice, useVoiceSession };