@pipecat-ai/client-react 1.0.1 → 1.2.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/dist/index.d.ts +185 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1153 -3
- package/dist/index.js.map +1 -1
- package/dist/index.module.js +1146 -5
- package/dist/index.module.js.map +1 -1
- package/package.json +38 -2
package/dist/index.js
CHANGED
|
@@ -18,15 +18,24 @@ $parcel$export(module.exports, "PipecatClientAudio", () => $a2a1c5f475114d56$exp
|
|
|
18
18
|
$parcel$export(module.exports, "PipecatClientCamToggle", () => $666ceba11158b494$export$dc9a029eeca8213f);
|
|
19
19
|
$parcel$export(module.exports, "PipecatClientMicToggle", () => $1a9931980e271aa3$export$bc8133b69ff660a2);
|
|
20
20
|
$parcel$export(module.exports, "PipecatClientProvider", () => $8df0e777e4d7dd49$export$bb43666ced7a20d0);
|
|
21
|
+
$parcel$export(module.exports, "PipecatClientScreenShareToggle", () => $0a9d1dc5be2e1cc2$export$93764714dfab3a46);
|
|
21
22
|
$parcel$export(module.exports, "PipecatClientVideo", () => $0f97689637ada1d8$export$85974db6d0cc43b3);
|
|
22
23
|
$parcel$export(module.exports, "usePipecatClient", () => $172f489fc5d91d99$export$777fa8498be78705);
|
|
23
24
|
$parcel$export(module.exports, "usePipecatClientCamControl", () => $d9b24817de62910a$export$3ea2601427f0430f);
|
|
24
25
|
$parcel$export(module.exports, "usePipecatClientMediaDevices", () => $9bd3e7d3a9d7acd1$export$642bc4d2d2a376f1);
|
|
25
26
|
$parcel$export(module.exports, "usePipecatClientMediaTrack", () => $630203d8dad1dd45$export$9813dcd2d0c26814);
|
|
26
27
|
$parcel$export(module.exports, "usePipecatClientMicControl", () => $4af0eba414c586fd$export$388e706586309ef0);
|
|
28
|
+
$parcel$export(module.exports, "usePipecatClientScreenShareControl", () => $5fc67d7ca05dec34$export$be63b19bd7f7d4f5);
|
|
27
29
|
$parcel$export(module.exports, "usePipecatClientTransportState", () => $810478f6ae107062$export$30aee278309a867b);
|
|
28
30
|
$parcel$export(module.exports, "useRTVIClientEvent", () => $8a6b68ebf0332682$export$33a6ac53b8f02625);
|
|
29
31
|
$parcel$export(module.exports, "VoiceVisualizer", () => $a1dfa75b13e6bb9b$export$59bf27bd43679db6);
|
|
32
|
+
$parcel$export(module.exports, "useConversationContext", () => $984246ab4e966dee$export$8eec679bf8249822);
|
|
33
|
+
$parcel$export(module.exports, "usePipecatConversation", () => $fe6dfdd0b8560c78$export$acb832b064cb6c09);
|
|
34
|
+
$parcel$export(module.exports, "deduplicateFunctionCalls", () => $cbb62fb16c5d45ff$export$dfa183f99573a822);
|
|
35
|
+
$parcel$export(module.exports, "filterEmptyMessages", () => $cbb62fb16c5d45ff$export$3d3951a55577516);
|
|
36
|
+
$parcel$export(module.exports, "isMessageEmpty", () => $cbb62fb16c5d45ff$export$f4610a88b89838b);
|
|
37
|
+
$parcel$export(module.exports, "mergeMessages", () => $cbb62fb16c5d45ff$export$23a96e868837e158);
|
|
38
|
+
$parcel$export(module.exports, "sortByCreatedAt", () => $cbb62fb16c5d45ff$export$cbefc5865f8cbd89);
|
|
30
39
|
/**
|
|
31
40
|
* Copyright (c) 2024, Daily.
|
|
32
41
|
*
|
|
@@ -53,13 +62,734 @@ $parcel$export(module.exports, "VoiceVisualizer", () => $a1dfa75b13e6bb9b$export
|
|
|
53
62
|
|
|
54
63
|
|
|
55
64
|
var $d1f89db81f967f39$exports = {};
|
|
56
|
-
$d1f89db81f967f39$exports = JSON.parse("{\"name\":\"@pipecat-ai/client-react\",\"version\":\"1.0
|
|
65
|
+
$d1f89db81f967f39$exports = JSON.parse("{\"name\":\"@pipecat-ai/client-react\",\"version\":\"1.2.0\",\"license\":\"BSD-2-Clause\",\"main\":\"dist/index.js\",\"module\":\"dist/index.module.js\",\"types\":\"dist/index.d.ts\",\"source\":\"src/index.ts\",\"repository\":{\"type\":\"git\",\"url\":\"git+https://github.com/pipecat-ai/pipecat-client-web.git\"},\"exports\":{\".\":{\"types\":\"./dist/index.d.ts\",\"import\":\"./dist/index.module.js\",\"require\":\"./dist/index.js\"}},\"files\":[\"dist\",\"package.json\",\"README.md\"],\"scripts\":{\"build\":\"parcel build --no-cache\",\"dev\":\"parcel watch\",\"lint\":\"eslint . --report-unused-disable-directives --max-warnings 0 --ignore-pattern 'dist/'\",\"test\":\"jest\"},\"jest\":{\"preset\":\"ts-jest\",\"testEnvironment\":\"jsdom\",\"moduleNameMapper\":{\"^@/(.*)$\":\"<rootDir>/src/$1\"},\"transform\":{\"^.+\\\\.tsx?$\":[\"ts-jest\",{\"tsconfig\":{\"jsx\":\"react-jsx\",\"module\":\"commonjs\",\"moduleResolution\":\"node\",\"esModuleInterop\":true,\"allowImportingTsExtensions\":false,\"noUnusedLocals\":false,\"noUnusedParameters\":false}}]}},\"devDependencies\":{\"@jest/globals\":\"^30.2.0\",\"@pipecat-ai/client-js\":\"*\",\"@types/jest\":\"^30.0.0\",\"@types/react\":\"^18.3.3\",\"@types/react-dom\":\"^18.3.0\",\"@typescript-eslint/eslint-plugin\":\"^8.32.0\",\"eslint\":\"^9.11.1\",\"eslint-config-prettier\":\"^9.1.0\",\"eslint-plugin-react-hooks\":\"^5.2.0\",\"eslint-plugin-simple-import-sort\":\"^12.1.1\",\"jest\":\"^30.2.0\",\"jest-environment-jsdom\":\"^30.2.0\",\"parcel\":\"^2.12.0\",\"react\":\"^18.3.1\",\"react-dom\":\"^18.3.1\",\"ts-jest\":\"^29.4.6\",\"typescript\":\"^5.2.2\"},\"peerDependencies\":{\"@pipecat-ai/client-js\":\"*\",\"react\":\">=18\",\"react-dom\":\">=18\"},\"dependencies\":{\"jotai\":\"^2.9.0\"}}");
|
|
57
66
|
|
|
58
67
|
|
|
59
68
|
|
|
60
69
|
|
|
61
70
|
|
|
62
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Copyright (c) 2024, Daily.
|
|
74
|
+
*
|
|
75
|
+
* SPDX-License-Identifier: BSD-2-Clause
|
|
76
|
+
*/ /**
|
|
77
|
+
* Copyright (c) 2024, Daily.
|
|
78
|
+
*
|
|
79
|
+
* SPDX-License-Identifier: BSD-2-Clause
|
|
80
|
+
*/ const $ad0c8ea1ee293a79$var$normalizeForMatching = (text)=>{
|
|
81
|
+
return text.toLowerCase().replace(/[^\w\s]/g, "");
|
|
82
|
+
};
|
|
83
|
+
const $ad0c8ea1ee293a79$var$skipWhitespace = (text, start)=>{
|
|
84
|
+
let i = start;
|
|
85
|
+
while(i < text.length && /\s/.test(text[i]))i++;
|
|
86
|
+
return i;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Finds where `spoken` appears in `unspoken`, starting from `startPosition`.
|
|
90
|
+
* - Best-effort sequential word matching (normalized, punctuation-stripped)
|
|
91
|
+
* - Returns the original start position on mismatch (no advancement)
|
|
92
|
+
*/ const $ad0c8ea1ee293a79$var$findSpokenPositionInUnspoken = (spoken, unspoken, startPosition)=>{
|
|
93
|
+
if (!spoken || !unspoken || startPosition >= unspoken.length) return startPosition;
|
|
94
|
+
// If spoken text includes a leading separator space, skip leading whitespace in unspoken.
|
|
95
|
+
let actualStart = startPosition;
|
|
96
|
+
let spokenForMatching = spoken;
|
|
97
|
+
if (spoken.startsWith(" ") && startPosition < unspoken.length) {
|
|
98
|
+
actualStart = $ad0c8ea1ee293a79$var$skipWhitespace(unspoken, startPosition);
|
|
99
|
+
spokenForMatching = spoken.trimStart();
|
|
100
|
+
} else if (startPosition === 0 && startPosition < unspoken.length) // If we're at the start, also skip leading whitespace (e.g. newlines)
|
|
101
|
+
actualStart = $ad0c8ea1ee293a79$var$skipWhitespace(unspoken, 0);
|
|
102
|
+
const remainder = unspoken.slice(actualStart);
|
|
103
|
+
// Sentence-level: if spoken exactly matches the remainder (normalized), consume the whole part
|
|
104
|
+
// so we never leave a word unspoken due to word-matching edge cases.
|
|
105
|
+
if ($ad0c8ea1ee293a79$var$normalizeForMatching(spokenForMatching).trim() === $ad0c8ea1ee293a79$var$normalizeForMatching(remainder).trim()) return unspoken.length;
|
|
106
|
+
const spokenWords = $ad0c8ea1ee293a79$var$normalizeForMatching(spokenForMatching).split(/\s+/).filter(Boolean);
|
|
107
|
+
if (spokenWords.length === 0) return actualStart;
|
|
108
|
+
const unspokenWords = $ad0c8ea1ee293a79$var$normalizeForMatching(unspoken.slice(actualStart)).split(/\s+/).filter(Boolean);
|
|
109
|
+
// Sequential match, allowing prefix match for contractions (e.g. "I" vs "I'm")
|
|
110
|
+
// and limited skipping of mismatched unspoken words (e.g. punctuation artifacts).
|
|
111
|
+
let matchedWords = 0;
|
|
112
|
+
let consecutiveSkips = 0;
|
|
113
|
+
const MAX_CONSECUTIVE_SKIPS = 2;
|
|
114
|
+
for(let i = 0; i < unspokenWords.length && matchedWords < spokenWords.length; i++){
|
|
115
|
+
const target = spokenWords[matchedWords];
|
|
116
|
+
const candidate = unspokenWords[i];
|
|
117
|
+
if (candidate === target || candidate.startsWith(target)) {
|
|
118
|
+
matchedWords++;
|
|
119
|
+
consecutiveSkips = 0;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
consecutiveSkips++;
|
|
123
|
+
if (consecutiveSkips > MAX_CONSECUTIVE_SKIPS) return actualStart;
|
|
124
|
+
// Skip this unspoken word and try matching the next one
|
|
125
|
+
}
|
|
126
|
+
if (matchedWords < spokenWords.length) return actualStart;
|
|
127
|
+
// Convert word matches back into a character position in the original unspoken string.
|
|
128
|
+
const isWordChar = (char)=>/[a-zA-Z0-9]/.test(char);
|
|
129
|
+
let wordCount = 0;
|
|
130
|
+
let i = actualStart;
|
|
131
|
+
let inWord = false;
|
|
132
|
+
while(i < unspoken.length){
|
|
133
|
+
const charIsWord = isWordChar(unspoken[i]);
|
|
134
|
+
if (charIsWord && !inWord) {
|
|
135
|
+
inWord = true;
|
|
136
|
+
wordCount++;
|
|
137
|
+
if (wordCount === matchedWords) {
|
|
138
|
+
// Consume the rest of this word
|
|
139
|
+
i++;
|
|
140
|
+
while(i < unspoken.length && isWordChar(unspoken[i]))i++;
|
|
141
|
+
// Include any punctuation after the word until the next space, then include the space
|
|
142
|
+
while(i < unspoken.length){
|
|
143
|
+
if (unspoken[i] === " ") {
|
|
144
|
+
i++;
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
i++;
|
|
148
|
+
}
|
|
149
|
+
return i;
|
|
150
|
+
}
|
|
151
|
+
} else if (!charIsWord && inWord) inWord = false;
|
|
152
|
+
i++;
|
|
153
|
+
}
|
|
154
|
+
return unspoken.length;
|
|
155
|
+
};
|
|
156
|
+
function $ad0c8ea1ee293a79$export$802e9b947136afbf(cursor, parts) {
|
|
157
|
+
if (parts.length === 0) return false;
|
|
158
|
+
for(let i = 0; i < parts.length; i++){
|
|
159
|
+
if (typeof parts[i]?.text !== "string") continue;
|
|
160
|
+
if (!cursor.partFinalFlags[i]) return true;
|
|
161
|
+
}
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
function $ad0c8ea1ee293a79$export$9b39fd8438081d6d(cursor, parts, spokenText) {
|
|
165
|
+
if (parts.length === 0) return false;
|
|
166
|
+
// Find the next part that should be spoken (skip parts already marked final/skipped)
|
|
167
|
+
let partToMatch = cursor.currentPartIndex;
|
|
168
|
+
while(partToMatch < parts.length && cursor.partFinalFlags[partToMatch])partToMatch++;
|
|
169
|
+
if (partToMatch >= parts.length) return false;
|
|
170
|
+
if (partToMatch > cursor.currentPartIndex) {
|
|
171
|
+
cursor.currentPartIndex = partToMatch;
|
|
172
|
+
cursor.currentCharIndex = 0;
|
|
173
|
+
}
|
|
174
|
+
const currentPart = parts[cursor.currentPartIndex];
|
|
175
|
+
if (typeof currentPart.text !== "string") return false;
|
|
176
|
+
const partText = currentPart.text;
|
|
177
|
+
const startChar = cursor.currentCharIndex;
|
|
178
|
+
const newPosition = $ad0c8ea1ee293a79$var$findSpokenPositionInUnspoken(spokenText, partText, startChar);
|
|
179
|
+
const whitespaceEnd = $ad0c8ea1ee293a79$var$skipWhitespace(partText, startChar);
|
|
180
|
+
if (newPosition > whitespaceEnd) {
|
|
181
|
+
cursor.currentCharIndex = newPosition;
|
|
182
|
+
if (newPosition >= partText.length) {
|
|
183
|
+
cursor.partFinalFlags[cursor.currentPartIndex] = true;
|
|
184
|
+
if (cursor.currentPartIndex < parts.length - 1) {
|
|
185
|
+
cursor.currentPartIndex++;
|
|
186
|
+
cursor.currentCharIndex = 0;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
// Intra-part scan-ahead recovery: if matching failed at the current position,
|
|
192
|
+
// scan forward word-by-word within the same part. This prevents the cursor
|
|
193
|
+
// from getting permanently stuck mid-part when a single word mismatch occurs
|
|
194
|
+
// (e.g. TTS variation, punctuation boundary like `apexes."Sometimes`).
|
|
195
|
+
if (startChar > 0) {
|
|
196
|
+
const MAX_SCAN_WORDS = 8;
|
|
197
|
+
let scanPos = startChar;
|
|
198
|
+
for(let scan = 0; scan < MAX_SCAN_WORDS; scan++){
|
|
199
|
+
// Advance past current word
|
|
200
|
+
while(scanPos < partText.length && !/\s/.test(partText[scanPos]))scanPos++;
|
|
201
|
+
// Advance past whitespace to next word
|
|
202
|
+
while(scanPos < partText.length && /\s/.test(partText[scanPos]))scanPos++;
|
|
203
|
+
if (scanPos >= partText.length) break;
|
|
204
|
+
const retryPos = $ad0c8ea1ee293a79$var$findSpokenPositionInUnspoken(spokenText, partText, scanPos);
|
|
205
|
+
const scanWsEnd = $ad0c8ea1ee293a79$var$skipWhitespace(partText, scanPos);
|
|
206
|
+
if (retryPos > scanWsEnd) {
|
|
207
|
+
cursor.currentCharIndex = retryPos;
|
|
208
|
+
if (retryPos >= partText.length) {
|
|
209
|
+
cursor.partFinalFlags[cursor.currentPartIndex] = true;
|
|
210
|
+
if (cursor.currentPartIndex < parts.length - 1) {
|
|
211
|
+
cursor.currentPartIndex++;
|
|
212
|
+
cursor.currentCharIndex = 0;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Mismatch recovery: try to find the spoken text in a later part.
|
|
220
|
+
for(let nextPartIdx = cursor.currentPartIndex + 1; nextPartIdx < parts.length; nextPartIdx++){
|
|
221
|
+
const nextPart = parts[nextPartIdx];
|
|
222
|
+
if (typeof nextPart.text !== "string") continue;
|
|
223
|
+
const match = $ad0c8ea1ee293a79$var$findSpokenPositionInUnspoken(spokenText, nextPart.text, 0);
|
|
224
|
+
const nextWhitespaceEnd = $ad0c8ea1ee293a79$var$skipWhitespace(nextPart.text, 0);
|
|
225
|
+
if (match > nextWhitespaceEnd) {
|
|
226
|
+
// Mark skipped parts as final and jump to the matched part
|
|
227
|
+
for(let i = cursor.currentPartIndex; i < nextPartIdx; i++)cursor.partFinalFlags[i] = true;
|
|
228
|
+
cursor.currentPartIndex = nextPartIdx;
|
|
229
|
+
cursor.currentCharIndex = match;
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// If we're stuck at the start, mark the current part as skipped to avoid deadlock.
|
|
234
|
+
if (startChar === 0 && cursor.currentPartIndex < parts.length - 1) {
|
|
235
|
+
cursor.partFinalFlags[cursor.currentPartIndex] = true;
|
|
236
|
+
cursor.currentPartIndex++;
|
|
237
|
+
cursor.currentCharIndex = 0;
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Copyright (c) 2024, Daily.
|
|
246
|
+
*
|
|
247
|
+
* SPDX-License-Identifier: BSD-2-Clause
|
|
248
|
+
*/
|
|
249
|
+
const $28e6b30207a0392e$export$92a4076839a978d0 = (0, $5Zyvw$jotai.atom)([]);
|
|
250
|
+
const $28e6b30207a0392e$export$bd01e11bc95333a1 = (0, $5Zyvw$jotai.atom)(new Map());
|
|
251
|
+
const $28e6b30207a0392e$export$b0cd27059c88d0ab = (0, $5Zyvw$jotai.atom)(new Map());
|
|
252
|
+
const $28e6b30207a0392e$export$57b1a1df06a7e728 = (0, $5Zyvw$jotai.atom)(null);
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Copyright (c) 2024, Daily.
|
|
257
|
+
*
|
|
258
|
+
* SPDX-License-Identifier: BSD-2-Clause
|
|
259
|
+
*/ // ES2020-compatible polyfills for findLast / findLastIndex
|
|
260
|
+
function $f4fa178c5adc67bb$export$8855a8be7bd3e9f8(arr, predicate) {
|
|
261
|
+
for(let i = arr.length - 1; i >= 0; i--){
|
|
262
|
+
if (predicate(arr[i], i, arr)) return i;
|
|
263
|
+
}
|
|
264
|
+
return -1;
|
|
265
|
+
}
|
|
266
|
+
function $f4fa178c5adc67bb$export$296de88ccac4bedb(arr, predicate) {
|
|
267
|
+
const idx = $f4fa178c5adc67bb$export$8855a8be7bd3e9f8(arr, predicate);
|
|
268
|
+
return idx === -1 ? undefined : arr[idx];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
/** Max time gap (ms) between consecutive same-role messages for merging. */ const $cbb62fb16c5d45ff$var$MERGE_WINDOW_MS = 30000;
|
|
273
|
+
const $cbb62fb16c5d45ff$export$cbefc5865f8cbd89 = (a, b)=>{
|
|
274
|
+
return a.createdAt < b.createdAt ? -1 : a.createdAt > b.createdAt ? 1 : 0;
|
|
275
|
+
};
|
|
276
|
+
const $cbb62fb16c5d45ff$export$f4610a88b89838b = (message)=>{
|
|
277
|
+
if (message.role === "function_call") return false;
|
|
278
|
+
const parts = message.parts || [];
|
|
279
|
+
if (parts.length === 0) return true;
|
|
280
|
+
return parts.every((p)=>{
|
|
281
|
+
if (typeof p.text === "string") return p.text.trim().length === 0;
|
|
282
|
+
// Check BotOutputText objects
|
|
283
|
+
if (typeof p.text === "object" && p.text !== null && "spoken" in p.text && "unspoken" in p.text) {
|
|
284
|
+
const botText = p.text;
|
|
285
|
+
return botText.spoken.trim().length === 0 && botText.unspoken.trim().length === 0;
|
|
286
|
+
}
|
|
287
|
+
// For ReactNode, consider it non-empty
|
|
288
|
+
return false;
|
|
289
|
+
});
|
|
290
|
+
};
|
|
291
|
+
const $cbb62fb16c5d45ff$export$3d3951a55577516 = (messages)=>{
|
|
292
|
+
return messages.filter((message, index, array)=>{
|
|
293
|
+
if (!$cbb62fb16c5d45ff$export$f4610a88b89838b(message)) return true;
|
|
294
|
+
// For empty messages, keep only if no following non-empty message with same role
|
|
295
|
+
const nextMessageWithSameRole = array.slice(index + 1).find((m)=>m.role === message.role && !$cbb62fb16c5d45ff$export$f4610a88b89838b(m));
|
|
296
|
+
return !nextMessageWithSameRole;
|
|
297
|
+
});
|
|
298
|
+
};
|
|
299
|
+
const $cbb62fb16c5d45ff$export$23a96e868837e158 = (messages)=>{
|
|
300
|
+
const mergedMessages = [];
|
|
301
|
+
for(let i = 0; i < messages.length; i++){
|
|
302
|
+
const currentMessage = messages[i];
|
|
303
|
+
const lastMerged = mergedMessages[mergedMessages.length - 1];
|
|
304
|
+
const timeDiff = lastMerged ? Math.abs(new Date(currentMessage.createdAt).getTime() - new Date(lastMerged.createdAt).getTime()) : Infinity;
|
|
305
|
+
const shouldMerge = lastMerged && lastMerged.role === currentMessage.role && currentMessage.role !== "system" && currentMessage.role !== "function_call" && timeDiff < $cbb62fb16c5d45ff$var$MERGE_WINDOW_MS;
|
|
306
|
+
if (shouldMerge) mergedMessages[mergedMessages.length - 1] = {
|
|
307
|
+
...lastMerged,
|
|
308
|
+
parts: [
|
|
309
|
+
...lastMerged.parts || [],
|
|
310
|
+
...currentMessage.parts || []
|
|
311
|
+
],
|
|
312
|
+
updatedAt: currentMessage.updatedAt || currentMessage.createdAt,
|
|
313
|
+
final: currentMessage.final !== false
|
|
314
|
+
};
|
|
315
|
+
else mergedMessages.push(currentMessage);
|
|
316
|
+
}
|
|
317
|
+
return mergedMessages;
|
|
318
|
+
};
|
|
319
|
+
const $cbb62fb16c5d45ff$var$statusPriority = {
|
|
320
|
+
started: 0,
|
|
321
|
+
in_progress: 1,
|
|
322
|
+
completed: 2
|
|
323
|
+
};
|
|
324
|
+
const $cbb62fb16c5d45ff$export$dfa183f99573a822 = (messages)=>{
|
|
325
|
+
const bestByToolCallId = new Map();
|
|
326
|
+
const toRemove = new Set();
|
|
327
|
+
for(let i = 0; i < messages.length; i++){
|
|
328
|
+
const msg = messages[i];
|
|
329
|
+
const tcid = msg.functionCall?.tool_call_id;
|
|
330
|
+
if (msg.role !== "function_call" || !tcid) continue;
|
|
331
|
+
const existingIdx = bestByToolCallId.get(tcid);
|
|
332
|
+
if (existingIdx !== undefined) {
|
|
333
|
+
const existingPriority = $cbb62fb16c5d45ff$var$statusPriority[messages[existingIdx].functionCall.status] ?? 0;
|
|
334
|
+
const currentPriority = $cbb62fb16c5d45ff$var$statusPriority[msg.functionCall.status] ?? 0;
|
|
335
|
+
if (currentPriority >= existingPriority) {
|
|
336
|
+
toRemove.add(existingIdx);
|
|
337
|
+
bestByToolCallId.set(tcid, i);
|
|
338
|
+
} else toRemove.add(i);
|
|
339
|
+
} else bestByToolCallId.set(tcid, i);
|
|
340
|
+
}
|
|
341
|
+
if (toRemove.size === 0) return messages;
|
|
342
|
+
return messages.filter((_, i)=>!toRemove.has(i));
|
|
343
|
+
};
|
|
344
|
+
const $cbb62fb16c5d45ff$var$normalizeMessagesForUI = (messages)=>{
|
|
345
|
+
return $cbb62fb16c5d45ff$export$23a96e868837e158($cbb62fb16c5d45ff$export$dfa183f99573a822($cbb62fb16c5d45ff$export$3d3951a55577516([
|
|
346
|
+
...messages
|
|
347
|
+
].sort($cbb62fb16c5d45ff$export$cbefc5865f8cbd89))));
|
|
348
|
+
};
|
|
349
|
+
// ---------------------------------------------------------------------------
|
|
350
|
+
// Internal helpers
|
|
351
|
+
// ---------------------------------------------------------------------------
|
|
352
|
+
const $cbb62fb16c5d45ff$var$callCallbacks = (callbacksMap, type, message)=>{
|
|
353
|
+
callbacksMap.forEach((callbacks)=>{
|
|
354
|
+
try {
|
|
355
|
+
callbacks[type]?.(message);
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.error(`Error in ${type} callback:`, error);
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
};
|
|
361
|
+
function $cbb62fb16c5d45ff$export$f2820c5e040afe17(get, set, id, callbacks) {
|
|
362
|
+
const map = new Map(get((0, $28e6b30207a0392e$export$b0cd27059c88d0ab)));
|
|
363
|
+
map.set(id, callbacks);
|
|
364
|
+
set((0, $28e6b30207a0392e$export$b0cd27059c88d0ab), map);
|
|
365
|
+
}
|
|
366
|
+
function $cbb62fb16c5d45ff$export$46ae1ba121fdc956(get, set, id) {
|
|
367
|
+
const map = new Map(get((0, $28e6b30207a0392e$export$b0cd27059c88d0ab)));
|
|
368
|
+
map.delete(id);
|
|
369
|
+
set((0, $28e6b30207a0392e$export$b0cd27059c88d0ab), map);
|
|
370
|
+
}
|
|
371
|
+
function $cbb62fb16c5d45ff$export$f2434643f2abff11(_get, set) {
|
|
372
|
+
set((0, $28e6b30207a0392e$export$92a4076839a978d0), []);
|
|
373
|
+
set((0, $28e6b30207a0392e$export$bd01e11bc95333a1), new Map());
|
|
374
|
+
}
|
|
375
|
+
function $cbb62fb16c5d45ff$export$16fdb433d434f08(get, set, messageData) {
|
|
376
|
+
const now = new Date();
|
|
377
|
+
const message = {
|
|
378
|
+
...messageData,
|
|
379
|
+
createdAt: now.toISOString(),
|
|
380
|
+
updatedAt: now.toISOString()
|
|
381
|
+
};
|
|
382
|
+
const current = get((0, $28e6b30207a0392e$export$92a4076839a978d0));
|
|
383
|
+
const updatedMessages = [
|
|
384
|
+
...current,
|
|
385
|
+
message
|
|
386
|
+
];
|
|
387
|
+
const processedMessages = $cbb62fb16c5d45ff$var$normalizeMessagesForUI(updatedMessages);
|
|
388
|
+
$cbb62fb16c5d45ff$var$callCallbacks(get((0, $28e6b30207a0392e$export$b0cd27059c88d0ab)), "onMessageCreated", message);
|
|
389
|
+
set((0, $28e6b30207a0392e$export$92a4076839a978d0), processedMessages);
|
|
390
|
+
}
|
|
391
|
+
function $cbb62fb16c5d45ff$export$a05f96a2aa40873e(get, set, role, updates) {
|
|
392
|
+
const messages = [
|
|
393
|
+
...get((0, $28e6b30207a0392e$export$92a4076839a978d0))
|
|
394
|
+
];
|
|
395
|
+
const lastMessageIndex = (0, $f4fa178c5adc67bb$export$8855a8be7bd3e9f8)(messages, (msg)=>msg.role === role);
|
|
396
|
+
if (lastMessageIndex === -1) return;
|
|
397
|
+
const existing = messages[lastMessageIndex];
|
|
398
|
+
const updatedMessage = {
|
|
399
|
+
...existing,
|
|
400
|
+
...updates,
|
|
401
|
+
updatedAt: new Date().toISOString()
|
|
402
|
+
};
|
|
403
|
+
messages[lastMessageIndex] = updatedMessage;
|
|
404
|
+
const processedMessages = $cbb62fb16c5d45ff$var$normalizeMessagesForUI(messages);
|
|
405
|
+
$cbb62fb16c5d45ff$var$callCallbacks(get((0, $28e6b30207a0392e$export$b0cd27059c88d0ab)), "onMessageUpdated", updatedMessage);
|
|
406
|
+
set((0, $28e6b30207a0392e$export$92a4076839a978d0), processedMessages);
|
|
407
|
+
}
|
|
408
|
+
function $cbb62fb16c5d45ff$export$78bd074993ab081f(get, set, role) {
|
|
409
|
+
const messages = [
|
|
410
|
+
...get((0, $28e6b30207a0392e$export$92a4076839a978d0))
|
|
411
|
+
];
|
|
412
|
+
const lastMessageIndex = (0, $f4fa178c5adc67bb$export$8855a8be7bd3e9f8)(messages, (msg)=>msg.role === role);
|
|
413
|
+
if (lastMessageIndex === -1) return;
|
|
414
|
+
const lastMessage = messages[lastMessageIndex];
|
|
415
|
+
// Check if message is empty
|
|
416
|
+
if ($cbb62fb16c5d45ff$export$f4610a88b89838b(lastMessage)) // Remove empty message only if it has no text in streams either
|
|
417
|
+
messages.splice(lastMessageIndex, 1);
|
|
418
|
+
else {
|
|
419
|
+
// Finalize message and its last part
|
|
420
|
+
const parts = [
|
|
421
|
+
...lastMessage.parts || []
|
|
422
|
+
];
|
|
423
|
+
if (parts.length > 0) parts[parts.length - 1] = {
|
|
424
|
+
...parts[parts.length - 1],
|
|
425
|
+
final: true
|
|
426
|
+
};
|
|
427
|
+
messages[lastMessageIndex] = {
|
|
428
|
+
...lastMessage,
|
|
429
|
+
parts: parts,
|
|
430
|
+
final: true,
|
|
431
|
+
updatedAt: new Date().toISOString()
|
|
432
|
+
};
|
|
433
|
+
$cbb62fb16c5d45ff$var$callCallbacks(get((0, $28e6b30207a0392e$export$b0cd27059c88d0ab)), "onMessageUpdated", messages[lastMessageIndex]);
|
|
434
|
+
}
|
|
435
|
+
const processedMessages = $cbb62fb16c5d45ff$var$normalizeMessagesForUI(messages);
|
|
436
|
+
set((0, $28e6b30207a0392e$export$92a4076839a978d0), processedMessages);
|
|
437
|
+
}
|
|
438
|
+
function $cbb62fb16c5d45ff$export$cd74f809c89ea10c(get, set, role) {
|
|
439
|
+
const messages = [
|
|
440
|
+
...get((0, $28e6b30207a0392e$export$92a4076839a978d0))
|
|
441
|
+
];
|
|
442
|
+
const lastMessageIndex = (0, $f4fa178c5adc67bb$export$8855a8be7bd3e9f8)(messages, (msg)=>msg.role === role);
|
|
443
|
+
if (lastMessageIndex === -1) return;
|
|
444
|
+
const lastMessage = messages[lastMessageIndex];
|
|
445
|
+
if ($cbb62fb16c5d45ff$export$f4610a88b89838b(lastMessage)) {
|
|
446
|
+
messages.splice(lastMessageIndex, 1);
|
|
447
|
+
const processedMessages = $cbb62fb16c5d45ff$var$normalizeMessagesForUI(messages);
|
|
448
|
+
set((0, $28e6b30207a0392e$export$92a4076839a978d0), processedMessages);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
function $cbb62fb16c5d45ff$export$c3a007efc2f315a0(get, set, messageData) {
|
|
452
|
+
const now = new Date();
|
|
453
|
+
const message = {
|
|
454
|
+
role: messageData.role,
|
|
455
|
+
final: true,
|
|
456
|
+
parts: [
|
|
457
|
+
...messageData.parts
|
|
458
|
+
],
|
|
459
|
+
createdAt: now.toISOString(),
|
|
460
|
+
updatedAt: now.toISOString()
|
|
461
|
+
};
|
|
462
|
+
const current = get((0, $28e6b30207a0392e$export$92a4076839a978d0));
|
|
463
|
+
const updatedMessages = [
|
|
464
|
+
...current,
|
|
465
|
+
message
|
|
466
|
+
];
|
|
467
|
+
const processedMessages = $cbb62fb16c5d45ff$var$normalizeMessagesForUI(updatedMessages);
|
|
468
|
+
$cbb62fb16c5d45ff$var$callCallbacks(get((0, $28e6b30207a0392e$export$b0cd27059c88d0ab)), "onMessageCreated", message);
|
|
469
|
+
set((0, $28e6b30207a0392e$export$92a4076839a978d0), processedMessages);
|
|
470
|
+
}
|
|
471
|
+
function $cbb62fb16c5d45ff$export$57de01211e3df548(get, set, text, final) {
|
|
472
|
+
const now = new Date();
|
|
473
|
+
const messages = [
|
|
474
|
+
...get((0, $28e6b30207a0392e$export$92a4076839a978d0))
|
|
475
|
+
];
|
|
476
|
+
// Find last user message
|
|
477
|
+
const lastUserIndex = (0, $f4fa178c5adc67bb$export$8855a8be7bd3e9f8)(messages, (m)=>m.role === "user");
|
|
478
|
+
if (lastUserIndex !== -1 && !messages[lastUserIndex].final) {
|
|
479
|
+
// Update existing user message
|
|
480
|
+
const target = {
|
|
481
|
+
...messages[lastUserIndex]
|
|
482
|
+
};
|
|
483
|
+
const parts = Array.isArray(target.parts) ? [
|
|
484
|
+
...target.parts
|
|
485
|
+
] : [];
|
|
486
|
+
const lastPart = parts[parts.length - 1];
|
|
487
|
+
if (!lastPart || lastPart.final) // Start a new part
|
|
488
|
+
parts.push({
|
|
489
|
+
text: text,
|
|
490
|
+
final: final,
|
|
491
|
+
createdAt: now.toISOString()
|
|
492
|
+
});
|
|
493
|
+
else // Update in-progress part
|
|
494
|
+
parts[parts.length - 1] = {
|
|
495
|
+
...lastPart,
|
|
496
|
+
text: text,
|
|
497
|
+
final: final
|
|
498
|
+
};
|
|
499
|
+
const updatedMessage = {
|
|
500
|
+
...target,
|
|
501
|
+
parts: parts,
|
|
502
|
+
updatedAt: now.toISOString()
|
|
503
|
+
};
|
|
504
|
+
messages[lastUserIndex] = updatedMessage;
|
|
505
|
+
const processedMessages = $cbb62fb16c5d45ff$var$normalizeMessagesForUI(messages);
|
|
506
|
+
$cbb62fb16c5d45ff$var$callCallbacks(get((0, $28e6b30207a0392e$export$b0cd27059c88d0ab)), "onMessageUpdated", updatedMessage);
|
|
507
|
+
set((0, $28e6b30207a0392e$export$92a4076839a978d0), processedMessages);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
// Create a new user message initialized with this transcript
|
|
511
|
+
const newMessage = {
|
|
512
|
+
role: "user",
|
|
513
|
+
final: false,
|
|
514
|
+
parts: [
|
|
515
|
+
{
|
|
516
|
+
text: text,
|
|
517
|
+
final: final,
|
|
518
|
+
createdAt: now.toISOString()
|
|
519
|
+
}
|
|
520
|
+
],
|
|
521
|
+
createdAt: now.toISOString(),
|
|
522
|
+
updatedAt: now.toISOString()
|
|
523
|
+
};
|
|
524
|
+
const updatedMessages = [
|
|
525
|
+
...messages,
|
|
526
|
+
newMessage
|
|
527
|
+
];
|
|
528
|
+
const processedMessages = $cbb62fb16c5d45ff$var$normalizeMessagesForUI(updatedMessages);
|
|
529
|
+
$cbb62fb16c5d45ff$var$callCallbacks(get((0, $28e6b30207a0392e$export$b0cd27059c88d0ab)), "onMessageCreated", newMessage);
|
|
530
|
+
set((0, $28e6b30207a0392e$export$92a4076839a978d0), processedMessages);
|
|
531
|
+
}
|
|
532
|
+
function $cbb62fb16c5d45ff$export$d78810e35f742a16(get, set, text, final, spoken, aggregatedBy) {
|
|
533
|
+
const now = new Date();
|
|
534
|
+
const messages = [
|
|
535
|
+
...get((0, $28e6b30207a0392e$export$92a4076839a978d0))
|
|
536
|
+
];
|
|
537
|
+
const botOutputMessageState = new Map(get((0, $28e6b30207a0392e$export$bd01e11bc95333a1)));
|
|
538
|
+
const lastAssistantIndex = (0, $f4fa178c5adc67bb$export$8855a8be7bd3e9f8)(messages, (msg)=>msg.role === "assistant");
|
|
539
|
+
let messageId;
|
|
540
|
+
let isNewMessage = false;
|
|
541
|
+
if (lastAssistantIndex === -1) {
|
|
542
|
+
// Create new assistant message
|
|
543
|
+
isNewMessage = true;
|
|
544
|
+
messageId = now.toISOString();
|
|
545
|
+
const newMessage = {
|
|
546
|
+
role: "assistant",
|
|
547
|
+
final: final,
|
|
548
|
+
parts: [],
|
|
549
|
+
createdAt: messageId,
|
|
550
|
+
updatedAt: messageId
|
|
551
|
+
};
|
|
552
|
+
messages.push(newMessage);
|
|
553
|
+
// Initialize message state
|
|
554
|
+
botOutputMessageState.set(messageId, {
|
|
555
|
+
currentPartIndex: 0,
|
|
556
|
+
currentCharIndex: 0,
|
|
557
|
+
partFinalFlags: []
|
|
558
|
+
});
|
|
559
|
+
} else {
|
|
560
|
+
// Update existing assistant message
|
|
561
|
+
const lastMessage = messages[lastAssistantIndex];
|
|
562
|
+
messageId = lastMessage.createdAt;
|
|
563
|
+
messages[lastAssistantIndex] = {
|
|
564
|
+
...lastMessage,
|
|
565
|
+
final: final ? true : lastMessage.final,
|
|
566
|
+
updatedAt: now.toISOString()
|
|
567
|
+
};
|
|
568
|
+
// Ensure message state exists
|
|
569
|
+
if (!botOutputMessageState.has(messageId)) botOutputMessageState.set(messageId, {
|
|
570
|
+
currentPartIndex: 0,
|
|
571
|
+
currentCharIndex: 0,
|
|
572
|
+
partFinalFlags: []
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
const messageState = botOutputMessageState.get(messageId);
|
|
576
|
+
const message = messages[lastAssistantIndex === -1 ? messages.length - 1 : lastAssistantIndex];
|
|
577
|
+
const parts = [
|
|
578
|
+
...message.parts || []
|
|
579
|
+
];
|
|
580
|
+
if (!spoken) {
|
|
581
|
+
// UNSPOKEN EVENT: Create/update message parts immediately
|
|
582
|
+
// Only append when both current and last part are word-level; sentence-level
|
|
583
|
+
// and other types each get their own part so spoken events can match 1:1.
|
|
584
|
+
const isDefaultType = aggregatedBy === "sentence" || aggregatedBy === "word" || !aggregatedBy;
|
|
585
|
+
const lastPart = parts[parts.length - 1];
|
|
586
|
+
const shouldAppend = lastPart && aggregatedBy === "word" && lastPart.aggregatedBy === "word" && typeof lastPart.text === "string";
|
|
587
|
+
if (shouldAppend) {
|
|
588
|
+
// Append to last part (word-level only)
|
|
589
|
+
const lastPartText = lastPart.text;
|
|
590
|
+
const separator = lastPartText && !lastPartText.endsWith(" ") && !text.startsWith(" ") ? " " : "";
|
|
591
|
+
parts[parts.length - 1] = {
|
|
592
|
+
...lastPart,
|
|
593
|
+
text: lastPartText + separator + text
|
|
594
|
+
};
|
|
595
|
+
} else {
|
|
596
|
+
// Create new part (sentence-level, custom types, or first word chunk)
|
|
597
|
+
// Default to inline; custom types get displayMode from metadata in the hook
|
|
598
|
+
const defaultDisplayMode = isDefaultType ? "inline" : undefined;
|
|
599
|
+
const newPart = {
|
|
600
|
+
text: text,
|
|
601
|
+
final: false,
|
|
602
|
+
createdAt: now.toISOString(),
|
|
603
|
+
aggregatedBy: aggregatedBy,
|
|
604
|
+
displayMode: defaultDisplayMode
|
|
605
|
+
};
|
|
606
|
+
parts.push(newPart);
|
|
607
|
+
// Extend partFinalFlags array
|
|
608
|
+
messageState.partFinalFlags.push(false);
|
|
609
|
+
}
|
|
610
|
+
// Update message with new parts
|
|
611
|
+
messages[lastAssistantIndex === -1 ? messages.length - 1 : lastAssistantIndex] = {
|
|
612
|
+
...message,
|
|
613
|
+
parts: parts
|
|
614
|
+
};
|
|
615
|
+
} else {
|
|
616
|
+
// SPOKEN EVENT: advance cursor into existing text, or add as new part if
|
|
617
|
+
// there is none (bots that only send spoken: true, never unspoken).
|
|
618
|
+
const advanced = parts.length > 0 && (0, $ad0c8ea1ee293a79$export$9b39fd8438081d6d)(messageState, parts, text);
|
|
619
|
+
if (!advanced) {
|
|
620
|
+
// No unspoken content to advance: add this text as a part already fully spoken
|
|
621
|
+
const isDefaultType = aggregatedBy === "sentence" || aggregatedBy === "word" || !aggregatedBy;
|
|
622
|
+
const defaultDisplayMode = isDefaultType ? "inline" : undefined;
|
|
623
|
+
const newPart = {
|
|
624
|
+
text: text,
|
|
625
|
+
final: false,
|
|
626
|
+
createdAt: now.toISOString(),
|
|
627
|
+
aggregatedBy: aggregatedBy,
|
|
628
|
+
displayMode: defaultDisplayMode
|
|
629
|
+
};
|
|
630
|
+
parts.push(newPart);
|
|
631
|
+
messageState.partFinalFlags.push(true);
|
|
632
|
+
messageState.currentPartIndex = parts.length - 1;
|
|
633
|
+
messageState.currentCharIndex = text.length;
|
|
634
|
+
messages[lastAssistantIndex === -1 ? messages.length - 1 : lastAssistantIndex] = {
|
|
635
|
+
...message,
|
|
636
|
+
parts: parts
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
const processedMessages = $cbb62fb16c5d45ff$var$normalizeMessagesForUI(messages);
|
|
641
|
+
const cbs = get((0, $28e6b30207a0392e$export$b0cd27059c88d0ab));
|
|
642
|
+
const updatedMsg = messages[lastAssistantIndex === -1 ? messages.length - 1 : lastAssistantIndex];
|
|
643
|
+
if (isNewMessage) $cbb62fb16c5d45ff$var$callCallbacks(cbs, "onMessageCreated", updatedMsg);
|
|
644
|
+
else $cbb62fb16c5d45ff$var$callCallbacks(cbs, "onMessageUpdated", updatedMsg);
|
|
645
|
+
set((0, $28e6b30207a0392e$export$92a4076839a978d0), processedMessages);
|
|
646
|
+
set((0, $28e6b30207a0392e$export$bd01e11bc95333a1), botOutputMessageState);
|
|
647
|
+
}
|
|
648
|
+
function $cbb62fb16c5d45ff$export$e450805545c7dd86(get, set, data) {
|
|
649
|
+
const messages = get((0, $28e6b30207a0392e$export$92a4076839a978d0));
|
|
650
|
+
// If a tool_call_id is provided, check for an existing entry to avoid duplicates
|
|
651
|
+
if (data.tool_call_id) {
|
|
652
|
+
const existingIndex = (0, $f4fa178c5adc67bb$export$8855a8be7bd3e9f8)(messages, (msg)=>msg.role === "function_call" && msg.functionCall?.tool_call_id === data.tool_call_id);
|
|
653
|
+
if (existingIndex !== -1) return;
|
|
654
|
+
}
|
|
655
|
+
const now = new Date();
|
|
656
|
+
const message = {
|
|
657
|
+
role: "function_call",
|
|
658
|
+
final: false,
|
|
659
|
+
parts: [],
|
|
660
|
+
createdAt: now.toISOString(),
|
|
661
|
+
updatedAt: now.toISOString(),
|
|
662
|
+
functionCall: {
|
|
663
|
+
function_name: data.function_name,
|
|
664
|
+
tool_call_id: data.tool_call_id,
|
|
665
|
+
args: data.args,
|
|
666
|
+
status: "started"
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
const updatedMessages = [
|
|
670
|
+
...messages,
|
|
671
|
+
message
|
|
672
|
+
];
|
|
673
|
+
const processedMessages = $cbb62fb16c5d45ff$var$normalizeMessagesForUI(updatedMessages);
|
|
674
|
+
$cbb62fb16c5d45ff$var$callCallbacks(get((0, $28e6b30207a0392e$export$b0cd27059c88d0ab)), "onMessageCreated", message);
|
|
675
|
+
set((0, $28e6b30207a0392e$export$92a4076839a978d0), processedMessages);
|
|
676
|
+
}
|
|
677
|
+
function $cbb62fb16c5d45ff$export$1908264de3a8afe4(get, set, tool_call_id, updates) {
|
|
678
|
+
const messages = [
|
|
679
|
+
...get((0, $28e6b30207a0392e$export$92a4076839a978d0))
|
|
680
|
+
];
|
|
681
|
+
const index = (0, $f4fa178c5adc67bb$export$8855a8be7bd3e9f8)(messages, (msg)=>msg.role === "function_call" && msg.functionCall?.tool_call_id === tool_call_id);
|
|
682
|
+
if (index === -1) return false;
|
|
683
|
+
const existing = messages[index];
|
|
684
|
+
const updated = {
|
|
685
|
+
...existing,
|
|
686
|
+
updatedAt: new Date().toISOString(),
|
|
687
|
+
final: updates.status === "completed" ? true : existing.final,
|
|
688
|
+
functionCall: {
|
|
689
|
+
...existing.functionCall,
|
|
690
|
+
...updates
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
messages[index] = updated;
|
|
694
|
+
const processedMessages = $cbb62fb16c5d45ff$var$normalizeMessagesForUI(messages);
|
|
695
|
+
$cbb62fb16c5d45ff$var$callCallbacks(get((0, $28e6b30207a0392e$export$b0cd27059c88d0ab)), "onMessageUpdated", updated);
|
|
696
|
+
set((0, $28e6b30207a0392e$export$92a4076839a978d0), processedMessages);
|
|
697
|
+
return true;
|
|
698
|
+
}
|
|
699
|
+
function $cbb62fb16c5d45ff$export$54b3765e641b1813(get, set, updates) {
|
|
700
|
+
const messages = [
|
|
701
|
+
...get((0, $28e6b30207a0392e$export$92a4076839a978d0))
|
|
702
|
+
];
|
|
703
|
+
const index = (0, $f4fa178c5adc67bb$export$8855a8be7bd3e9f8)(messages, (msg)=>msg.role === "function_call" && msg.functionCall?.status === "started" && !msg.functionCall?.tool_call_id);
|
|
704
|
+
if (index === -1) return false;
|
|
705
|
+
const existing = messages[index];
|
|
706
|
+
const updated = {
|
|
707
|
+
...existing,
|
|
708
|
+
updatedAt: new Date().toISOString(),
|
|
709
|
+
functionCall: {
|
|
710
|
+
...existing.functionCall,
|
|
711
|
+
...updates
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
messages[index] = updated;
|
|
715
|
+
const processedMessages = $cbb62fb16c5d45ff$var$normalizeMessagesForUI(messages);
|
|
716
|
+
$cbb62fb16c5d45ff$var$callCallbacks(get((0, $28e6b30207a0392e$export$b0cd27059c88d0ab)), "onMessageUpdated", updated);
|
|
717
|
+
set((0, $28e6b30207a0392e$export$92a4076839a978d0), processedMessages);
|
|
718
|
+
return true;
|
|
719
|
+
}
|
|
720
|
+
function $cbb62fb16c5d45ff$export$809efdca1a10761a(get, set, data) {
|
|
721
|
+
const messages = get((0, $28e6b30207a0392e$export$92a4076839a978d0));
|
|
722
|
+
const lastFc = (0, $f4fa178c5adc67bb$export$296de88ccac4bedb)(messages, (m)=>m.role === "function_call");
|
|
723
|
+
// Check if InProgress already created an entry (events arrived out of order).
|
|
724
|
+
if (lastFc?.functionCall && lastFc.functionCall.status !== "started" && Date.now() - new Date(lastFc.createdAt).getTime() < 2000) {
|
|
725
|
+
if (data.function_name && !lastFc.functionCall.function_name && lastFc.functionCall.tool_call_id) $cbb62fb16c5d45ff$export$1908264de3a8afe4(get, set, lastFc.functionCall.tool_call_id, {
|
|
726
|
+
function_name: data.function_name
|
|
727
|
+
});
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
$cbb62fb16c5d45ff$export$e450805545c7dd86(get, set, {
|
|
731
|
+
function_name: data.function_name
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
function $cbb62fb16c5d45ff$export$568cde5f4aa4dcba(get, set, data) {
|
|
735
|
+
// Tier 1: Try to update the last "started" entry (from LLMFunctionCallStarted)
|
|
736
|
+
const updated = $cbb62fb16c5d45ff$export$54b3765e641b1813(get, set, {
|
|
737
|
+
function_name: data.function_name,
|
|
738
|
+
tool_call_id: data.tool_call_id,
|
|
739
|
+
args: data.args,
|
|
740
|
+
status: "in_progress"
|
|
741
|
+
});
|
|
742
|
+
if (!updated) {
|
|
743
|
+
// Tier 2: Try updating an existing entry by tool_call_id
|
|
744
|
+
const found = $cbb62fb16c5d45ff$export$1908264de3a8afe4(get, set, data.tool_call_id, {
|
|
745
|
+
function_name: data.function_name,
|
|
746
|
+
args: data.args,
|
|
747
|
+
status: "in_progress"
|
|
748
|
+
});
|
|
749
|
+
if (!found) {
|
|
750
|
+
// Tier 3: No existing entry at all; create a new one as in_progress
|
|
751
|
+
$cbb62fb16c5d45ff$export$e450805545c7dd86(get, set, {
|
|
752
|
+
function_name: data.function_name,
|
|
753
|
+
tool_call_id: data.tool_call_id,
|
|
754
|
+
args: data.args
|
|
755
|
+
});
|
|
756
|
+
$cbb62fb16c5d45ff$export$1908264de3a8afe4(get, set, data.tool_call_id, {
|
|
757
|
+
status: "in_progress"
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
function $cbb62fb16c5d45ff$export$a3cea3f7508e820b(get, set, data) {
|
|
763
|
+
// Tier 1: Try updating by tool_call_id
|
|
764
|
+
const found = $cbb62fb16c5d45ff$export$1908264de3a8afe4(get, set, data.tool_call_id, {
|
|
765
|
+
function_name: data.function_name,
|
|
766
|
+
status: "completed",
|
|
767
|
+
result: data.result,
|
|
768
|
+
cancelled: data.cancelled
|
|
769
|
+
});
|
|
770
|
+
if (!found) {
|
|
771
|
+
// Tier 2: No match by tool_call_id (e.g. InProgress was skipped).
|
|
772
|
+
const matched = $cbb62fb16c5d45ff$export$54b3765e641b1813(get, set, {
|
|
773
|
+
function_name: data.function_name,
|
|
774
|
+
tool_call_id: data.tool_call_id
|
|
775
|
+
});
|
|
776
|
+
if (matched) $cbb62fb16c5d45ff$export$1908264de3a8afe4(get, set, data.tool_call_id, {
|
|
777
|
+
status: "completed",
|
|
778
|
+
result: data.result,
|
|
779
|
+
cancelled: data.cancelled
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Copyright (c) 2024, Daily.
|
|
788
|
+
*
|
|
789
|
+
* SPDX-License-Identifier: BSD-2-Clause
|
|
790
|
+
*/
|
|
791
|
+
|
|
792
|
+
|
|
63
793
|
/**
|
|
64
794
|
* Copyright (c) 2024, Daily.
|
|
65
795
|
*
|
|
@@ -88,6 +818,239 @@ const $8a6b68ebf0332682$export$33a6ac53b8f02625 = (event, handler)=>{
|
|
|
88
818
|
};
|
|
89
819
|
|
|
90
820
|
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
/**
|
|
826
|
+
* Checks if a version meets a minimum version requirement.
|
|
827
|
+
* Inlined to avoid adding a `semver` dependency.
|
|
828
|
+
*/ function $40515932ecd2dc41$var$isMinVersion(currentVersion, minVersion) {
|
|
829
|
+
// Strip pre-release suffix (e.g. "1.1.0-beta.1" -> "1.1.0")
|
|
830
|
+
const parts = currentVersion.split("-")[0].split(".").map(Number);
|
|
831
|
+
for(let i = 0; i < 3; i++){
|
|
832
|
+
if ((parts[i] || 0) > minVersion[i]) return true;
|
|
833
|
+
if ((parts[i] || 0) < minVersion[i]) return false;
|
|
834
|
+
}
|
|
835
|
+
return true; // equal
|
|
836
|
+
}
|
|
837
|
+
/** Delay (ms) before finalizing the assistant message after bot stops speaking. */ const $40515932ecd2dc41$var$BOT_STOPPED_FINALIZE_DELAY_MS = 2500;
|
|
838
|
+
function $40515932ecd2dc41$export$52680e26621bab39() {
|
|
839
|
+
const userStoppedTimeout = (0, $5Zyvw$react.useRef)(undefined);
|
|
840
|
+
const botStoppedSpeakingTimeoutRef = (0, $5Zyvw$react.useRef)(undefined);
|
|
841
|
+
const assistantStreamResetRef = (0, $5Zyvw$react.useRef)(0);
|
|
842
|
+
const botOutputLastChunkRef = (0, $5Zyvw$react.useRef)({
|
|
843
|
+
spoken: "",
|
|
844
|
+
unspoken: ""
|
|
845
|
+
});
|
|
846
|
+
// Clean up pending timeouts on unmount
|
|
847
|
+
(0, $5Zyvw$react.useEffect)(()=>{
|
|
848
|
+
return ()=>{
|
|
849
|
+
clearTimeout(userStoppedTimeout.current);
|
|
850
|
+
clearTimeout(botStoppedSpeakingTimeoutRef.current);
|
|
851
|
+
};
|
|
852
|
+
}, []);
|
|
853
|
+
// -- helpers ---------------------------------------------------------------
|
|
854
|
+
const finalizeLastAssistantMessageIfPending = (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set)=>{
|
|
855
|
+
clearTimeout(botStoppedSpeakingTimeoutRef.current);
|
|
856
|
+
botStoppedSpeakingTimeoutRef.current = undefined;
|
|
857
|
+
const messages = get((0, $28e6b30207a0392e$export$92a4076839a978d0));
|
|
858
|
+
const lastAssistant = (0, $f4fa178c5adc67bb$export$296de88ccac4bedb)(messages, (m)=>m.role === "assistant");
|
|
859
|
+
if (lastAssistant && !lastAssistant.final) (0, $cbb62fb16c5d45ff$export$78bd074993ab081f)(get, set, "assistant");
|
|
860
|
+
}, []));
|
|
861
|
+
const ensureAssistantMessage = (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set)=>{
|
|
862
|
+
const messages = get((0, $28e6b30207a0392e$export$92a4076839a978d0));
|
|
863
|
+
const lastAssistantIndex = (0, $f4fa178c5adc67bb$export$8855a8be7bd3e9f8)(messages, (msg)=>msg.role === "assistant");
|
|
864
|
+
const lastAssistant = lastAssistantIndex !== -1 ? messages[lastAssistantIndex] : undefined;
|
|
865
|
+
if (!lastAssistant || lastAssistant.final) {
|
|
866
|
+
// If the message was finalized but still has unspoken content, it was
|
|
867
|
+
// finalized prematurely (e.g. BotStoppedSpeaking timer fired during a
|
|
868
|
+
// TTS pause mid-response). Un-finalize it instead of creating a new
|
|
869
|
+
// message bubble — but only when no user message followed.
|
|
870
|
+
if (lastAssistant?.final && lastAssistantIndex === messages.length - 1) {
|
|
871
|
+
const messageId = lastAssistant.createdAt;
|
|
872
|
+
const botOutputState = get((0, $28e6b30207a0392e$export$bd01e11bc95333a1));
|
|
873
|
+
const cursor = botOutputState.get(messageId);
|
|
874
|
+
if (cursor && (0, $ad0c8ea1ee293a79$export$802e9b947136afbf)(cursor, lastAssistant.parts || [])) {
|
|
875
|
+
(0, $cbb62fb16c5d45ff$export$a05f96a2aa40873e)(get, set, "assistant", {
|
|
876
|
+
final: false
|
|
877
|
+
});
|
|
878
|
+
return false;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
(0, $cbb62fb16c5d45ff$export$16fdb433d434f08)(get, set, {
|
|
882
|
+
role: "assistant",
|
|
883
|
+
final: false,
|
|
884
|
+
parts: []
|
|
885
|
+
});
|
|
886
|
+
assistantStreamResetRef.current += 1;
|
|
887
|
+
return true;
|
|
888
|
+
}
|
|
889
|
+
return false;
|
|
890
|
+
}, []));
|
|
891
|
+
// -- event handlers --------------------------------------------------------
|
|
892
|
+
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).Connected, (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set)=>{
|
|
893
|
+
(0, $cbb62fb16c5d45ff$export$f2434643f2abff11)(get, set);
|
|
894
|
+
set((0, $28e6b30207a0392e$export$57b1a1df06a7e728), null);
|
|
895
|
+
clearTimeout(botStoppedSpeakingTimeoutRef.current);
|
|
896
|
+
botStoppedSpeakingTimeoutRef.current = undefined;
|
|
897
|
+
botOutputLastChunkRef.current = {
|
|
898
|
+
spoken: "",
|
|
899
|
+
unspoken: ""
|
|
900
|
+
};
|
|
901
|
+
}, [])));
|
|
902
|
+
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).BotReady, (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((_get, set, botData)=>{
|
|
903
|
+
const rtviVersion = botData.version;
|
|
904
|
+
const supportsBotOutput = $40515932ecd2dc41$var$isMinVersion(rtviVersion, [
|
|
905
|
+
1,
|
|
906
|
+
1,
|
|
907
|
+
0
|
|
908
|
+
]);
|
|
909
|
+
set((0, $28e6b30207a0392e$export$57b1a1df06a7e728), supportsBotOutput);
|
|
910
|
+
}, [])));
|
|
911
|
+
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).BotOutput, (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set, data)=>{
|
|
912
|
+
// A BotOutput event means the response is still active; cancel any
|
|
913
|
+
// pending finalize timer from BotStoppedSpeaking.
|
|
914
|
+
clearTimeout(botStoppedSpeakingTimeoutRef.current);
|
|
915
|
+
botStoppedSpeakingTimeoutRef.current = undefined;
|
|
916
|
+
ensureAssistantMessage();
|
|
917
|
+
// Handle spacing for BotOutput chunks
|
|
918
|
+
let textToAdd = data.text;
|
|
919
|
+
const lastChunk = data.spoken ? botOutputLastChunkRef.current.spoken : botOutputLastChunkRef.current.unspoken;
|
|
920
|
+
// Add space separator if needed between BotOutput chunks
|
|
921
|
+
if (lastChunk) textToAdd = " " + textToAdd;
|
|
922
|
+
// Update the appropriate last chunk tracker
|
|
923
|
+
if (data.spoken) botOutputLastChunkRef.current.spoken = textToAdd;
|
|
924
|
+
else botOutputLastChunkRef.current.unspoken = textToAdd;
|
|
925
|
+
// Update both spoken and unspoken text streams
|
|
926
|
+
const isFinal = data.aggregated_by === "sentence";
|
|
927
|
+
(0, $cbb62fb16c5d45ff$export$d78810e35f742a16)(get, set, textToAdd, isFinal, data.spoken, data.aggregated_by);
|
|
928
|
+
}, [
|
|
929
|
+
ensureAssistantMessage
|
|
930
|
+
])));
|
|
931
|
+
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).BotStoppedSpeaking, (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set)=>{
|
|
932
|
+
// Don't finalize immediately; start a timer. Bot may start speaking again (pause).
|
|
933
|
+
clearTimeout(botStoppedSpeakingTimeoutRef.current);
|
|
934
|
+
const messages = get((0, $28e6b30207a0392e$export$92a4076839a978d0));
|
|
935
|
+
const lastAssistant = (0, $f4fa178c5adc67bb$export$296de88ccac4bedb)(messages, (m)=>m.role === "assistant");
|
|
936
|
+
if (!lastAssistant || lastAssistant.final) return;
|
|
937
|
+
botStoppedSpeakingTimeoutRef.current = setTimeout(()=>{
|
|
938
|
+
botStoppedSpeakingTimeoutRef.current = undefined;
|
|
939
|
+
// Snap the speech-progress cursor to the end of all parts.
|
|
940
|
+
// The bot finished speaking normally (not interrupted), so all
|
|
941
|
+
// text should render as "spoken". Without this, text from the
|
|
942
|
+
// last sentence can remain grey if the spoken BotOutput event
|
|
943
|
+
// didn't match the unspoken text exactly.
|
|
944
|
+
const msgs = get((0, $28e6b30207a0392e$export$92a4076839a978d0));
|
|
945
|
+
const cursorMap = new Map(get((0, $28e6b30207a0392e$export$bd01e11bc95333a1)));
|
|
946
|
+
const last = (0, $f4fa178c5adc67bb$export$296de88ccac4bedb)(msgs, (m)=>m.role === "assistant");
|
|
947
|
+
if (last) {
|
|
948
|
+
const cursor = cursorMap.get(last.createdAt);
|
|
949
|
+
if (cursor && last.parts && last.parts.length > 0) {
|
|
950
|
+
const lastPartIdx = last.parts.length - 1;
|
|
951
|
+
const lastPartText = last.parts[lastPartIdx]?.text;
|
|
952
|
+
cursor.currentPartIndex = lastPartIdx;
|
|
953
|
+
cursor.currentCharIndex = typeof lastPartText === "string" ? lastPartText.length : 0;
|
|
954
|
+
for(let i = 0; i <= lastPartIdx; i++)cursor.partFinalFlags[i] = true;
|
|
955
|
+
set((0, $28e6b30207a0392e$export$bd01e11bc95333a1), cursorMap);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
(0, $cbb62fb16c5d45ff$export$78bd074993ab081f)(get, set, "assistant");
|
|
959
|
+
}, $40515932ecd2dc41$var$BOT_STOPPED_FINALIZE_DELAY_MS);
|
|
960
|
+
}, [])));
|
|
961
|
+
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).BotStartedSpeaking, (0, $5Zyvw$react.useCallback)(()=>{
|
|
962
|
+
// Bot is speaking again; reset the finalize timer (bot was just pausing).
|
|
963
|
+
clearTimeout(botStoppedSpeakingTimeoutRef.current);
|
|
964
|
+
botStoppedSpeakingTimeoutRef.current = undefined;
|
|
965
|
+
}, []));
|
|
966
|
+
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).UserStartedSpeaking, (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set)=>{
|
|
967
|
+
// User started a new turn; bot's turn is done. Fast-forward: finalize immediately.
|
|
968
|
+
finalizeLastAssistantMessageIfPending();
|
|
969
|
+
clearTimeout(userStoppedTimeout.current);
|
|
970
|
+
// Only finalize the previous user message if the bot has responded since
|
|
971
|
+
// the user last spoke. This prevents finalizing during VAD gaps (brief
|
|
972
|
+
// breathing pauses within the same user turn where UserStoppedSpeaking/
|
|
973
|
+
// UserStartedSpeaking fire without an actual turn change).
|
|
974
|
+
const messages = get((0, $28e6b30207a0392e$export$92a4076839a978d0));
|
|
975
|
+
const lastUserIdx = (0, $f4fa178c5adc67bb$export$8855a8be7bd3e9f8)(messages, (m)=>m.role === "user");
|
|
976
|
+
if (lastUserIdx !== -1 && !messages[lastUserIdx].final) {
|
|
977
|
+
const hasBotActivityAfterUser = messages.slice(lastUserIdx + 1).some((m)=>m.role === "assistant");
|
|
978
|
+
if (hasBotActivityAfterUser) (0, $cbb62fb16c5d45ff$export$78bd074993ab081f)(get, set, "user");
|
|
979
|
+
}
|
|
980
|
+
}, [
|
|
981
|
+
finalizeLastAssistantMessageIfPending
|
|
982
|
+
])));
|
|
983
|
+
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).UserTranscript, (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set, data)=>{
|
|
984
|
+
const text = data.text ?? "";
|
|
985
|
+
const final = Boolean(data.final);
|
|
986
|
+
(0, $cbb62fb16c5d45ff$export$57de01211e3df548)(get, set, text, final);
|
|
987
|
+
// If we got any transcript, cancel pending cleanup
|
|
988
|
+
clearTimeout(userStoppedTimeout.current);
|
|
989
|
+
}, [])));
|
|
990
|
+
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).UserStoppedSpeaking, (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set)=>{
|
|
991
|
+
clearTimeout(userStoppedTimeout.current);
|
|
992
|
+
// If no transcript ends up arriving, ensure any accidental empty placeholder is removed.
|
|
993
|
+
userStoppedTimeout.current = setTimeout(()=>{
|
|
994
|
+
// Re-read state at timeout time
|
|
995
|
+
const messages = get((0, $28e6b30207a0392e$export$92a4076839a978d0));
|
|
996
|
+
const lastUser = (0, $f4fa178c5adc67bb$export$296de88ccac4bedb)(messages, (m)=>m.role === "user");
|
|
997
|
+
const hasParts = Array.isArray(lastUser?.parts) && lastUser.parts.length > 0;
|
|
998
|
+
if (!lastUser || !hasParts) (0, $cbb62fb16c5d45ff$export$cd74f809c89ea10c)(get, set, "user");
|
|
999
|
+
else if (!lastUser.final) (0, $cbb62fb16c5d45ff$export$78bd074993ab081f)(get, set, "user");
|
|
1000
|
+
}, 3000);
|
|
1001
|
+
}, [])));
|
|
1002
|
+
// LLM Function Call lifecycle events
|
|
1003
|
+
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).LLMFunctionCallStarted, (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set, data)=>{
|
|
1004
|
+
(0, $cbb62fb16c5d45ff$export$809efdca1a10761a)(get, set, {
|
|
1005
|
+
function_name: data.function_name
|
|
1006
|
+
});
|
|
1007
|
+
}, [])));
|
|
1008
|
+
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).LLMFunctionCallInProgress, (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set, data)=>{
|
|
1009
|
+
(0, $cbb62fb16c5d45ff$export$568cde5f4aa4dcba)(get, set, {
|
|
1010
|
+
function_name: data.function_name,
|
|
1011
|
+
tool_call_id: data.tool_call_id,
|
|
1012
|
+
args: data.arguments
|
|
1013
|
+
});
|
|
1014
|
+
}, [])));
|
|
1015
|
+
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).LLMFunctionCallStopped, (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set, data)=>{
|
|
1016
|
+
(0, $cbb62fb16c5d45ff$export$a3cea3f7508e820b)(get, set, {
|
|
1017
|
+
function_name: data.function_name,
|
|
1018
|
+
tool_call_id: data.tool_call_id,
|
|
1019
|
+
result: data.result,
|
|
1020
|
+
cancelled: data.cancelled
|
|
1021
|
+
});
|
|
1022
|
+
}, [])));
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
|
|
1026
|
+
const $984246ab4e966dee$export$4d68d6035e4164b1 = /*#__PURE__*/ (0, $5Zyvw$react.createContext)(null);
|
|
1027
|
+
const $984246ab4e966dee$export$e372a2172e7d18e8 = ({ children: children })=>{
|
|
1028
|
+
(0, $40515932ecd2dc41$export$52680e26621bab39)();
|
|
1029
|
+
const injectMessage = (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set, message)=>{
|
|
1030
|
+
(0, $cbb62fb16c5d45ff$export$c3a007efc2f315a0)(get, set, message);
|
|
1031
|
+
}, []));
|
|
1032
|
+
const botOutputSupported = (0, $5Zyvw$jotai.useAtomValue)((0, $28e6b30207a0392e$export$57b1a1df06a7e728));
|
|
1033
|
+
return (0, $5Zyvw$reactjsxruntime.jsx)($984246ab4e966dee$export$4d68d6035e4164b1.Provider, {
|
|
1034
|
+
value: {
|
|
1035
|
+
injectMessage: injectMessage,
|
|
1036
|
+
botOutputSupported: botOutputSupported
|
|
1037
|
+
},
|
|
1038
|
+
children: children
|
|
1039
|
+
});
|
|
1040
|
+
};
|
|
1041
|
+
$984246ab4e966dee$export$e372a2172e7d18e8.displayName = "PipecatConversationProvider";
|
|
1042
|
+
const $984246ab4e966dee$export$8eec679bf8249822 = ()=>{
|
|
1043
|
+
const context = (0, $5Zyvw$react.useContext)($984246ab4e966dee$export$4d68d6035e4164b1);
|
|
1044
|
+
if (!context) throw new Error("useConversationContext must be used within a PipecatClientProvider");
|
|
1045
|
+
return context;
|
|
1046
|
+
};
|
|
1047
|
+
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
|
|
1052
|
+
|
|
1053
|
+
|
|
91
1054
|
const $44c6278d186dd94f$export$d6bdcccacef16204 = /*#__PURE__*/ (0, $5Zyvw$react.createContext)({
|
|
92
1055
|
enableCam: ()=>{
|
|
93
1056
|
throw new Error("PipecatClientCamStateContext: enableCam() called outside of provider");
|
|
@@ -100,17 +1063,25 @@ const $44c6278d186dd94f$export$802b42df0e0d8153 = /*#__PURE__*/ (0, $5Zyvw$react
|
|
|
100
1063
|
},
|
|
101
1064
|
isMicEnabled: false
|
|
102
1065
|
});
|
|
1066
|
+
const $44c6278d186dd94f$export$8e633e67c760098b = /*#__PURE__*/ (0, $5Zyvw$react.createContext)({
|
|
1067
|
+
enableScreenShare: ()=>{
|
|
1068
|
+
throw new Error("PipecatClientScreenShareStateContext: enableScreenShare() called outside of provider");
|
|
1069
|
+
},
|
|
1070
|
+
isScreenShareEnabled: false
|
|
1071
|
+
});
|
|
103
1072
|
const $44c6278d186dd94f$export$db79fdf85ddd6b65 = /*#__PURE__*/ (0, $5Zyvw$react.createContext)("disconnected");
|
|
104
1073
|
const $44c6278d186dd94f$export$4777554fda61c378 = ({ children: children })=>{
|
|
105
1074
|
const client = (0, $172f489fc5d91d99$export$777fa8498be78705)();
|
|
106
1075
|
const [isCamEnabled, setIsCamEnabled] = (0, $5Zyvw$react.useState)(false);
|
|
107
1076
|
const [isMicEnabled, setIsMicEnabled] = (0, $5Zyvw$react.useState)(false);
|
|
1077
|
+
const [isScreenShareEnabled, setIsScreenShareEnabled] = (0, $5Zyvw$react.useState)(false);
|
|
108
1078
|
const [transportState, setTransportState] = (0, $5Zyvw$react.useState)("disconnected");
|
|
109
1079
|
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).TransportStateChanged, (state)=>{
|
|
110
1080
|
setTransportState(state);
|
|
111
1081
|
if (state === "initialized" && client) {
|
|
112
1082
|
setIsCamEnabled(client.isCamEnabled ?? false);
|
|
113
1083
|
setIsMicEnabled(client.isMicEnabled ?? false);
|
|
1084
|
+
setIsScreenShareEnabled(client.isSharingScreen ?? false);
|
|
114
1085
|
}
|
|
115
1086
|
});
|
|
116
1087
|
const enableCam = (0, $5Zyvw$react.useCallback)((enabled)=>{
|
|
@@ -125,6 +1096,17 @@ const $44c6278d186dd94f$export$4777554fda61c378 = ({ children: children })=>{
|
|
|
125
1096
|
}, [
|
|
126
1097
|
client
|
|
127
1098
|
]);
|
|
1099
|
+
const enableScreenShare = (0, $5Zyvw$react.useCallback)((enabled)=>{
|
|
1100
|
+
client?.enableScreenShare?.(enabled);
|
|
1101
|
+
}, [
|
|
1102
|
+
client
|
|
1103
|
+
]);
|
|
1104
|
+
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).ScreenTrackStarted, (_track, participant)=>{
|
|
1105
|
+
if (participant?.local) setIsScreenShareEnabled(true);
|
|
1106
|
+
});
|
|
1107
|
+
(0, $8a6b68ebf0332682$export$33a6ac53b8f02625)((0, $5Zyvw$pipecataiclientjs.RTVIEvent).ScreenTrackStopped, (_track, participant)=>{
|
|
1108
|
+
if (participant?.local) setIsScreenShareEnabled(false);
|
|
1109
|
+
});
|
|
128
1110
|
return (0, $5Zyvw$reactjsxruntime.jsx)($44c6278d186dd94f$export$db79fdf85ddd6b65.Provider, {
|
|
129
1111
|
value: transportState,
|
|
130
1112
|
children: (0, $5Zyvw$reactjsxruntime.jsx)($44c6278d186dd94f$export$d6bdcccacef16204.Provider, {
|
|
@@ -137,7 +1119,13 @@ const $44c6278d186dd94f$export$4777554fda61c378 = ({ children: children })=>{
|
|
|
137
1119
|
enableMic: enableMic,
|
|
138
1120
|
isMicEnabled: isMicEnabled
|
|
139
1121
|
},
|
|
140
|
-
children:
|
|
1122
|
+
children: (0, $5Zyvw$reactjsxruntime.jsx)($44c6278d186dd94f$export$8e633e67c760098b.Provider, {
|
|
1123
|
+
value: {
|
|
1124
|
+
enableScreenShare: enableScreenShare,
|
|
1125
|
+
isScreenShareEnabled: isScreenShareEnabled
|
|
1126
|
+
},
|
|
1127
|
+
children: children
|
|
1128
|
+
})
|
|
141
1129
|
})
|
|
142
1130
|
})
|
|
143
1131
|
});
|
|
@@ -197,7 +1185,9 @@ const $8df0e777e4d7dd49$export$bb43666ced7a20d0 = ({ children: children, client:
|
|
|
197
1185
|
off: off
|
|
198
1186
|
},
|
|
199
1187
|
children: (0, $5Zyvw$reactjsxruntime.jsx)((0, $44c6278d186dd94f$export$4777554fda61c378), {
|
|
200
|
-
children:
|
|
1188
|
+
children: (0, $5Zyvw$reactjsxruntime.jsx)((0, $984246ab4e966dee$export$e372a2172e7d18e8), {
|
|
1189
|
+
children: children
|
|
1190
|
+
})
|
|
201
1191
|
})
|
|
202
1192
|
})
|
|
203
1193
|
})
|
|
@@ -378,6 +1368,44 @@ var $1a9931980e271aa3$export$2e2bcd8739ae039 = $1a9931980e271aa3$export$bc8133b6
|
|
|
378
1368
|
|
|
379
1369
|
|
|
380
1370
|
|
|
1371
|
+
/**
|
|
1372
|
+
* Copyright (c) 2025, Daily.
|
|
1373
|
+
*
|
|
1374
|
+
* SPDX-License-Identifier: BSD-2-Clause
|
|
1375
|
+
*/
|
|
1376
|
+
|
|
1377
|
+
const $5fc67d7ca05dec34$export$be63b19bd7f7d4f5 = ()=>(0, $5Zyvw$react.useContext)((0, $44c6278d186dd94f$export$8e633e67c760098b));
|
|
1378
|
+
|
|
1379
|
+
|
|
1380
|
+
const $0a9d1dc5be2e1cc2$export$93764714dfab3a46 = ({ onScreenShareEnabledChanged: onScreenShareEnabledChanged, disabled: disabled = false, children: children })=>{
|
|
1381
|
+
const { enableScreenShare: enableScreenShare, isScreenShareEnabled: isScreenShareEnabled } = (0, $5fc67d7ca05dec34$export$be63b19bd7f7d4f5)();
|
|
1382
|
+
const handleToggleScreenShare = (0, $5Zyvw$react.useCallback)(()=>{
|
|
1383
|
+
if (disabled) return;
|
|
1384
|
+
enableScreenShare(!isScreenShareEnabled);
|
|
1385
|
+
}, [
|
|
1386
|
+
disabled,
|
|
1387
|
+
enableScreenShare,
|
|
1388
|
+
isScreenShareEnabled
|
|
1389
|
+
]);
|
|
1390
|
+
(0, $5Zyvw$react.useEffect)(()=>{
|
|
1391
|
+
onScreenShareEnabledChanged?.(isScreenShareEnabled);
|
|
1392
|
+
}, [
|
|
1393
|
+
isScreenShareEnabled,
|
|
1394
|
+
onScreenShareEnabledChanged
|
|
1395
|
+
]);
|
|
1396
|
+
return (0, $5Zyvw$reactjsxruntime.jsx)((0, $5Zyvw$reactjsxruntime.Fragment), {
|
|
1397
|
+
children: children({
|
|
1398
|
+
isScreenShareEnabled: isScreenShareEnabled,
|
|
1399
|
+
onClick: handleToggleScreenShare,
|
|
1400
|
+
disabled: disabled
|
|
1401
|
+
})
|
|
1402
|
+
});
|
|
1403
|
+
};
|
|
1404
|
+
var $0a9d1dc5be2e1cc2$export$2e2bcd8739ae039 = $0a9d1dc5be2e1cc2$export$93764714dfab3a46;
|
|
1405
|
+
|
|
1406
|
+
|
|
1407
|
+
|
|
1408
|
+
|
|
381
1409
|
/**
|
|
382
1410
|
* Copyright (c) 2024, Daily.
|
|
383
1411
|
*
|
|
@@ -612,6 +1640,7 @@ const $9bd3e7d3a9d7acd1$export$642bc4d2d2a376f1 = ()=>{
|
|
|
612
1640
|
|
|
613
1641
|
|
|
614
1642
|
|
|
1643
|
+
|
|
615
1644
|
/**
|
|
616
1645
|
* Copyright (c) 2024, Daily.
|
|
617
1646
|
*
|
|
@@ -804,4 +1833,125 @@ $a1dfa75b13e6bb9b$export$59bf27bd43679db6.displayName = "VoiceVisualizer";
|
|
|
804
1833
|
|
|
805
1834
|
|
|
806
1835
|
|
|
1836
|
+
/**
|
|
1837
|
+
* Copyright (c) 2024, Daily.
|
|
1838
|
+
*
|
|
1839
|
+
* SPDX-License-Identifier: BSD-2-Clause
|
|
1840
|
+
*/
|
|
1841
|
+
|
|
1842
|
+
|
|
1843
|
+
|
|
1844
|
+
|
|
1845
|
+
|
|
1846
|
+
const $fe6dfdd0b8560c78$export$acb832b064cb6c09 = ({ onMessageCreated: onMessageCreated, onMessageUpdated: onMessageUpdated, onMessageAdded: onMessageAdded, aggregationMetadata: aggregationMetadata } = {})=>{
|
|
1847
|
+
const { injectMessage: injectMessage } = (0, $984246ab4e966dee$export$8eec679bf8249822)();
|
|
1848
|
+
// Generate a unique ID for this hook instance
|
|
1849
|
+
const callbackId = (0, $5Zyvw$react.useId)();
|
|
1850
|
+
// Resolve deprecated onMessageAdded → onMessageCreated
|
|
1851
|
+
const resolvedCreated = onMessageCreated ?? onMessageAdded;
|
|
1852
|
+
// Register and unregister the callbacks
|
|
1853
|
+
const doRegister = (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set)=>{
|
|
1854
|
+
(0, $cbb62fb16c5d45ff$export$f2820c5e040afe17)(get, set, callbackId, {
|
|
1855
|
+
onMessageCreated: resolvedCreated,
|
|
1856
|
+
onMessageUpdated: onMessageUpdated
|
|
1857
|
+
});
|
|
1858
|
+
}, [
|
|
1859
|
+
callbackId,
|
|
1860
|
+
resolvedCreated,
|
|
1861
|
+
onMessageUpdated
|
|
1862
|
+
]));
|
|
1863
|
+
const doUnregister = (0, $5Zyvw$jotaiutils.useAtomCallback)((0, $5Zyvw$react.useCallback)((get, set)=>{
|
|
1864
|
+
(0, $cbb62fb16c5d45ff$export$46ae1ba121fdc956)(get, set, callbackId);
|
|
1865
|
+
}, [
|
|
1866
|
+
callbackId
|
|
1867
|
+
]));
|
|
1868
|
+
(0, $5Zyvw$react.useEffect)(()=>{
|
|
1869
|
+
doRegister();
|
|
1870
|
+
return ()=>{
|
|
1871
|
+
doUnregister();
|
|
1872
|
+
};
|
|
1873
|
+
}, [
|
|
1874
|
+
doRegister,
|
|
1875
|
+
doUnregister
|
|
1876
|
+
]);
|
|
1877
|
+
// Get the raw state from atoms
|
|
1878
|
+
const messages = (0, $5Zyvw$jotai.useAtomValue)((0, $28e6b30207a0392e$export$92a4076839a978d0));
|
|
1879
|
+
const botOutputMessageState = (0, $5Zyvw$jotai.useAtomValue)((0, $28e6b30207a0392e$export$bd01e11bc95333a1));
|
|
1880
|
+
// Memoize the filtered messages to prevent infinite loops
|
|
1881
|
+
const filteredMessages = (0, $5Zyvw$react.useMemo)(()=>{
|
|
1882
|
+
const getMetadata = (part)=>{
|
|
1883
|
+
return part.aggregatedBy ? aggregationMetadata?.[part.aggregatedBy] : undefined;
|
|
1884
|
+
};
|
|
1885
|
+
// Process messages: convert string parts to BotOutputText based on position state
|
|
1886
|
+
const processedMessages = messages.map((message)=>{
|
|
1887
|
+
if (message.role === "assistant") {
|
|
1888
|
+
const messageId = message.createdAt;
|
|
1889
|
+
const messageState = botOutputMessageState.get(messageId);
|
|
1890
|
+
if (!messageState) // No state yet, return message as-is
|
|
1891
|
+
return message;
|
|
1892
|
+
const parts = message.parts || [];
|
|
1893
|
+
// Find the actual current part index (skip parts that aren't meant to be spoken)
|
|
1894
|
+
let actualCurrentPartIndex = messageState.currentPartIndex;
|
|
1895
|
+
while(actualCurrentPartIndex < parts.length){
|
|
1896
|
+
const part = parts[actualCurrentPartIndex];
|
|
1897
|
+
if (typeof part?.text !== "string") break;
|
|
1898
|
+
const isSpoken = getMetadata(part)?.isSpoken !== false;
|
|
1899
|
+
if (isSpoken) break;
|
|
1900
|
+
actualCurrentPartIndex++;
|
|
1901
|
+
}
|
|
1902
|
+
if (parts.length > 0 && actualCurrentPartIndex >= parts.length) actualCurrentPartIndex = parts.length - 1;
|
|
1903
|
+
// Convert parts to BotOutputText format based on position state
|
|
1904
|
+
const processedParts = parts.map((part, partIndex)=>{
|
|
1905
|
+
// If part text is not a string, it's already processed (e.g., ReactNode)
|
|
1906
|
+
if (typeof part.text !== "string") return part;
|
|
1907
|
+
const metadata = getMetadata(part);
|
|
1908
|
+
const displayMode = part.displayMode ?? metadata?.displayMode ?? "inline";
|
|
1909
|
+
const isSpoken = metadata?.isSpoken !== false;
|
|
1910
|
+
const partText = displayMode === "block" && !isSpoken ? part.text.trim() : part.text;
|
|
1911
|
+
if (!isSpoken) return {
|
|
1912
|
+
...part,
|
|
1913
|
+
displayMode: displayMode,
|
|
1914
|
+
text: {
|
|
1915
|
+
spoken: "",
|
|
1916
|
+
unspoken: partText
|
|
1917
|
+
}
|
|
1918
|
+
};
|
|
1919
|
+
// Use cursor split for the part at actualCurrentPartIndex for every message,
|
|
1920
|
+
// so previous (e.g. interrupted) messages keep partially spoken state.
|
|
1921
|
+
const isPartAtCursor = partIndex === actualCurrentPartIndex;
|
|
1922
|
+
const currentCharIndex = messageState.currentCharIndex;
|
|
1923
|
+
const spokenText = isPartAtCursor ? partText.slice(0, currentCharIndex) : partIndex < actualCurrentPartIndex ? partText : "";
|
|
1924
|
+
const unspokenText = isPartAtCursor ? partText.slice(currentCharIndex) : partIndex < actualCurrentPartIndex ? "" : partText;
|
|
1925
|
+
return {
|
|
1926
|
+
...part,
|
|
1927
|
+
displayMode: displayMode,
|
|
1928
|
+
text: {
|
|
1929
|
+
spoken: spokenText,
|
|
1930
|
+
unspoken: unspokenText
|
|
1931
|
+
}
|
|
1932
|
+
};
|
|
1933
|
+
});
|
|
1934
|
+
return {
|
|
1935
|
+
...message,
|
|
1936
|
+
parts: processedParts
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
return message;
|
|
1940
|
+
});
|
|
1941
|
+
// Messages are already normalized (sorted, filtered, deduped, merged) on write.
|
|
1942
|
+
return processedMessages;
|
|
1943
|
+
}, [
|
|
1944
|
+
messages,
|
|
1945
|
+
botOutputMessageState,
|
|
1946
|
+
aggregationMetadata
|
|
1947
|
+
]);
|
|
1948
|
+
return {
|
|
1949
|
+
messages: filteredMessages,
|
|
1950
|
+
injectMessage: injectMessage
|
|
1951
|
+
};
|
|
1952
|
+
};
|
|
1953
|
+
|
|
1954
|
+
|
|
1955
|
+
|
|
1956
|
+
|
|
807
1957
|
//# sourceMappingURL=index.js.map
|