@chanl/widget-sdk 0.2.0-canary.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 +257 -0
- package/dist/auth.d.ts +26 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +36 -0
- package/dist/auth.js.map +1 -0
- package/dist/chat/chat-client.d.ts +81 -0
- package/dist/chat/chat-client.d.ts.map +1 -0
- package/dist/chat/chat-client.js +192 -0
- package/dist/chat/chat-client.js.map +1 -0
- package/dist/chat/stream-parser.d.ts +20 -0
- package/dist/chat/stream-parser.d.ts.map +1 -0
- package/dist/chat/stream-parser.js +134 -0
- package/dist/chat/stream-parser.js.map +1 -0
- package/dist/chat/widget-config.d.ts +7 -0
- package/dist/chat/widget-config.d.ts.map +1 -0
- package/dist/chat/widget-config.js +26 -0
- package/dist/chat/widget-config.js.map +1 -0
- package/dist/client.d.ts +66 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +49 -0
- package/dist/client.js.map +1 -0
- package/dist/defaults.d.ts +12 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +27 -0
- package/dist/defaults.js.map +1 -0
- package/dist/embed/loader-types.d.ts +119 -0
- package/dist/embed/loader-types.d.ts.map +1 -0
- package/dist/embed/loader-types.js +20 -0
- package/dist/embed/loader-types.js.map +1 -0
- package/dist/embed/loader.d.ts +101 -0
- package/dist/embed/loader.d.ts.map +1 -0
- package/dist/embed/loader.js +439 -0
- package/dist/embed/loader.js.map +1 -0
- package/dist/embed/v1.global.js +5 -0
- package/dist/embed/v1.global.js.map +1 -0
- package/dist/events.d.ts +10 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +25 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +14 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +3 -0
- package/dist/logger.js.map +1 -0
- package/dist/next/index.d.ts +58 -0
- package/dist/next/index.d.ts.map +1 -0
- package/dist/next/index.js +83 -0
- package/dist/next/index.js.map +1 -0
- package/dist/react/index.d.ts +16 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +20 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/types.d.ts +27 -0
- package/dist/react/types.d.ts.map +1 -0
- package/dist/react/types.js +8 -0
- package/dist/react/types.js.map +1 -0
- package/dist/react/use-chanl.d.ts +27 -0
- package/dist/react/use-chanl.d.ts.map +1 -0
- package/dist/react/use-chanl.js +57 -0
- package/dist/react/use-chanl.js.map +1 -0
- package/dist/react/use-chat.d.ts +32 -0
- package/dist/react/use-chat.d.ts.map +1 -0
- package/dist/react/use-chat.js +224 -0
- package/dist/react/use-chat.js.map +1 -0
- package/dist/react/use-voice.d.ts +37 -0
- package/dist/react/use-voice.d.ts.map +1 -0
- package/dist/react/use-voice.js +268 -0
- package/dist/react/use-voice.js.map +1 -0
- package/dist/react/widget.d.ts +43 -0
- package/dist/react/widget.d.ts.map +1 -0
- package/dist/react/widget.js +188 -0
- package/dist/react/widget.js.map +1 -0
- package/dist/storage/session-storage.d.ts +48 -0
- package/dist/storage/session-storage.d.ts.map +1 -0
- package/dist/storage/session-storage.js +84 -0
- package/dist/storage/session-storage.js.map +1 -0
- package/dist/types.d.ts +140 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/voice/audio-recorder.d.ts +43 -0
- package/dist/voice/audio-recorder.d.ts.map +1 -0
- package/dist/voice/audio-recorder.js +127 -0
- package/dist/voice/audio-recorder.js.map +1 -0
- package/dist/voice/index.d.ts +13 -0
- package/dist/voice/index.d.ts.map +1 -0
- package/dist/voice/index.js +16 -0
- package/dist/voice/index.js.map +1 -0
- package/dist/voice/mock-mode.d.ts +93 -0
- package/dist/voice/mock-mode.d.ts.map +1 -0
- package/dist/voice/mock-mode.js +375 -0
- package/dist/voice/mock-mode.js.map +1 -0
- package/dist/voice/transports/index.d.ts +5 -0
- package/dist/voice/transports/index.d.ts.map +1 -0
- package/dist/voice/transports/index.js +10 -0
- package/dist/voice/transports/index.js.map +1 -0
- package/dist/voice/transports/transport.d.ts +70 -0
- package/dist/voice/transports/transport.d.ts.map +1 -0
- package/dist/voice/transports/transport.js +12 -0
- package/dist/voice/transports/transport.js.map +1 -0
- package/dist/voice/transports/vapi.d.ts +147 -0
- package/dist/voice/transports/vapi.d.ts.map +1 -0
- package/dist/voice/transports/vapi.js +337 -0
- package/dist/voice/transports/vapi.js.map +1 -0
- package/dist/voice/transports/webrtc.d.ts +58 -0
- package/dist/voice/transports/webrtc.d.ts.map +1 -0
- package/dist/voice/transports/webrtc.js +318 -0
- package/dist/voice/transports/webrtc.js.map +1 -0
- package/dist/voice/transports/websocket.d.ts +39 -0
- package/dist/voice/transports/websocket.d.ts.map +1 -0
- package/dist/voice/transports/websocket.js +280 -0
- package/dist/voice/transports/websocket.js.map +1 -0
- package/dist/voice/types.d.ts +323 -0
- package/dist/voice/types.d.ts.map +1 -0
- package/dist/voice/types.js +41 -0
- package/dist/voice/types.js.map +1 -0
- package/dist/voice/utils.d.ts +22 -0
- package/dist/voice/utils.d.ts.map +1 -0
- package/dist/voice/utils.js +44 -0
- package/dist/voice/utils.js.map +1 -0
- package/dist/voice/voice-client.d.ts +231 -0
- package/dist/voice/voice-client.d.ts.map +1 -0
- package/dist/voice/voice-client.js +1187 -0
- package/dist/voice/voice-client.js.map +1 -0
- package/package.json +91 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.useChat = useChat;
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const chat_client_1 = require("../chat/chat-client");
|
|
7
|
+
const widget_config_1 = require("../chat/widget-config");
|
|
8
|
+
const defaults_1 = require("../defaults");
|
|
9
|
+
// ── Helpers ──
|
|
10
|
+
let counter = 0;
|
|
11
|
+
function id() { return `sdk-${++counter}-${Date.now()}`; }
|
|
12
|
+
function toolLabel(toolName, state) {
|
|
13
|
+
// Friendly labels — in production these come from agent config
|
|
14
|
+
const labels = {
|
|
15
|
+
search_listings: { call: 'Searching listings...', result: '✓ Found results' },
|
|
16
|
+
lookup_order: { call: 'Looking up order...', result: '✓ Order found' },
|
|
17
|
+
get_available_slots: { call: 'Checking availability...', result: '✓ Slots found' },
|
|
18
|
+
check_order_status: { call: 'Checking order status...', result: '✓ Status retrieved' },
|
|
19
|
+
calendar_booking: { call: 'Booking appointment...', result: '✓ Booked' },
|
|
20
|
+
send_email: { call: 'Sending email...', result: '✓ Email sent' },
|
|
21
|
+
knowledge_search: { call: 'Searching knowledge base...', result: '✓ Found answers' },
|
|
22
|
+
};
|
|
23
|
+
const entry = labels[toolName] ?? { call: 'Working on it...', result: '✓ Done' };
|
|
24
|
+
return state === 'call' ? entry.call : entry.result;
|
|
25
|
+
}
|
|
26
|
+
// ── Hook ──
|
|
27
|
+
function useChat({ agentId, apiKey, baseUrl, greeting, user, userHash, variables, metadata, }) {
|
|
28
|
+
const resolvedBaseUrl = (0, defaults_1.resolveBaseUrl)(baseUrl);
|
|
29
|
+
const clientRef = (0, react_1.useRef)((0, chat_client_1.createChatClient)({ apiKey, baseUrl: resolvedBaseUrl }));
|
|
30
|
+
const sessionRef = (0, react_1.useRef)(null);
|
|
31
|
+
const isStreamingRef = (0, react_1.useRef)(false);
|
|
32
|
+
// Hold latest identity in refs so `send` always reads fresh values without
|
|
33
|
+
// the `send` callback's identity changing on every identity prop change
|
|
34
|
+
// (would trigger parent re-renders that pass `send` via props).
|
|
35
|
+
const identityRef = (0, react_1.useRef)({ user, userHash, variables, metadata });
|
|
36
|
+
identityRef.current = { user, userHash, variables, metadata };
|
|
37
|
+
const [messages, setMessages] = (0, react_1.useState)([]);
|
|
38
|
+
const [isTyping, setIsTyping] = (0, react_1.useState)(false);
|
|
39
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
40
|
+
const [sessionReady, setSessionReady] = (0, react_1.useState)(false);
|
|
41
|
+
const [agentConfig, setAgentConfig] = (0, react_1.useState)(null);
|
|
42
|
+
// Fetch widget config on mount → get agent name, avatar, greeting
|
|
43
|
+
(0, react_1.useEffect)(() => {
|
|
44
|
+
let cancelled = false;
|
|
45
|
+
(0, widget_config_1.getWidgetConfig)(agentId, apiKey, resolvedBaseUrl).then((config) => {
|
|
46
|
+
if (cancelled || !config)
|
|
47
|
+
return;
|
|
48
|
+
const agent = {
|
|
49
|
+
id: agentId,
|
|
50
|
+
name: config.agent?.name ?? 'AI Assistant',
|
|
51
|
+
initials: (config.agent?.name ?? 'AI').split(' ').map((w) => w[0]).join('').slice(0, 2),
|
|
52
|
+
avatarUrl: config.style?.agentAvatar,
|
|
53
|
+
greeting: greeting ?? config.banner?.description ?? `Hi! I'm ${config.agent?.name ?? 'here to help'}. How can I assist you?`,
|
|
54
|
+
suggestions: [],
|
|
55
|
+
primaryColor: config.style?.primaryColor,
|
|
56
|
+
};
|
|
57
|
+
setAgentConfig(agent);
|
|
58
|
+
// Set greeting message
|
|
59
|
+
setMessages([{ id: id(), role: 'assistant', content: agent.greeting, timestamp: Date.now() }]);
|
|
60
|
+
});
|
|
61
|
+
return () => { cancelled = true; };
|
|
62
|
+
}, [agentId, apiKey, baseUrl, greeting]);
|
|
63
|
+
// Create session lazily (on first send). Reads latest identity from the
|
|
64
|
+
// ref so re-identify (externalId change) takes effect on the next send
|
|
65
|
+
// without recreating the `send` callback.
|
|
66
|
+
const ensureSession = (0, react_1.useCallback)(async () => {
|
|
67
|
+
if (sessionRef.current)
|
|
68
|
+
return sessionRef.current;
|
|
69
|
+
const { user, userHash, variables, metadata } = identityRef.current;
|
|
70
|
+
const session = await clientRef.current.createSession(agentId, {
|
|
71
|
+
user,
|
|
72
|
+
userHash,
|
|
73
|
+
variables,
|
|
74
|
+
metadata,
|
|
75
|
+
});
|
|
76
|
+
sessionRef.current = session;
|
|
77
|
+
setSessionReady(true);
|
|
78
|
+
return session;
|
|
79
|
+
}, [agentId]);
|
|
80
|
+
// Re-identify: when externalId changes, end the current session so the
|
|
81
|
+
// next send creates a fresh one with the new identity. Deps are primitive
|
|
82
|
+
// (`externalId` string) per react-best-practices `rerender-dependencies` —
|
|
83
|
+
// using the `user` object directly would trigger reset on every parent
|
|
84
|
+
// re-render even when externalId is stable.
|
|
85
|
+
const externalId = user?.externalId;
|
|
86
|
+
(0, react_1.useEffect)(() => {
|
|
87
|
+
if (sessionRef.current) {
|
|
88
|
+
const stale = sessionRef.current;
|
|
89
|
+
sessionRef.current = null;
|
|
90
|
+
setSessionReady(false);
|
|
91
|
+
// Best-effort cleanup; don't block the re-identify.
|
|
92
|
+
clientRef.current.endSession(stale.sessionId).catch(() => { });
|
|
93
|
+
}
|
|
94
|
+
// Intentionally NOT depending on `user` object — only externalId primitive.
|
|
95
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
96
|
+
}, [externalId]);
|
|
97
|
+
// Send message with streaming
|
|
98
|
+
const send = (0, react_1.useCallback)(async (text) => {
|
|
99
|
+
if (isStreamingRef.current)
|
|
100
|
+
return;
|
|
101
|
+
setError(null);
|
|
102
|
+
// Add user message
|
|
103
|
+
setMessages((p) => [...p, { id: id(), role: 'user', content: text, timestamp: Date.now() }]);
|
|
104
|
+
setIsTyping(true);
|
|
105
|
+
try {
|
|
106
|
+
const session = await ensureSession();
|
|
107
|
+
// Lazy placeholder: don't create the assistant bubble until the first
|
|
108
|
+
// chunk arrives. While we wait, the typing-dots indicator carries the
|
|
109
|
+
// "agent is thinking" affordance alone — otherwise we'd render BOTH the
|
|
110
|
+
// typing dots AND an empty assistant bubble for the gap between
|
|
111
|
+
// stream-connected and first-chunk, which looks like two replies.
|
|
112
|
+
let placeholderId = null;
|
|
113
|
+
const startTime = Date.now();
|
|
114
|
+
isStreamingRef.current = true;
|
|
115
|
+
// Track status pill IDs for cleanup
|
|
116
|
+
const statusIds = [];
|
|
117
|
+
const response = await clientRef.current.streamMessage(session.sessionId, text,
|
|
118
|
+
// onChunk — text delta
|
|
119
|
+
(chunk) => {
|
|
120
|
+
// Stream parser can emit empty deltas (e.g. control packets sent
|
|
121
|
+
// before any actual tokens). Don't create the bubble until we have
|
|
122
|
+
// real content — otherwise we get the ghost-bubble bug back: an
|
|
123
|
+
// empty assistant bubble alongside the still-spinning typing dots.
|
|
124
|
+
if (!placeholderId) {
|
|
125
|
+
if (!chunk)
|
|
126
|
+
return;
|
|
127
|
+
const newId = id();
|
|
128
|
+
placeholderId = newId;
|
|
129
|
+
setIsTyping(false); // Bubble takes over for the typing dots
|
|
130
|
+
setMessages((p) => [
|
|
131
|
+
...p,
|
|
132
|
+
{ id: newId, role: 'assistant', content: chunk, timestamp: Date.now() },
|
|
133
|
+
]);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
setMessages((p) => p.map((m) => m.id === placeholderId ? { ...m, content: m.content + chunk } : m));
|
|
137
|
+
},
|
|
138
|
+
// onPart — tool invocations
|
|
139
|
+
(part) => {
|
|
140
|
+
if (part.type !== 'tool-invocation' || !part.toolInvocation)
|
|
141
|
+
return;
|
|
142
|
+
const inv = part.toolInvocation;
|
|
143
|
+
const label = toolLabel(inv.toolName, inv.state);
|
|
144
|
+
if (inv.state === 'call') {
|
|
145
|
+
const sid = id();
|
|
146
|
+
statusIds.push(sid);
|
|
147
|
+
setMessages((p) => {
|
|
148
|
+
// Insert status pill before placeholder
|
|
149
|
+
const idx = p.findIndex((m) => m.id === placeholderId);
|
|
150
|
+
const pill = { id: sid, role: 'status', content: label, label, timestamp: Date.now() };
|
|
151
|
+
if (idx >= 0) {
|
|
152
|
+
const next = [...p];
|
|
153
|
+
next.splice(idx, 0, pill);
|
|
154
|
+
return next;
|
|
155
|
+
}
|
|
156
|
+
return [...p, pill];
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
else if (inv.state === 'result') {
|
|
160
|
+
// Update the most recent status pill
|
|
161
|
+
const lastSid = statusIds[statusIds.length - 1];
|
|
162
|
+
if (lastSid) {
|
|
163
|
+
setMessages((p) => p.map((m) => m.id === lastSid ? { ...m, content: label, label } : m));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
isStreamingRef.current = false;
|
|
168
|
+
// Remove status pills, add thought badge + final response
|
|
169
|
+
const elapsed = (Date.now() - startTime) / 1000;
|
|
170
|
+
const toolCount = statusIds.length;
|
|
171
|
+
// If no chunks ever streamed (non-streaming fallback or empty stream),
|
|
172
|
+
// create the bubble now from response.message so the user sees it.
|
|
173
|
+
if (!placeholderId && response.message) {
|
|
174
|
+
const newId = id();
|
|
175
|
+
placeholderId = newId;
|
|
176
|
+
setIsTyping(false);
|
|
177
|
+
}
|
|
178
|
+
const finalPlaceholderId = placeholderId;
|
|
179
|
+
setMessages((p) => {
|
|
180
|
+
let next = p.filter((m) => !statusIds.includes(m.id));
|
|
181
|
+
if (finalPlaceholderId) {
|
|
182
|
+
const exists = next.some((m) => m.id === finalPlaceholderId);
|
|
183
|
+
if (exists) {
|
|
184
|
+
next = next.map((m) => m.id === finalPlaceholderId ? { ...m, content: response.message } : m);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
next = [
|
|
188
|
+
...next,
|
|
189
|
+
{ id: finalPlaceholderId, role: 'assistant', content: response.message, timestamp: Date.now() },
|
|
190
|
+
];
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (toolCount > 0 && finalPlaceholderId) {
|
|
194
|
+
const badgeIdx = next.findIndex((m) => m.id === finalPlaceholderId);
|
|
195
|
+
if (badgeIdx >= 0) {
|
|
196
|
+
next.splice(badgeIdx, 0, {
|
|
197
|
+
id: id(),
|
|
198
|
+
role: 'tool',
|
|
199
|
+
content: `Thought for ${elapsed.toFixed(1)}s · Used ${toolCount} tool${toolCount > 1 ? 's' : ''}`,
|
|
200
|
+
timestamp: Date.now(),
|
|
201
|
+
duration: elapsed,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return next;
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
isStreamingRef.current = false;
|
|
210
|
+
setError(err instanceof Error ? err.message : 'Something went wrong');
|
|
211
|
+
setIsTyping(false);
|
|
212
|
+
}
|
|
213
|
+
}, [ensureSession]);
|
|
214
|
+
// Cleanup on unmount
|
|
215
|
+
(0, react_1.useEffect)(() => {
|
|
216
|
+
return () => {
|
|
217
|
+
if (sessionRef.current) {
|
|
218
|
+
clientRef.current.endSession(sessionRef.current.sessionId);
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
}, []);
|
|
222
|
+
return { messages, isTyping, error, send, sessionReady, agentConfig };
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=use-chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-chat.js","sourceRoot":"","sources":["../../src/react/use-chat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { VoiceClient } from '../voice/voice-client';
|
|
2
|
+
export interface VoiceMessage {
|
|
3
|
+
id: string;
|
|
4
|
+
sender: 'agent' | 'user';
|
|
5
|
+
content: string;
|
|
6
|
+
timestamp: Date;
|
|
7
|
+
}
|
|
8
|
+
export type VoiceMode = 'idle' | 'voice';
|
|
9
|
+
export type VoiceStatus = 'idle' | 'connecting' | 'active' | 'reconnecting' | 'closed' | 'error';
|
|
10
|
+
export interface UseVoiceOptions {
|
|
11
|
+
/** Public or server API key. `pub_xxx` for browser, `ak_xxx` for server. */
|
|
12
|
+
apiKey: string;
|
|
13
|
+
/** Optional backend override (defaults to production; auto-resolves to localhost in dev). */
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
/** Log internal events to the console. */
|
|
16
|
+
debug?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface UseVoiceReturn {
|
|
19
|
+
mode: VoiceMode;
|
|
20
|
+
start: (agentId: string) => void;
|
|
21
|
+
stop: () => void;
|
|
22
|
+
toggleMute: () => void;
|
|
23
|
+
sendMessage: (text: string) => void;
|
|
24
|
+
startVoice: (agentId: string) => void;
|
|
25
|
+
stopVoice: () => void;
|
|
26
|
+
status: VoiceStatus;
|
|
27
|
+
messages: VoiceMessage[];
|
|
28
|
+
isMuted: boolean;
|
|
29
|
+
isAgentSpeaking: boolean;
|
|
30
|
+
duration: number;
|
|
31
|
+
lastError?: Error;
|
|
32
|
+
voiceState: VoiceStatus;
|
|
33
|
+
error?: Error;
|
|
34
|
+
voice: VoiceClient | null;
|
|
35
|
+
}
|
|
36
|
+
export declare function useVoice(opts: UseVoiceOptions): UseVoiceReturn;
|
|
37
|
+
//# sourceMappingURL=use-voice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-voice.d.ts","sourceRoot":"","sources":["../../src/react/use-voice.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAMzD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAKD,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AACzC,MAAM,MAAM,WAAW,GACnB,MAAM,GACN,YAAY,GACZ,QAAQ,GACR,cAAc,GACd,QAAQ,GACR,OAAO,CAAC;AAKZ,MAAM,WAAW,eAAe;IAC9B,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAE7B,IAAI,EAAE,SAAS,CAAC;IAGhB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAGpC,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,MAAM,IAAI,CAAC;IAGtB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,KAAK,CAAC;IAGlB,UAAU,EAAE,WAAW,CAAC;IACxB,KAAK,CAAC,EAAE,KAAK,CAAC;IAGd,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;CAC3B;AAKD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,cAAc,CAqQ9D"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.useVoice = useVoice;
|
|
5
|
+
/**
|
|
6
|
+
* useVoice — React hook for voice calls against a Chanl agent.
|
|
7
|
+
*
|
|
8
|
+
* Port of `packages/audial-widget/src/hooks/use-audial.tsx` from chanl-platform.
|
|
9
|
+
* Strictly copied — chat paths stripped (use-chat.ts handles text), imports swapped
|
|
10
|
+
* to use `createChanlClient().voice` (lazy VoiceClient) instead of `new Audial(...)`.
|
|
11
|
+
*
|
|
12
|
+
* The hook owns the full voice lifecycle:
|
|
13
|
+
* start(agentId) — instantiate VoiceClient, wire events, connect
|
|
14
|
+
* stop() — close transport, clear timers
|
|
15
|
+
* toggleMute() — toggle mic mute state
|
|
16
|
+
* sendMessage(t) — send a text frame over the live voice call
|
|
17
|
+
*
|
|
18
|
+
* State exposed (both audial-legacy names AND spec-contract names):
|
|
19
|
+
* status / voiceState — 'idle' | 'connecting' | 'active' | 'closed' | 'error'
|
|
20
|
+
* messages — TranscriptMessage-derived UI list
|
|
21
|
+
* isMuted — mic mute state (tracked from 'mic-muted'/'mic-unmuted')
|
|
22
|
+
* isAgentSpeaking — from 'speech-start'/'speech-end'
|
|
23
|
+
* duration — seconds since 'ready'
|
|
24
|
+
* lastError / error — last error (Error | undefined)
|
|
25
|
+
*/
|
|
26
|
+
const react_1 = require("react");
|
|
27
|
+
const client_1 = require("../client");
|
|
28
|
+
/* ────────────────────────────────────────────────────────────────────────── */
|
|
29
|
+
/* 4. Hook implementation */
|
|
30
|
+
/* ────────────────────────────────────────────────────────────────────────── */
|
|
31
|
+
function useVoice(opts) {
|
|
32
|
+
const { apiKey, debug = false, baseUrl } = opts;
|
|
33
|
+
/* refs & state */
|
|
34
|
+
const voiceRef = (0, react_1.useRef)(null);
|
|
35
|
+
const [mode, setMode] = (0, react_1.useState)('idle');
|
|
36
|
+
const [status, setStatus] = (0, react_1.useState)('idle');
|
|
37
|
+
const [isMuted, setIsMuted] = (0, react_1.useState)(false);
|
|
38
|
+
const [messages, setMessages] = (0, react_1.useState)([]);
|
|
39
|
+
const [lastError, setLastError] = (0, react_1.useState)();
|
|
40
|
+
const [isAgentSpeaking, setIsAgentSpeaking] = (0, react_1.useState)(false);
|
|
41
|
+
// Duration state and timer ref
|
|
42
|
+
const [duration, setDuration] = (0, react_1.useState)(0);
|
|
43
|
+
const timerRef = (0, react_1.useRef)(null);
|
|
44
|
+
// Track current agentId
|
|
45
|
+
const currentAgentIdRef = (0, react_1.useRef)(null);
|
|
46
|
+
/* helper to add transcript in required shape.
|
|
47
|
+
*
|
|
48
|
+
* Pipecat + Deepgram emit INTERIM transcripts as the user speaks, then a
|
|
49
|
+
* FINAL when they stop. Interims are a growing prefix of the final:
|
|
50
|
+
* "Can you"
|
|
51
|
+
* "Can you tell me what"
|
|
52
|
+
* "Can you tell me what day is it?" ← final
|
|
53
|
+
*
|
|
54
|
+
* The wire-level TranscriptMessage has no `is_final` flag, so we dedupe
|
|
55
|
+
* by pattern: if the NEW transcript from the same sender has the LAST
|
|
56
|
+
* transcript as a prefix (or vice versa), REPLACE the last bubble in
|
|
57
|
+
* place with the longer string. This keeps one bubble per utterance.
|
|
58
|
+
*/
|
|
59
|
+
const pushTranscript = (0, react_1.useCallback)((transcript) => {
|
|
60
|
+
if (!transcript?.text)
|
|
61
|
+
return;
|
|
62
|
+
const sender = transcript.sender === 'assistant' ? 'agent' : 'user';
|
|
63
|
+
const content = transcript.text;
|
|
64
|
+
setMessages((prev) => {
|
|
65
|
+
const last = prev[prev.length - 1];
|
|
66
|
+
if (last && last.sender === sender) {
|
|
67
|
+
// Exact duplicate — skip.
|
|
68
|
+
if (last.content === content)
|
|
69
|
+
return prev;
|
|
70
|
+
// Prefix extension (or rare shrink) — replace in place with the longer.
|
|
71
|
+
if (content.startsWith(last.content) || last.content.startsWith(content)) {
|
|
72
|
+
const longer = content.length >= last.content.length ? content : last.content;
|
|
73
|
+
const replaced = { ...last, content: longer };
|
|
74
|
+
return [...prev.slice(0, -1), replaced];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return [
|
|
78
|
+
...prev,
|
|
79
|
+
{
|
|
80
|
+
id: (transcript.timestamp || Date.now()).toString(),
|
|
81
|
+
sender,
|
|
82
|
+
content,
|
|
83
|
+
timestamp: new Date(transcript.timestamp || Date.now()),
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
});
|
|
87
|
+
}, []);
|
|
88
|
+
/* helper to add an immediate user message (before transcript echoes back) */
|
|
89
|
+
const addMessage = (0, react_1.useCallback)((sender, content) => {
|
|
90
|
+
setMessages((prev) => [
|
|
91
|
+
...prev,
|
|
92
|
+
{
|
|
93
|
+
id: Date.now().toString(),
|
|
94
|
+
sender,
|
|
95
|
+
content,
|
|
96
|
+
timestamp: new Date(),
|
|
97
|
+
},
|
|
98
|
+
]);
|
|
99
|
+
}, []);
|
|
100
|
+
/* attach SDK event listeners */
|
|
101
|
+
const bindVoiceEvents = (0, react_1.useCallback)(() => {
|
|
102
|
+
const v = voiceRef.current;
|
|
103
|
+
if (!v)
|
|
104
|
+
return undefined;
|
|
105
|
+
const onReady = () => {
|
|
106
|
+
if (debug)
|
|
107
|
+
console.debug('[useVoice] onReady');
|
|
108
|
+
setStatus('active');
|
|
109
|
+
setDuration(0);
|
|
110
|
+
if (timerRef.current)
|
|
111
|
+
clearInterval(timerRef.current);
|
|
112
|
+
timerRef.current = setInterval(() => {
|
|
113
|
+
setDuration((prev) => prev + 1);
|
|
114
|
+
}, 1000);
|
|
115
|
+
};
|
|
116
|
+
const onClose = (code, reason) => {
|
|
117
|
+
if (debug)
|
|
118
|
+
console.debug('[useVoice] onClose', { code, reason });
|
|
119
|
+
setStatus('closed');
|
|
120
|
+
setMode('idle');
|
|
121
|
+
if (timerRef.current) {
|
|
122
|
+
clearInterval(timerRef.current);
|
|
123
|
+
timerRef.current = null;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const onError = (e) => {
|
|
127
|
+
console.error('[useVoice] onError', e);
|
|
128
|
+
setLastError(e);
|
|
129
|
+
setStatus('error');
|
|
130
|
+
if (timerRef.current) {
|
|
131
|
+
clearInterval(timerRef.current);
|
|
132
|
+
timerRef.current = null;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const onTranscript = (transcript) => {
|
|
136
|
+
if (debug)
|
|
137
|
+
console.debug('[useVoice] onTranscript', transcript);
|
|
138
|
+
pushTranscript(transcript);
|
|
139
|
+
};
|
|
140
|
+
const onMicMuted = () => {
|
|
141
|
+
if (debug)
|
|
142
|
+
console.debug('[useVoice] onMicMuted');
|
|
143
|
+
setIsMuted(true);
|
|
144
|
+
};
|
|
145
|
+
const onMicUnmuted = () => {
|
|
146
|
+
if (debug)
|
|
147
|
+
console.debug('[useVoice] onMicUnmuted');
|
|
148
|
+
setIsMuted(false);
|
|
149
|
+
};
|
|
150
|
+
const onSpeechStart = () => {
|
|
151
|
+
if (debug)
|
|
152
|
+
console.debug('[useVoice] onSpeechStart');
|
|
153
|
+
setIsAgentSpeaking(true);
|
|
154
|
+
};
|
|
155
|
+
const onSpeechEnd = () => {
|
|
156
|
+
if (debug)
|
|
157
|
+
console.debug('[useVoice] onSpeechEnd');
|
|
158
|
+
setIsAgentSpeaking(false);
|
|
159
|
+
};
|
|
160
|
+
v.on('ready', onReady);
|
|
161
|
+
v.on('closed', onClose);
|
|
162
|
+
v.on('error', onError);
|
|
163
|
+
v.on('transcript', onTranscript);
|
|
164
|
+
v.on('mic-muted', onMicMuted);
|
|
165
|
+
v.on('mic-unmuted', onMicUnmuted);
|
|
166
|
+
v.on('speech-start', onSpeechStart);
|
|
167
|
+
v.on('speech-end', onSpeechEnd);
|
|
168
|
+
return () => {
|
|
169
|
+
v.off('ready', onReady);
|
|
170
|
+
v.off('closed', onClose);
|
|
171
|
+
v.off('error', onError);
|
|
172
|
+
v.off('transcript', onTranscript);
|
|
173
|
+
v.off('mic-muted', onMicMuted);
|
|
174
|
+
v.off('mic-unmuted', onMicUnmuted);
|
|
175
|
+
v.off('speech-start', onSpeechStart);
|
|
176
|
+
v.off('speech-end', onSpeechEnd);
|
|
177
|
+
};
|
|
178
|
+
}, [pushTranscript, debug]);
|
|
179
|
+
/* voice controls */
|
|
180
|
+
const start = (0, react_1.useCallback)((agentId) => {
|
|
181
|
+
if (debug)
|
|
182
|
+
console.debug(`[useVoice] start with agentId: ${agentId}`);
|
|
183
|
+
if (typeof window === 'undefined') {
|
|
184
|
+
console.warn('[useVoice] window is undefined, cannot start');
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
// Lazy voice client via createChanlClient — browser-only require happens here.
|
|
188
|
+
const client = (0, client_1.createChanlClient)({ agentId, apiKey, baseUrl });
|
|
189
|
+
voiceRef.current = client.voice;
|
|
190
|
+
bindVoiceEvents();
|
|
191
|
+
setMessages([]);
|
|
192
|
+
setLastError(undefined);
|
|
193
|
+
setStatus('connecting');
|
|
194
|
+
setMode('voice');
|
|
195
|
+
setDuration(0);
|
|
196
|
+
currentAgentIdRef.current = agentId;
|
|
197
|
+
// Start the voice connection
|
|
198
|
+
voiceRef.current.start(agentId);
|
|
199
|
+
}, [apiKey, baseUrl, debug, bindVoiceEvents]);
|
|
200
|
+
const stop = (0, react_1.useCallback)(() => {
|
|
201
|
+
if (debug)
|
|
202
|
+
console.debug('[useVoice] stop');
|
|
203
|
+
voiceRef.current?.stop();
|
|
204
|
+
if (timerRef.current) {
|
|
205
|
+
clearInterval(timerRef.current);
|
|
206
|
+
timerRef.current = null;
|
|
207
|
+
}
|
|
208
|
+
setMode('idle');
|
|
209
|
+
setStatus('closed');
|
|
210
|
+
}, [debug]);
|
|
211
|
+
const toggleMute = (0, react_1.useCallback)(() => {
|
|
212
|
+
if (!voiceRef.current)
|
|
213
|
+
return;
|
|
214
|
+
if (debug)
|
|
215
|
+
console.debug('[useVoice] toggleMute');
|
|
216
|
+
voiceRef.current.toggleMicMute();
|
|
217
|
+
}, [debug]);
|
|
218
|
+
/* send text frame over a live voice call */
|
|
219
|
+
const sendMessage = (0, react_1.useCallback)((text) => {
|
|
220
|
+
if (!voiceRef.current || !text.trim())
|
|
221
|
+
return;
|
|
222
|
+
if (debug)
|
|
223
|
+
console.debug('[useVoice] sendMessage', text);
|
|
224
|
+
voiceRef.current.send({
|
|
225
|
+
type: 'text',
|
|
226
|
+
text: text.trim(),
|
|
227
|
+
});
|
|
228
|
+
// Optimistically add the user's message to the transcript
|
|
229
|
+
addMessage('user', text.trim());
|
|
230
|
+
}, [debug, addMessage]);
|
|
231
|
+
// Cleanup on unmount
|
|
232
|
+
(0, react_1.useEffect)(() => {
|
|
233
|
+
return () => {
|
|
234
|
+
if (debug)
|
|
235
|
+
console.debug('[useVoice] cleanup on unmount');
|
|
236
|
+
voiceRef.current?.stop();
|
|
237
|
+
if (timerRef.current) {
|
|
238
|
+
clearInterval(timerRef.current);
|
|
239
|
+
timerRef.current = null;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}, [debug]);
|
|
243
|
+
return {
|
|
244
|
+
// Mode
|
|
245
|
+
mode,
|
|
246
|
+
// Voice controls (audial-legacy names)
|
|
247
|
+
start,
|
|
248
|
+
stop,
|
|
249
|
+
toggleMute,
|
|
250
|
+
sendMessage,
|
|
251
|
+
// Spec-contract aliases
|
|
252
|
+
startVoice: start,
|
|
253
|
+
stopVoice: stop,
|
|
254
|
+
// State (audial-legacy field names)
|
|
255
|
+
status,
|
|
256
|
+
messages,
|
|
257
|
+
isMuted,
|
|
258
|
+
isAgentSpeaking,
|
|
259
|
+
duration,
|
|
260
|
+
lastError,
|
|
261
|
+
// Spec-contract aliases
|
|
262
|
+
voiceState: status,
|
|
263
|
+
error: lastError,
|
|
264
|
+
// Low-level access
|
|
265
|
+
voice: voiceRef.current,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=use-voice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-voice.js","sourceRoot":"","sources":["../../src/react/use-voice.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ChanlUser } from '../types';
|
|
2
|
+
export interface ChanlWidgetProps {
|
|
3
|
+
/** Public key (`pub_xxx`) — origin-scoped browser-safe auth. Required. */
|
|
4
|
+
pubKey: string;
|
|
5
|
+
/** Agent to load. Required. */
|
|
6
|
+
agentId: string;
|
|
7
|
+
/** Identified end-user (Intercom-style widget identity path). */
|
|
8
|
+
user?: ChanlUser;
|
|
9
|
+
/** HMAC-SHA256 of `user.externalId` — compute via `computeUserHash` on the server. */
|
|
10
|
+
userHash?: string;
|
|
11
|
+
/** Platform API base URL (auto-resolved to localhost/prod by default). */
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
/** Chat iframe host URL (defaults to `https://chat.channel.tel` in prod). */
|
|
14
|
+
chatHost?: string;
|
|
15
|
+
/** Visual theme. Default 'dark'. */
|
|
16
|
+
theme?: 'dark' | 'light';
|
|
17
|
+
/** Launcher position. Default 'bottom-right'. */
|
|
18
|
+
position?: 'bottom-right' | 'bottom-left';
|
|
19
|
+
/** Launcher button background color. */
|
|
20
|
+
color?: string;
|
|
21
|
+
/** Show the "Powered by Chanl" footer. Default true. */
|
|
22
|
+
branding?: boolean;
|
|
23
|
+
/** Override the agent's display name in the header. */
|
|
24
|
+
agentName?: string;
|
|
25
|
+
/** Subtitle shown under the agent name. */
|
|
26
|
+
agentSubtitle?: string;
|
|
27
|
+
/** 1–2 character initials for the avatar fallback. */
|
|
28
|
+
agentInitials?: string;
|
|
29
|
+
/** Avatar image URL. */
|
|
30
|
+
agentAvatarUrl?: string;
|
|
31
|
+
/** Override the greeting message shown when the chat panel first opens. */
|
|
32
|
+
greeting?: string;
|
|
33
|
+
/** Input placeholder text. */
|
|
34
|
+
placeholder?: string;
|
|
35
|
+
/** Override the dark theme background color. */
|
|
36
|
+
darkBg?: string;
|
|
37
|
+
/** Link to your privacy policy, shown in the disclaimer. */
|
|
38
|
+
privacyUrl?: string;
|
|
39
|
+
/** Locale code to load localized agent copy. */
|
|
40
|
+
locale?: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function ChanlWidget(props: ChanlWidgetProps): null;
|
|
43
|
+
//# sourceMappingURL=widget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget.d.ts","sourceRoot":"","sources":["../../src/react/widget.tsx"],"names":[],"mappings":"AAkDA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;IAEhB,iEAAiE;IACjE,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,cAAc,GAAG,aAAa,CAAC;IAC1C,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sDAAsD;IACtD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wBAAwB;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CA+IzD"}
|