@modelnex/sdk 0.5.44 → 0.5.45
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/{aom-LJNCLNXL.mjs → aom-SP2LMWQI.mjs} +1 -1
- package/dist/chunk-SXGINP3O.mjs +683 -0
- package/dist/index.js +755 -673
- package/dist/index.mjs +400 -772
- package/package.json +1 -1
- package/dist/chunk-H4LUY7LI.mjs +0 -243
package/dist/index.mjs
CHANGED
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
import {
|
|
2
2
|
collectEditableControls,
|
|
3
|
+
emitSdkDebugLog,
|
|
4
|
+
extractInteractiveElements,
|
|
3
5
|
findEditableControlInShadowRoot,
|
|
6
|
+
generateFingerprint,
|
|
4
7
|
generateMinifiedAOM,
|
|
5
8
|
isEditableControlDisabled,
|
|
9
|
+
isSdkDebugEnabled,
|
|
6
10
|
isValueBearingElement,
|
|
7
11
|
readEditableControlName,
|
|
8
12
|
readEditableControlPlaceholder,
|
|
9
13
|
readEditableControlType,
|
|
10
14
|
readEditableControlValue,
|
|
11
|
-
resolveEditableControlElement
|
|
12
|
-
|
|
15
|
+
resolveEditableControlElement,
|
|
16
|
+
sanitizeAgentDebug,
|
|
17
|
+
sanitizeChatMessages,
|
|
18
|
+
useAutoExtract
|
|
19
|
+
} from "./chunk-SXGINP3O.mjs";
|
|
13
20
|
|
|
14
21
|
// src/index.ts
|
|
15
|
-
import React8, { useState as
|
|
22
|
+
import React8, { useState as useState14, useCallback as useCallback13, useEffect as useEffect18, useMemo as useMemo5 } from "react";
|
|
16
23
|
|
|
17
24
|
// src/context.ts
|
|
18
25
|
import { createContext } from "react";
|
|
19
26
|
var ModelNexContext = createContext(null);
|
|
20
27
|
|
|
21
28
|
// src/hooks/useModelNexSocket.ts
|
|
22
|
-
import { useEffect as
|
|
29
|
+
import { useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
23
30
|
import { io } from "socket.io-client";
|
|
24
31
|
|
|
25
32
|
// src/utils/socket-io-transports.ts
|
|
@@ -34,390 +41,11 @@ function resolveSocketIoTransports(serverUrl, order) {
|
|
|
34
41
|
return ["websocket", "polling"];
|
|
35
42
|
}
|
|
36
43
|
|
|
37
|
-
// src/auto-extract.ts
|
|
38
|
-
import { useState, useEffect as useEffect2, useRef as useRef2, useCallback as useCallback2 } from "react";
|
|
39
|
-
|
|
40
|
-
// src/utils/dev-logging.ts
|
|
41
|
-
function isSdkDebugEnabled(devMode) {
|
|
42
|
-
if (devMode) return true;
|
|
43
|
-
if (typeof window !== "undefined" && Boolean(window.MODELNEX_DEBUG)) {
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
return process.env.NODE_ENV === "development";
|
|
47
|
-
}
|
|
48
|
-
function emitSdkDebugLog(message, payload, options) {
|
|
49
|
-
if (!isSdkDebugEnabled(options?.devMode)) return;
|
|
50
|
-
if (payload && Object.keys(payload).length > 0) {
|
|
51
|
-
console.log(message, payload);
|
|
52
|
-
} else {
|
|
53
|
-
console.log(message);
|
|
54
|
-
}
|
|
55
|
-
if (options?.dispatchEvent && typeof window !== "undefined") {
|
|
56
|
-
window.dispatchEvent(new CustomEvent("modelnex-debug", { detail: { msg: message, data: payload } }));
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
function sanitizeActionList(actions) {
|
|
60
|
-
if (!Array.isArray(actions) || actions.length === 0) return void 0;
|
|
61
|
-
return actions.map(({ actionId }) => ({ actionId }));
|
|
62
|
-
}
|
|
63
|
-
function sanitizeAgentDebug(debug) {
|
|
64
|
-
if (!debug) return void 0;
|
|
65
|
-
const actions = sanitizeActionList(debug.actions);
|
|
66
|
-
const traces = Array.isArray(debug.traces) && debug.traces.length > 0 ? debug.traces.map((trace) => ({
|
|
67
|
-
step: trace.step,
|
|
68
|
-
actions: sanitizeActionList(trace.actions) ?? [],
|
|
69
|
-
results: Array.isArray(trace.results) && trace.results.length > 0 ? trace.results.map(({ actionId, success }) => ({ actionId, success })) : void 0
|
|
70
|
-
})) : void 0;
|
|
71
|
-
if ((!actions || actions.length === 0) && (!traces || traces.length === 0)) {
|
|
72
|
-
return void 0;
|
|
73
|
-
}
|
|
74
|
-
return {
|
|
75
|
-
...actions ? { actions } : {},
|
|
76
|
-
...traces ? { traces } : {}
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
function sanitizeChatMessages(messages, devMode) {
|
|
80
|
-
const includeDebug = isSdkDebugEnabled(devMode);
|
|
81
|
-
return messages.map((message) => {
|
|
82
|
-
if (message.role !== "assistant") {
|
|
83
|
-
return message;
|
|
84
|
-
}
|
|
85
|
-
return {
|
|
86
|
-
...message,
|
|
87
|
-
debug: includeDebug ? sanitizeAgentDebug(message.debug) : void 0
|
|
88
|
-
};
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// src/auto-extract.ts
|
|
93
|
-
function simpleHash(str) {
|
|
94
|
-
let hash = 0;
|
|
95
|
-
for (let i = 0; i < str.length; i++) {
|
|
96
|
-
const char = str.charCodeAt(i);
|
|
97
|
-
hash = (hash << 5) - hash + char;
|
|
98
|
-
hash |= 0;
|
|
99
|
-
}
|
|
100
|
-
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
101
|
-
}
|
|
102
|
-
function isStableDomId(id) {
|
|
103
|
-
if (!id) return false;
|
|
104
|
-
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
105
|
-
const REACT_USE_ID_RE = /^(?:radix-)?:[rR][^\s]*$/;
|
|
106
|
-
if (REACT_USE_ID_RE.test(id)) return false;
|
|
107
|
-
if (/^\d+$/.test(id)) return false;
|
|
108
|
-
if (UUID_RE.test(id)) return false;
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
function getNearestHeading(el) {
|
|
112
|
-
const shellContainer = el.closest('nav, aside, header, [role="navigation"], [role="complementary"], [role="banner"]');
|
|
113
|
-
const boundary = shellContainer || document.body;
|
|
114
|
-
let current = el;
|
|
115
|
-
while (current && current !== boundary) {
|
|
116
|
-
let sibling = current.previousElementSibling;
|
|
117
|
-
while (sibling) {
|
|
118
|
-
if (/^H[1-6]$/.test(sibling.tagName)) {
|
|
119
|
-
return sibling.textContent?.trim().slice(0, 100) || null;
|
|
120
|
-
}
|
|
121
|
-
const innerHeading = sibling.querySelector("h1, h2, h3, h4, h5, h6");
|
|
122
|
-
if (innerHeading) {
|
|
123
|
-
return innerHeading.textContent?.trim().slice(0, 100) || null;
|
|
124
|
-
}
|
|
125
|
-
sibling = sibling.previousElementSibling;
|
|
126
|
-
}
|
|
127
|
-
const parentHeading = current.parentElement?.querySelector("h1, h2, h3, h4, h5, h6");
|
|
128
|
-
if (parentHeading && !current.contains(parentHeading)) {
|
|
129
|
-
return parentHeading.textContent?.trim().slice(0, 100) || null;
|
|
130
|
-
}
|
|
131
|
-
current = current.parentElement;
|
|
132
|
-
}
|
|
133
|
-
return null;
|
|
134
|
-
}
|
|
135
|
-
function getParentContainer(el) {
|
|
136
|
-
let current = el.parentElement;
|
|
137
|
-
while (current && current !== document.body) {
|
|
138
|
-
const role = current.getAttribute("role");
|
|
139
|
-
const tag = current.tagName.toLowerCase();
|
|
140
|
-
const state = current.getAttribute("data-state");
|
|
141
|
-
if (role === "dialog" || role === "alertdialog" || tag === "dialog") {
|
|
142
|
-
const title = current.querySelector('h2, h3, [class*="title"]');
|
|
143
|
-
const titleText = title?.textContent?.trim().slice(0, 60) || "";
|
|
144
|
-
return titleText ? `dialog:${titleText}` : "dialog";
|
|
145
|
-
}
|
|
146
|
-
if (role === "menu" || role === "listbox") {
|
|
147
|
-
return role;
|
|
148
|
-
}
|
|
149
|
-
if (current.hasAttribute("popover") || state === "open" && current.getAttribute("data-radix-popper-content-wrapper") !== null) {
|
|
150
|
-
return "popover";
|
|
151
|
-
}
|
|
152
|
-
if (current.getAttribute("data-radix-menu-content") !== null || role === "menubar") {
|
|
153
|
-
return "dropdown-menu";
|
|
154
|
-
}
|
|
155
|
-
if (role === "tabpanel") {
|
|
156
|
-
const label = current.getAttribute("aria-label") || current.getAttribute("aria-labelledby");
|
|
157
|
-
return label ? `tabpanel:${label.slice(0, 40)}` : "tabpanel";
|
|
158
|
-
}
|
|
159
|
-
if (tag === "nav" || role === "navigation") {
|
|
160
|
-
const label = current.getAttribute("aria-label");
|
|
161
|
-
return label ? `navigation:${label.slice(0, 40)}` : "navigation";
|
|
162
|
-
}
|
|
163
|
-
if (tag === "aside") {
|
|
164
|
-
return "sidebar";
|
|
165
|
-
}
|
|
166
|
-
if (tag === "header") {
|
|
167
|
-
return "header";
|
|
168
|
-
}
|
|
169
|
-
current = current.parentElement;
|
|
170
|
-
}
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
173
|
-
function getRowContext(el) {
|
|
174
|
-
let current = el.parentElement;
|
|
175
|
-
while (current && current !== document.body) {
|
|
176
|
-
const tag = current.tagName.toLowerCase();
|
|
177
|
-
if (tag === "tr" || tag === "li" || current.getAttribute("role") === "row" || current.getAttribute("role") === "listitem") {
|
|
178
|
-
const rowText = current.textContent?.trim().replace(/\s+/g, " ").slice(0, 120) || "";
|
|
179
|
-
return rowText;
|
|
180
|
-
}
|
|
181
|
-
current = current.parentElement;
|
|
182
|
-
}
|
|
183
|
-
return "";
|
|
184
|
-
}
|
|
185
|
-
function getNearestAncestorId(el) {
|
|
186
|
-
let current = el.parentElement;
|
|
187
|
-
while (current && current !== document.body) {
|
|
188
|
-
const aid = current.id;
|
|
189
|
-
if (isStableDomId(aid)) {
|
|
190
|
-
return aid;
|
|
191
|
-
}
|
|
192
|
-
const ancestorTestId = current.getAttribute("data-testid");
|
|
193
|
-
if (ancestorTestId) return `[data-testid="${ancestorTestId}"]`;
|
|
194
|
-
current = current.parentElement;
|
|
195
|
-
}
|
|
196
|
-
return null;
|
|
197
|
-
}
|
|
198
|
-
function generateFingerprint(el) {
|
|
199
|
-
const tag = el.tagName.toLowerCase();
|
|
200
|
-
const testId = el.getAttribute("data-testid");
|
|
201
|
-
const id = el.id;
|
|
202
|
-
const name = el.getAttribute("name");
|
|
203
|
-
const ariaLabel = el.getAttribute("aria-label");
|
|
204
|
-
const type = el.type || "";
|
|
205
|
-
const text = el.textContent?.trim().slice(0, 80) || "";
|
|
206
|
-
if (testId) return `tid:${testId}`;
|
|
207
|
-
if (isStableDomId(id)) return `id:${id}`;
|
|
208
|
-
if (name) return `name:${tag}:${name}`;
|
|
209
|
-
if (ariaLabel) {
|
|
210
|
-
const rowCtx2 = getRowContext(el);
|
|
211
|
-
if (rowCtx2) {
|
|
212
|
-
return `aria:${simpleHash(ariaLabel + ":" + rowCtx2)}:${ariaLabel.slice(0, 40)}`;
|
|
213
|
-
}
|
|
214
|
-
return `aria:${simpleHash(ariaLabel)}:${ariaLabel.slice(0, 40)}`;
|
|
215
|
-
}
|
|
216
|
-
if (tag === "a") {
|
|
217
|
-
const href = el.getAttribute("href");
|
|
218
|
-
if (href && href !== "#" && !href.startsWith("javascript:")) {
|
|
219
|
-
return `href:${simpleHash(href + ":" + text)}:${text.slice(0, 30) || href.slice(0, 30)}`;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
const ancestorId = getNearestAncestorId(el);
|
|
223
|
-
if (ancestorId) {
|
|
224
|
-
return `anc:${simpleHash(ancestorId + ":" + tag + ":" + text)}:${text.slice(0, 30) || tag}`;
|
|
225
|
-
}
|
|
226
|
-
const heading = getNearestHeading(el) || "";
|
|
227
|
-
const rowCtx = getRowContext(el);
|
|
228
|
-
const raw = `${tag}:${type}:${text}:${heading}:${rowCtx}`;
|
|
229
|
-
return `hash:${simpleHash(raw)}:${text.slice(0, 30) || tag}`;
|
|
230
|
-
}
|
|
231
|
-
function classifyRole(el) {
|
|
232
|
-
const tag = el.tagName.toLowerCase();
|
|
233
|
-
const role = el.getAttribute("role");
|
|
234
|
-
if (tag === "button" || role === "button") return "button";
|
|
235
|
-
if (tag === "a") return "link";
|
|
236
|
-
if (tag === "input") return "input";
|
|
237
|
-
if (tag === "textarea") return "textarea";
|
|
238
|
-
if (tag === "select") return "select";
|
|
239
|
-
if (tag === "form") return "form";
|
|
240
|
-
if (tag === "label") return "label";
|
|
241
|
-
if (role === "link") return "link";
|
|
242
|
-
if (role === "menuitem") return "menuitem";
|
|
243
|
-
if (role === "menuitemcheckbox") return "menuitem";
|
|
244
|
-
if (role === "menuitemradio") return "menuitem";
|
|
245
|
-
if (role === "tab") return "tab";
|
|
246
|
-
if (role === "checkbox") return "checkbox";
|
|
247
|
-
if (role === "radio") return "radio";
|
|
248
|
-
if (role === "switch") return "switch";
|
|
249
|
-
if (role === "slider") return "slider";
|
|
250
|
-
if (role === "combobox") return "combobox";
|
|
251
|
-
if (role === "option") return "option";
|
|
252
|
-
if (role === "treeitem") return "treeitem";
|
|
253
|
-
if (role === "gridcell") return "gridcell";
|
|
254
|
-
if (el.hasAttribute("tabindex") && el.getAttribute("tabindex") !== "-1") return "interactive";
|
|
255
|
-
if (el.hasAttribute("cmdk-item")) return "menuitem";
|
|
256
|
-
return null;
|
|
257
|
-
}
|
|
258
|
-
var INTERACTIVE_SELECTOR = [
|
|
259
|
-
"button",
|
|
260
|
-
"a",
|
|
261
|
-
// All anchor tags (SPA links may not have href)
|
|
262
|
-
'input:not([type="hidden"])',
|
|
263
|
-
"textarea",
|
|
264
|
-
"select",
|
|
265
|
-
"label[for]",
|
|
266
|
-
'[role="button"]',
|
|
267
|
-
'[role="link"]',
|
|
268
|
-
'[role="menuitem"]',
|
|
269
|
-
'[role="menuitemcheckbox"]',
|
|
270
|
-
'[role="menuitemradio"]',
|
|
271
|
-
'[role="tab"]',
|
|
272
|
-
'[role="checkbox"]',
|
|
273
|
-
'[role="radio"]',
|
|
274
|
-
'[role="switch"]',
|
|
275
|
-
'[role="slider"]',
|
|
276
|
-
'[role="combobox"]',
|
|
277
|
-
'[role="option"]',
|
|
278
|
-
'[role="treeitem"]',
|
|
279
|
-
'[role="gridcell"]',
|
|
280
|
-
'[tabindex]:not([tabindex="-1"])',
|
|
281
|
-
"[data-discover]",
|
|
282
|
-
// React Router links
|
|
283
|
-
"[cmdk-item]",
|
|
284
|
-
// cmdk menu items
|
|
285
|
-
"form"
|
|
286
|
-
].join(", ");
|
|
287
|
-
function isVisible(el) {
|
|
288
|
-
if (el.offsetParent === null) {
|
|
289
|
-
const computed = window.getComputedStyle(el);
|
|
290
|
-
if (computed.position !== "fixed" && computed.position !== "sticky") {
|
|
291
|
-
if (computed.display === "none" || computed.visibility === "hidden") {
|
|
292
|
-
return false;
|
|
293
|
-
}
|
|
294
|
-
const rect2 = el.getBoundingClientRect();
|
|
295
|
-
if (rect2.width === 0 && rect2.height === 0) return false;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
const style = window.getComputedStyle(el);
|
|
299
|
-
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") {
|
|
300
|
-
return false;
|
|
301
|
-
}
|
|
302
|
-
const rect = el.getBoundingClientRect();
|
|
303
|
-
return rect.width > 0 && rect.height > 0;
|
|
304
|
-
}
|
|
305
|
-
function extractInteractiveElements() {
|
|
306
|
-
const elements = [];
|
|
307
|
-
const seen = /* @__PURE__ */ new Set();
|
|
308
|
-
try {
|
|
309
|
-
const nodes = document.querySelectorAll(INTERACTIVE_SELECTOR);
|
|
310
|
-
nodes.forEach((node) => {
|
|
311
|
-
const el = node;
|
|
312
|
-
if (!isVisible(el)) return;
|
|
313
|
-
if (el.closest(".modelnex-chat-panel, .modelnex-studio-overlay, [data-modelnex-internal]")) return;
|
|
314
|
-
const role = classifyRole(el);
|
|
315
|
-
if (!role) return;
|
|
316
|
-
let fingerprint = generateFingerprint(el);
|
|
317
|
-
if (seen.has(fingerprint)) {
|
|
318
|
-
let idx = 2;
|
|
319
|
-
while (seen.has(`${fingerprint}#${idx}`)) idx++;
|
|
320
|
-
fingerprint = `${fingerprint}#${idx}`;
|
|
321
|
-
}
|
|
322
|
-
seen.add(fingerprint);
|
|
323
|
-
const rect = el.getBoundingClientRect();
|
|
324
|
-
const text = el.textContent?.trim().slice(0, 200) || "";
|
|
325
|
-
elements.push({
|
|
326
|
-
fingerprint,
|
|
327
|
-
tagName: el.tagName.toLowerCase(),
|
|
328
|
-
text,
|
|
329
|
-
role,
|
|
330
|
-
rect: {
|
|
331
|
-
top: rect.top,
|
|
332
|
-
left: rect.left,
|
|
333
|
-
width: rect.width,
|
|
334
|
-
height: rect.height
|
|
335
|
-
},
|
|
336
|
-
attributes: {
|
|
337
|
-
id: el.id || void 0,
|
|
338
|
-
name: el.getAttribute("name") || void 0,
|
|
339
|
-
type: el.type || void 0,
|
|
340
|
-
ariaLabel: el.getAttribute("aria-label") || void 0,
|
|
341
|
-
dataTestId: el.getAttribute("data-testid") || void 0,
|
|
342
|
-
href: el.href || void 0,
|
|
343
|
-
placeholder: el.placeholder || void 0
|
|
344
|
-
},
|
|
345
|
-
nearestHeading: getNearestHeading(el),
|
|
346
|
-
parentContainer: getParentContainer(el),
|
|
347
|
-
disabled: el.disabled || el.getAttribute("aria-disabled") === "true",
|
|
348
|
-
element: el
|
|
349
|
-
});
|
|
350
|
-
});
|
|
351
|
-
} catch (err) {
|
|
352
|
-
console.warn("[ModelNex] Auto-extraction error:", err);
|
|
353
|
-
}
|
|
354
|
-
return elements;
|
|
355
|
-
}
|
|
356
|
-
function useAutoExtract(devMode) {
|
|
357
|
-
const [elements, setElements] = useState([]);
|
|
358
|
-
const timerRef = useRef2(null);
|
|
359
|
-
const lastSnapshotRef = useRef2("");
|
|
360
|
-
const scan = useCallback2(() => {
|
|
361
|
-
if (typeof document === "undefined") return;
|
|
362
|
-
const extracted = extractInteractiveElements();
|
|
363
|
-
const snapshot = JSON.stringify(extracted.map((e) => ({
|
|
364
|
-
fingerprint: e.fingerprint,
|
|
365
|
-
role: e.role,
|
|
366
|
-
text: e.text,
|
|
367
|
-
rect: e.rect,
|
|
368
|
-
disabled: e.disabled,
|
|
369
|
-
nearestHeading: e.nearestHeading,
|
|
370
|
-
parentContainer: e.parentContainer
|
|
371
|
-
})));
|
|
372
|
-
if (snapshot === lastSnapshotRef.current) return;
|
|
373
|
-
lastSnapshotRef.current = snapshot;
|
|
374
|
-
emitSdkDebugLog("[ModelNex AutoExtract] Scan complete", {
|
|
375
|
-
elementCount: extracted.length
|
|
376
|
-
}, { devMode });
|
|
377
|
-
setElements(extracted);
|
|
378
|
-
}, [devMode]);
|
|
379
|
-
useEffect2(() => {
|
|
380
|
-
const initialTimer = setTimeout(scan, 300);
|
|
381
|
-
const observer = new MutationObserver((mutations) => {
|
|
382
|
-
const hasRelevantMutation = mutations.some((mutation) => {
|
|
383
|
-
const target = mutation.target;
|
|
384
|
-
if (target?.closest?.(".modelnex-chat-panel, .modelnex-studio-overlay, [data-modelnex-internal]")) {
|
|
385
|
-
return false;
|
|
386
|
-
}
|
|
387
|
-
return true;
|
|
388
|
-
});
|
|
389
|
-
if (!hasRelevantMutation) return;
|
|
390
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
391
|
-
timerRef.current = setTimeout(scan, 500);
|
|
392
|
-
});
|
|
393
|
-
observer.observe(document.body, {
|
|
394
|
-
childList: true,
|
|
395
|
-
subtree: true,
|
|
396
|
-
attributes: true,
|
|
397
|
-
attributeFilter: ["disabled", "aria-disabled", "hidden", "style", "class"]
|
|
398
|
-
});
|
|
399
|
-
const handlePositionChange = () => {
|
|
400
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
401
|
-
timerRef.current = setTimeout(scan, 200);
|
|
402
|
-
};
|
|
403
|
-
window.addEventListener("scroll", handlePositionChange, { passive: true });
|
|
404
|
-
window.addEventListener("resize", handlePositionChange, { passive: true });
|
|
405
|
-
return () => {
|
|
406
|
-
clearTimeout(initialTimer);
|
|
407
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
408
|
-
observer.disconnect();
|
|
409
|
-
window.removeEventListener("scroll", handlePositionChange);
|
|
410
|
-
window.removeEventListener("resize", handlePositionChange);
|
|
411
|
-
};
|
|
412
|
-
}, [scan]);
|
|
413
|
-
return elements;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
44
|
// src/utils/dom-summary.ts
|
|
417
45
|
function textOf(el) {
|
|
418
46
|
return el?.textContent?.trim().slice(0, 200) ?? "";
|
|
419
47
|
}
|
|
420
|
-
function
|
|
48
|
+
function isVisible(el) {
|
|
421
49
|
const htmlEl = el;
|
|
422
50
|
const style = window.getComputedStyle(htmlEl);
|
|
423
51
|
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") {
|
|
@@ -488,7 +116,7 @@ function captureDomSummary(tags) {
|
|
|
488
116
|
const alerts = safeQueryAll('[role="alert"], [role="status"]').map(textOf).filter(Boolean);
|
|
489
117
|
const allButtons = safeQueryAll('button, [role="button"], a[class*="btn"], a[class*="Button"], a');
|
|
490
118
|
const disabledButtons = allButtons.filter((b) => b.disabled || b.getAttribute("aria-disabled") === "true").map((b) => ({ text: textOf(b), fingerprint: generateFingerprint(b) })).filter((o) => !!o.text);
|
|
491
|
-
const enabledButtons = allButtons.filter((b) => !b.disabled && b.getAttribute("aria-disabled") !== "true").filter((b) =>
|
|
119
|
+
const enabledButtons = allButtons.filter((b) => !b.disabled && b.getAttribute("aria-disabled") !== "true").filter((b) => isVisible(b)).map((b) => ({ text: textOf(b), fingerprint: generateFingerprint(b) })).filter((o) => !!o.text).slice(0, 40);
|
|
492
120
|
const visibleDialogs = safeQueryAll('[role="dialog"], [data-state="open"], dialog[open]').map((d) => {
|
|
493
121
|
const title = d.querySelector('h2, h3, [class*="title"]');
|
|
494
122
|
return title ? textOf(title) : textOf(d).slice(0, 100);
|
|
@@ -692,16 +320,16 @@ function useModelNexSocket({
|
|
|
692
320
|
websiteId,
|
|
693
321
|
devMode
|
|
694
322
|
}) {
|
|
695
|
-
const socketRef =
|
|
696
|
-
const actionsRef =
|
|
697
|
-
const contextsRef =
|
|
698
|
-
const documentationRef =
|
|
699
|
-
const tagsRef =
|
|
323
|
+
const socketRef = useRef2(null);
|
|
324
|
+
const actionsRef = useRef2(actions);
|
|
325
|
+
const contextsRef = useRef2(contexts);
|
|
326
|
+
const documentationRef = useRef2(documentation);
|
|
327
|
+
const tagsRef = useRef2(tags);
|
|
700
328
|
actionsRef.current = actions;
|
|
701
329
|
contextsRef.current = contexts;
|
|
702
330
|
documentationRef.current = documentation;
|
|
703
331
|
tagsRef.current = tags;
|
|
704
|
-
|
|
332
|
+
useEffect2(() => {
|
|
705
333
|
if (disabled) {
|
|
706
334
|
socketRef.current = null;
|
|
707
335
|
onSocketId?.(null);
|
|
@@ -834,7 +462,7 @@ function useModelNexSocket({
|
|
|
834
462
|
socket.disconnect();
|
|
835
463
|
};
|
|
836
464
|
}, [disabled, onSocketId, serverUrl]);
|
|
837
|
-
|
|
465
|
+
useEffect2(() => {
|
|
838
466
|
if (disabled) {
|
|
839
467
|
return;
|
|
840
468
|
}
|
|
@@ -852,10 +480,10 @@ function useModelNexSocket({
|
|
|
852
480
|
}
|
|
853
481
|
|
|
854
482
|
// src/hooks/useFieldHighlight.ts
|
|
855
|
-
import { useEffect as
|
|
483
|
+
import { useEffect as useEffect3, useRef as useRef3 } from "react";
|
|
856
484
|
function useFieldHighlight(stagingFields, executedFields, setExecutedFields) {
|
|
857
|
-
const highlightedRef =
|
|
858
|
-
|
|
485
|
+
const highlightedRef = useRef3(/* @__PURE__ */ new Map());
|
|
486
|
+
useEffect3(() => {
|
|
859
487
|
const prev = highlightedRef.current;
|
|
860
488
|
prev.forEach((_, fieldId) => {
|
|
861
489
|
if (!stagingFields.has(fieldId)) {
|
|
@@ -874,7 +502,7 @@ function useFieldHighlight(stagingFields, executedFields, setExecutedFields) {
|
|
|
874
502
|
prev.clear();
|
|
875
503
|
};
|
|
876
504
|
}, [stagingFields]);
|
|
877
|
-
|
|
505
|
+
useEffect3(() => {
|
|
878
506
|
const timeouts = [];
|
|
879
507
|
executedFields.forEach((fieldId) => {
|
|
880
508
|
const els = document.querySelectorAll(`[data-modelnex-field-id="${fieldId}"]`);
|
|
@@ -895,7 +523,7 @@ function useFieldHighlight(stagingFields, executedFields, setExecutedFields) {
|
|
|
895
523
|
}
|
|
896
524
|
|
|
897
525
|
// src/overlay.tsx
|
|
898
|
-
import React2, { useState
|
|
526
|
+
import React2, { useState, useEffect as useEffect4 } from "react";
|
|
899
527
|
var AIActivityOverlay = ({ activeActions }) => {
|
|
900
528
|
if (activeActions.size === 0) return null;
|
|
901
529
|
return React2.createElement(
|
|
@@ -1092,7 +720,7 @@ body.modelnex-highlight-actions [data-modelnex-action-id]::before {
|
|
|
1092
720
|
`;
|
|
1093
721
|
|
|
1094
722
|
// src/tag-store.ts
|
|
1095
|
-
import { useState as
|
|
723
|
+
import { useState as useState2, useCallback as useCallback2, useEffect as useEffect5 } from "react";
|
|
1096
724
|
var STORAGE_KEY = "modelnex-tags";
|
|
1097
725
|
function loadTags() {
|
|
1098
726
|
try {
|
|
@@ -1116,10 +744,10 @@ function saveTags(tags) {
|
|
|
1116
744
|
}
|
|
1117
745
|
}
|
|
1118
746
|
function useTagStore(options) {
|
|
1119
|
-
const [tags, setTags] =
|
|
747
|
+
const [tags, setTags] = useState2(/* @__PURE__ */ new Map());
|
|
1120
748
|
const apiUrl = options?.serverUrl ? `${options.serverUrl.replace(/\/$/, "")}/api/tags` : null;
|
|
1121
749
|
const websiteId = options?.websiteId;
|
|
1122
|
-
|
|
750
|
+
useEffect5(() => {
|
|
1123
751
|
const local = loadTags();
|
|
1124
752
|
setTags(local);
|
|
1125
753
|
if (apiUrl) {
|
|
@@ -1139,14 +767,14 @@ function useTagStore(options) {
|
|
|
1139
767
|
}).catch((err) => console.warn("[ModelNex] Failed to fetch remote tags:", err));
|
|
1140
768
|
}
|
|
1141
769
|
}, [apiUrl]);
|
|
1142
|
-
|
|
770
|
+
useEffect5(() => {
|
|
1143
771
|
if (typeof window === "undefined") return;
|
|
1144
772
|
saveTags(tags);
|
|
1145
773
|
}, [tags]);
|
|
1146
|
-
const getTag =
|
|
774
|
+
const getTag = useCallback2((fingerprint) => {
|
|
1147
775
|
return tags.get(fingerprint);
|
|
1148
776
|
}, [tags]);
|
|
1149
|
-
const setTag =
|
|
777
|
+
const setTag = useCallback2((fingerprint, description, category, metadata, selector, patternId, behavior, sourcePage, displayContext, skipRemoteSync) => {
|
|
1150
778
|
setTags((prev) => {
|
|
1151
779
|
const next = new Map(prev);
|
|
1152
780
|
const key = selector ? `selector:${selector}` : fingerprint;
|
|
@@ -1178,7 +806,7 @@ function useTagStore(options) {
|
|
|
1178
806
|
return next;
|
|
1179
807
|
});
|
|
1180
808
|
}, [apiUrl, websiteId]);
|
|
1181
|
-
const setTagsBatch =
|
|
809
|
+
const setTagsBatch = useCallback2((newTags, skipRemoteSync) => {
|
|
1182
810
|
setTags((prev) => {
|
|
1183
811
|
const next = new Map(prev);
|
|
1184
812
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1206,24 +834,24 @@ function useTagStore(options) {
|
|
|
1206
834
|
return next;
|
|
1207
835
|
});
|
|
1208
836
|
}, [apiUrl, websiteId]);
|
|
1209
|
-
const deleteTag =
|
|
837
|
+
const deleteTag = useCallback2((fingerprint) => {
|
|
1210
838
|
setTags((prev) => {
|
|
1211
839
|
const next = new Map(prev);
|
|
1212
840
|
next.delete(fingerprint);
|
|
1213
841
|
return next;
|
|
1214
842
|
});
|
|
1215
843
|
}, []);
|
|
1216
|
-
const getAllTags =
|
|
844
|
+
const getAllTags = useCallback2(() => {
|
|
1217
845
|
return Array.from(tags.values());
|
|
1218
846
|
}, [tags]);
|
|
1219
|
-
const exportTags =
|
|
847
|
+
const exportTags = useCallback2(() => {
|
|
1220
848
|
const obj = {};
|
|
1221
849
|
tags.forEach((v, k) => {
|
|
1222
850
|
obj[k] = v;
|
|
1223
851
|
});
|
|
1224
852
|
return JSON.stringify(obj, null, 2);
|
|
1225
853
|
}, [tags]);
|
|
1226
|
-
const importTags =
|
|
854
|
+
const importTags = useCallback2((json) => {
|
|
1227
855
|
try {
|
|
1228
856
|
const parsed = JSON.parse(json);
|
|
1229
857
|
setTags((prev) => {
|
|
@@ -1239,7 +867,7 @@ function useTagStore(options) {
|
|
|
1239
867
|
}
|
|
1240
868
|
|
|
1241
869
|
// src/studio-mode.tsx
|
|
1242
|
-
import { useState as
|
|
870
|
+
import { useState as useState3, useEffect as useEffect6, useRef as useRef4, useCallback as useCallback3 } from "react";
|
|
1243
871
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1244
872
|
var CATEGORIES = [
|
|
1245
873
|
{ value: "button", label: "Button" },
|
|
@@ -1250,10 +878,10 @@ var CATEGORIES = [
|
|
|
1250
878
|
{ value: "other", label: "Other" }
|
|
1251
879
|
];
|
|
1252
880
|
function TaggingPanel({ element, existingTag, onSave, onDelete, onClose }) {
|
|
1253
|
-
const [description, setDescription] =
|
|
1254
|
-
const [category, setCategory] =
|
|
1255
|
-
const inputRef =
|
|
1256
|
-
|
|
881
|
+
const [description, setDescription] = useState3(existingTag?.description ?? "");
|
|
882
|
+
const [category, setCategory] = useState3(existingTag?.category ?? "other");
|
|
883
|
+
const inputRef = useRef4(null);
|
|
884
|
+
useEffect6(() => {
|
|
1257
885
|
inputRef.current?.focus();
|
|
1258
886
|
}, []);
|
|
1259
887
|
const handleSave = () => {
|
|
@@ -1480,10 +1108,10 @@ function findTagForElement(el, tagStore) {
|
|
|
1480
1108
|
return void 0;
|
|
1481
1109
|
}
|
|
1482
1110
|
function StudioOverlay({ elements, tagStore }) {
|
|
1483
|
-
const [selectedFingerprint, setSelectedFingerprint] =
|
|
1484
|
-
const [positions, setPositions] =
|
|
1485
|
-
const liveElementsRef =
|
|
1486
|
-
const updatePositions =
|
|
1111
|
+
const [selectedFingerprint, setSelectedFingerprint] = useState3(null);
|
|
1112
|
+
const [positions, setPositions] = useState3(/* @__PURE__ */ new Map());
|
|
1113
|
+
const liveElementsRef = useRef4(/* @__PURE__ */ new Map());
|
|
1114
|
+
const updatePositions = useCallback3(() => {
|
|
1487
1115
|
const newPositions = /* @__PURE__ */ new Map();
|
|
1488
1116
|
const newLiveElements = /* @__PURE__ */ new Map();
|
|
1489
1117
|
const knownFingerprints = new Set(elements.map((e) => e.fingerprint));
|
|
@@ -1518,7 +1146,7 @@ function StudioOverlay({ elements, tagStore }) {
|
|
|
1518
1146
|
liveElementsRef.current = newLiveElements;
|
|
1519
1147
|
setPositions(newPositions);
|
|
1520
1148
|
}, [elements]);
|
|
1521
|
-
|
|
1149
|
+
useEffect6(() => {
|
|
1522
1150
|
updatePositions();
|
|
1523
1151
|
const interval = setInterval(updatePositions, 1e3);
|
|
1524
1152
|
window.addEventListener("scroll", updatePositions, { passive: true });
|
|
@@ -1662,7 +1290,7 @@ function StudioOverlay({ elements, tagStore }) {
|
|
|
1662
1290
|
}
|
|
1663
1291
|
|
|
1664
1292
|
// src/hooks/useBuiltinActions.ts
|
|
1665
|
-
import { useEffect as
|
|
1293
|
+
import { useEffect as useEffect7, useRef as useRef5 } from "react";
|
|
1666
1294
|
import { z as z2 } from "zod";
|
|
1667
1295
|
|
|
1668
1296
|
// src/utils/screenshot.ts
|
|
@@ -2514,18 +2142,18 @@ var BUILTIN_ACTION_IDS = {
|
|
|
2514
2142
|
startWorkflow: "start_workflow"
|
|
2515
2143
|
};
|
|
2516
2144
|
function useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl, websiteId, toursApiBase, userProfile) {
|
|
2517
|
-
const registeredRef =
|
|
2518
|
-
const tagStoreRef =
|
|
2145
|
+
const registeredRef = useRef5(false);
|
|
2146
|
+
const tagStoreRef = useRef5(tagStore);
|
|
2519
2147
|
tagStoreRef.current = tagStore;
|
|
2520
|
-
const serverUrlRef =
|
|
2148
|
+
const serverUrlRef = useRef5(serverUrl);
|
|
2521
2149
|
serverUrlRef.current = serverUrl;
|
|
2522
|
-
const websiteIdRef =
|
|
2150
|
+
const websiteIdRef = useRef5(websiteId);
|
|
2523
2151
|
websiteIdRef.current = websiteId;
|
|
2524
|
-
const toursApiBaseRef =
|
|
2152
|
+
const toursApiBaseRef = useRef5(toursApiBase);
|
|
2525
2153
|
toursApiBaseRef.current = toursApiBase;
|
|
2526
|
-
const userProfileRef =
|
|
2154
|
+
const userProfileRef = useRef5(userProfile);
|
|
2527
2155
|
userProfileRef.current = userProfile;
|
|
2528
|
-
|
|
2156
|
+
useEffect7(() => {
|
|
2529
2157
|
if (registeredRef.current) return;
|
|
2530
2158
|
registeredRef.current = true;
|
|
2531
2159
|
const getTagStore = () => tagStoreRef.current;
|
|
@@ -2880,7 +2508,7 @@ function readPreviewSessionSuppression() {
|
|
|
2880
2508
|
}
|
|
2881
2509
|
|
|
2882
2510
|
// src/hooks/useRunCommand.ts
|
|
2883
|
-
import { useCallback as
|
|
2511
|
+
import { useCallback as useCallback4, useContext as useContext2 } from "react";
|
|
2884
2512
|
function searchTaggedElementsForQuery(store, query, limit = 8) {
|
|
2885
2513
|
const allTags = store.getAllTags();
|
|
2886
2514
|
if (allTags.length === 0) return [];
|
|
@@ -2903,7 +2531,7 @@ function useRunCommand(serverUrlOverride) {
|
|
|
2903
2531
|
const context = useContext2(ModelNexContext);
|
|
2904
2532
|
const baseUrl = serverUrlOverride ?? context?.commandUrl ?? context?.serverUrl ?? DEFAULT_MODELNEX_SERVER_URL;
|
|
2905
2533
|
const tagStore = context?.tagStore;
|
|
2906
|
-
return
|
|
2534
|
+
return useCallback4(
|
|
2907
2535
|
async (command, signal) => {
|
|
2908
2536
|
const url = baseUrl.startsWith("/") ? `${window.location.origin}${baseUrl}/agent/command` : `${baseUrl}/agent/command`;
|
|
2909
2537
|
const relevantTaggedElements = tagStore ? searchTaggedElementsForQuery(tagStore, command) : void 0;
|
|
@@ -2931,7 +2559,7 @@ function useRunCommand(serverUrlOverride) {
|
|
|
2931
2559
|
}
|
|
2932
2560
|
|
|
2933
2561
|
// src/ui-state.tsx
|
|
2934
|
-
import { createContext as createContext2, useContext as useContext3, useState as
|
|
2562
|
+
import { createContext as createContext2, useContext as useContext3, useState as useState4, useCallback as useCallback5, useMemo as useMemo2 } from "react";
|
|
2935
2563
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
2936
2564
|
var UIStateContext = createContext2(null);
|
|
2937
2565
|
function UIStateProvider({
|
|
@@ -2940,8 +2568,8 @@ function UIStateProvider({
|
|
|
2940
2568
|
type = "ui",
|
|
2941
2569
|
initialState = {}
|
|
2942
2570
|
}) {
|
|
2943
|
-
const [state, setStateInternal] =
|
|
2944
|
-
const setState =
|
|
2571
|
+
const [state, setStateInternal] = useState4(initialState);
|
|
2572
|
+
const setState = useCallback5((update) => {
|
|
2945
2573
|
setStateInternal((prev) => ({ ...prev, ...update }));
|
|
2946
2574
|
}, []);
|
|
2947
2575
|
const value = useMemo2(() => ({ state, setState }), [state, setState]);
|
|
@@ -2954,7 +2582,7 @@ function useUIState() {
|
|
|
2954
2582
|
}
|
|
2955
2583
|
|
|
2956
2584
|
// src/viewport.ts
|
|
2957
|
-
import { useEffect as
|
|
2585
|
+
import { useEffect as useEffect9, useRef as useRef6, useState as useState5 } from "react";
|
|
2958
2586
|
var visibleIds = /* @__PURE__ */ new Set();
|
|
2959
2587
|
var listeners = /* @__PURE__ */ new Set();
|
|
2960
2588
|
function updateVisibility(id, visible) {
|
|
@@ -2963,9 +2591,9 @@ function updateVisibility(id, visible) {
|
|
|
2963
2591
|
listeners.forEach((fn) => fn());
|
|
2964
2592
|
}
|
|
2965
2593
|
function useViewportTrack(id) {
|
|
2966
|
-
const ref =
|
|
2967
|
-
const [, setTick] =
|
|
2968
|
-
|
|
2594
|
+
const ref = useRef6(null);
|
|
2595
|
+
const [, setTick] = useState5(0);
|
|
2596
|
+
useEffect9(() => {
|
|
2969
2597
|
const el = ref.current;
|
|
2970
2598
|
if (!el) return;
|
|
2971
2599
|
const obs = new IntersectionObserver(
|
|
@@ -2980,7 +2608,7 @@ function useViewportTrack(id) {
|
|
|
2980
2608
|
updateVisibility(id, false);
|
|
2981
2609
|
};
|
|
2982
2610
|
}, [id]);
|
|
2983
|
-
|
|
2611
|
+
useEffect9(() => {
|
|
2984
2612
|
const fn = () => setTick((t) => t + 1);
|
|
2985
2613
|
listeners.add(fn);
|
|
2986
2614
|
return () => {
|
|
@@ -2990,8 +2618,8 @@ function useViewportTrack(id) {
|
|
|
2990
2618
|
return ref;
|
|
2991
2619
|
}
|
|
2992
2620
|
function useVisibleIds() {
|
|
2993
|
-
const [ids, setIds] =
|
|
2994
|
-
|
|
2621
|
+
const [ids, setIds] = useState5([]);
|
|
2622
|
+
useEffect9(() => {
|
|
2995
2623
|
const fn = () => setIds(Array.from(visibleIds));
|
|
2996
2624
|
fn();
|
|
2997
2625
|
listeners.add(fn);
|
|
@@ -3008,11 +2636,11 @@ function useAgentViewport(options = {}) {
|
|
|
3008
2636
|
}
|
|
3009
2637
|
|
|
3010
2638
|
// src/chat-bubble.tsx
|
|
3011
|
-
import { useState as
|
|
2639
|
+
import { useState as useState12, useRef as useRef12, useEffect as useEffect16, useContext as useContext5, useCallback as useCallback11, useMemo as useMemo3 } from "react";
|
|
3012
2640
|
import { createPortal, flushSync } from "react-dom";
|
|
3013
2641
|
|
|
3014
2642
|
// src/hooks/useExperiencePlaybackController.ts
|
|
3015
|
-
import { useCallback as
|
|
2643
|
+
import { useCallback as useCallback7, useEffect as useEffect11, useRef as useRef8, useState as useState7 } from "react";
|
|
3016
2644
|
|
|
3017
2645
|
// src/utils/locationSignature.ts
|
|
3018
2646
|
function getLocationSignature(locationLike) {
|
|
@@ -3021,7 +2649,7 @@ function getLocationSignature(locationLike) {
|
|
|
3021
2649
|
}
|
|
3022
2650
|
|
|
3023
2651
|
// src/hooks/useTourPlayback.ts
|
|
3024
|
-
import { useState as
|
|
2652
|
+
import { useState as useState6, useRef as useRef7, useCallback as useCallback6, useEffect as useEffect10, useContext as useContext4 } from "react";
|
|
3025
2653
|
|
|
3026
2654
|
// src/utils/retryLookup.ts
|
|
3027
2655
|
var defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -3787,58 +3415,58 @@ function useTourPlayback({
|
|
|
3787
3415
|
enableAutoDiscovery = true
|
|
3788
3416
|
}) {
|
|
3789
3417
|
const locationSignature = typeof window === "undefined" ? "" : getLocationSignature(window.location);
|
|
3790
|
-
const [isActive, setIsActive] =
|
|
3791
|
-
const [currentStepIndex, setCurrentStepIndex] =
|
|
3792
|
-
const [totalSteps, setTotalSteps] =
|
|
3793
|
-
const [activeTour, setActiveTour] =
|
|
3794
|
-
const [playbackState, setPlaybackState] =
|
|
3795
|
-
const [isReviewMode, setIsReviewMode] =
|
|
3796
|
-
const [previewRunId, setPreviewRunId] =
|
|
3797
|
-
const [reviewSubmitting, setReviewSubmitting] =
|
|
3798
|
-
const [reviewStatusMessage, setReviewStatusMessage] =
|
|
3799
|
-
const [pendingTour, setPendingTour] =
|
|
3800
|
-
const [serverState, setServerState] =
|
|
3418
|
+
const [isActive, setIsActive] = useState6(false);
|
|
3419
|
+
const [currentStepIndex, setCurrentStepIndex] = useState6(0);
|
|
3420
|
+
const [totalSteps, setTotalSteps] = useState6(0);
|
|
3421
|
+
const [activeTour, setActiveTour] = useState6(null);
|
|
3422
|
+
const [playbackState, setPlaybackState] = useState6("idle");
|
|
3423
|
+
const [isReviewMode, setIsReviewMode] = useState6(false);
|
|
3424
|
+
const [previewRunId, setPreviewRunId] = useState6(null);
|
|
3425
|
+
const [reviewSubmitting, setReviewSubmitting] = useState6(false);
|
|
3426
|
+
const [reviewStatusMessage, setReviewStatusMessage] = useState6(null);
|
|
3427
|
+
const [pendingTour, setPendingTour] = useState6(null);
|
|
3428
|
+
const [serverState, setServerState] = useState6(null);
|
|
3801
3429
|
const ctx = useContext4(ModelNexContext);
|
|
3802
3430
|
const devMode = ctx?.devMode;
|
|
3803
|
-
const devModeRef =
|
|
3431
|
+
const devModeRef = useRef7(devMode);
|
|
3804
3432
|
devModeRef.current = devMode;
|
|
3805
|
-
const userProfileRef =
|
|
3433
|
+
const userProfileRef = useRef7(userProfile);
|
|
3806
3434
|
userProfileRef.current = userProfile;
|
|
3807
|
-
const experienceTypeRef =
|
|
3435
|
+
const experienceTypeRef = useRef7(experienceType);
|
|
3808
3436
|
experienceTypeRef.current = experienceType;
|
|
3809
|
-
const tourRef =
|
|
3810
|
-
const stepIndexRef =
|
|
3811
|
-
const skipRequestedRef =
|
|
3812
|
-
const advanceRequestedRef =
|
|
3813
|
-
const textInputResolveRef =
|
|
3814
|
-
const voiceInputResolveRef =
|
|
3815
|
-
const askOrFillRef =
|
|
3816
|
-
const pendingManualWaitCleanupRef =
|
|
3817
|
-
const pendingManualInputSyncRef =
|
|
3818
|
-
const llmRespondingRef =
|
|
3819
|
-
const interruptedForQuestionRef =
|
|
3820
|
-
const pendingInputBufRef =
|
|
3821
|
-
const activeExecutionTokenRef =
|
|
3822
|
-
const commandInFlightRef =
|
|
3823
|
-
const reviewModeRef =
|
|
3824
|
-
const previewRunIdRef =
|
|
3825
|
-
const toursApiBaseRef =
|
|
3826
|
-
const pendingTourRef =
|
|
3827
|
-
const pendingTourOptionsRef =
|
|
3828
|
-
const showCaptionsRef =
|
|
3829
|
-
const initialPersistedTourSessionRef =
|
|
3830
|
-
const runIdRef =
|
|
3831
|
-
const turnIdRef =
|
|
3832
|
-
const startRequestedRef =
|
|
3833
|
-
const playbackOwnerIdRef =
|
|
3834
|
-
const claimedPlaybackOwnerKeyRef =
|
|
3835
|
-
const socketRef =
|
|
3836
|
-
const socketIdRef =
|
|
3837
|
-
const commandUrlRef =
|
|
3838
|
-
const websiteIdRef =
|
|
3839
|
-
const onStepChangeRef =
|
|
3840
|
-
const isActiveRef =
|
|
3841
|
-
const activeCommandBatchIdRef =
|
|
3437
|
+
const tourRef = useRef7(null);
|
|
3438
|
+
const stepIndexRef = useRef7(0);
|
|
3439
|
+
const skipRequestedRef = useRef7(false);
|
|
3440
|
+
const advanceRequestedRef = useRef7(false);
|
|
3441
|
+
const textInputResolveRef = useRef7(null);
|
|
3442
|
+
const voiceInputResolveRef = useRef7(null);
|
|
3443
|
+
const askOrFillRef = useRef7(null);
|
|
3444
|
+
const pendingManualWaitCleanupRef = useRef7(null);
|
|
3445
|
+
const pendingManualInputSyncRef = useRef7(null);
|
|
3446
|
+
const llmRespondingRef = useRef7(false);
|
|
3447
|
+
const interruptedForQuestionRef = useRef7(false);
|
|
3448
|
+
const pendingInputBufRef = useRef7(null);
|
|
3449
|
+
const activeExecutionTokenRef = useRef7(0);
|
|
3450
|
+
const commandInFlightRef = useRef7(false);
|
|
3451
|
+
const reviewModeRef = useRef7(false);
|
|
3452
|
+
const previewRunIdRef = useRef7(null);
|
|
3453
|
+
const toursApiBaseRef = useRef7(toursApiBase);
|
|
3454
|
+
const pendingTourRef = useRef7(null);
|
|
3455
|
+
const pendingTourOptionsRef = useRef7(null);
|
|
3456
|
+
const showCaptionsRef = useRef7(showCaptions);
|
|
3457
|
+
const initialPersistedTourSessionRef = useRef7(readPersistedActiveTourSession());
|
|
3458
|
+
const runIdRef = useRef7(initialPersistedTourSessionRef.current?.runId ?? null);
|
|
3459
|
+
const turnIdRef = useRef7(null);
|
|
3460
|
+
const startRequestedRef = useRef7(false);
|
|
3461
|
+
const playbackOwnerIdRef = useRef7(`playback-owner-${Math.random().toString(36).slice(2, 10)}`);
|
|
3462
|
+
const claimedPlaybackOwnerKeyRef = useRef7(null);
|
|
3463
|
+
const socketRef = useRef7(null);
|
|
3464
|
+
const socketIdRef = useRef7(socketId);
|
|
3465
|
+
const commandUrlRef = useRef7(commandUrl);
|
|
3466
|
+
const websiteIdRef = useRef7(websiteId);
|
|
3467
|
+
const onStepChangeRef = useRef7(onStepChange);
|
|
3468
|
+
const isActiveRef = useRef7(false);
|
|
3469
|
+
const activeCommandBatchIdRef = useRef7(null);
|
|
3842
3470
|
socketIdRef.current = socketId;
|
|
3843
3471
|
commandUrlRef.current = commandUrl;
|
|
3844
3472
|
websiteIdRef.current = websiteId;
|
|
@@ -3849,13 +3477,13 @@ function useTourPlayback({
|
|
|
3849
3477
|
toursApiBaseRef.current = toursApiBase;
|
|
3850
3478
|
pendingTourRef.current = pendingTour;
|
|
3851
3479
|
showCaptionsRef.current = showCaptions;
|
|
3852
|
-
const releasePlaybackOwnership =
|
|
3480
|
+
const releasePlaybackOwnership = useCallback6(() => {
|
|
3853
3481
|
const claimedKey = claimedPlaybackOwnerKeyRef.current;
|
|
3854
3482
|
if (!claimedKey) return;
|
|
3855
3483
|
releaseTourPlaybackOwnership(claimedKey, playbackOwnerIdRef.current);
|
|
3856
3484
|
claimedPlaybackOwnerKeyRef.current = null;
|
|
3857
3485
|
}, []);
|
|
3858
|
-
const emitTourInit =
|
|
3486
|
+
const emitTourInit = useCallback6((socket, currentWebsiteId, profile) => {
|
|
3859
3487
|
if (!currentWebsiteId || !profile?.type) return;
|
|
3860
3488
|
const persistedRunId = runIdRef.current ?? readPersistedActiveTourSession()?.runId ?? null;
|
|
3861
3489
|
const payload = {
|
|
@@ -3868,7 +3496,7 @@ function useTourPlayback({
|
|
|
3868
3496
|
}
|
|
3869
3497
|
emitSocketEvent(socket, "tour:init", payload);
|
|
3870
3498
|
}, []);
|
|
3871
|
-
|
|
3499
|
+
useEffect10(() => {
|
|
3872
3500
|
if (disabled) return;
|
|
3873
3501
|
if (typeof window === "undefined") return;
|
|
3874
3502
|
const socket = tourSocketPool.acquire(serverUrl);
|
|
@@ -4017,7 +3645,7 @@ function useTourPlayback({
|
|
|
4017
3645
|
resolve: async () => {
|
|
4018
3646
|
let targetEl = null;
|
|
4019
3647
|
if (params.uid) {
|
|
4020
|
-
const { getElementByUid } = await import("./aom-
|
|
3648
|
+
const { getElementByUid } = await import("./aom-SP2LMWQI.mjs");
|
|
4021
3649
|
targetEl = getElementByUid(params.uid);
|
|
4022
3650
|
}
|
|
4023
3651
|
if (!targetEl) {
|
|
@@ -4495,7 +4123,7 @@ function useTourPlayback({
|
|
|
4495
4123
|
void recordTourEvent(serverUrl, toursApiBaseRef.current, tour.id, userProfile.userId, "started", websiteId);
|
|
4496
4124
|
}
|
|
4497
4125
|
try {
|
|
4498
|
-
const { generateMinifiedAOM: generateMinifiedAOM2 } = await import("./aom-
|
|
4126
|
+
const { generateMinifiedAOM: generateMinifiedAOM2 } = await import("./aom-SP2LMWQI.mjs");
|
|
4499
4127
|
const aom = generateMinifiedAOM2();
|
|
4500
4128
|
if (socketRef.current === socket) {
|
|
4501
4129
|
emitSocketEvent(socket, "tour:sync_dom", {
|
|
@@ -4579,7 +4207,7 @@ function useTourPlayback({
|
|
|
4579
4207
|
tourSocketPool.release(serverUrl, toClose);
|
|
4580
4208
|
};
|
|
4581
4209
|
}, [serverUrl, disabled, emitTourInit, releasePlaybackOwnership]);
|
|
4582
|
-
|
|
4210
|
+
useEffect10(() => {
|
|
4583
4211
|
if (disabled) return;
|
|
4584
4212
|
const s = socketRef.current;
|
|
4585
4213
|
const profile = userProfile;
|
|
@@ -4589,12 +4217,12 @@ function useTourPlayback({
|
|
|
4589
4217
|
}, 150);
|
|
4590
4218
|
return () => clearTimeout(timer);
|
|
4591
4219
|
}, [disabled, emitTourInit, websiteId, userProfile?.userId, userProfile?.type]);
|
|
4592
|
-
|
|
4220
|
+
useEffect10(() => {
|
|
4593
4221
|
if (!showCaptions || !isReviewMode) {
|
|
4594
4222
|
removeCaption();
|
|
4595
4223
|
}
|
|
4596
4224
|
}, [showCaptions, isReviewMode]);
|
|
4597
|
-
|
|
4225
|
+
useEffect10(() => {
|
|
4598
4226
|
if (!isActiveRef.current) return;
|
|
4599
4227
|
emitSocketEvent(socketRef.current, "tour:client_state", {
|
|
4600
4228
|
runId: runIdRef.current,
|
|
@@ -4608,9 +4236,9 @@ function useTourPlayback({
|
|
|
4608
4236
|
awaitingVoiceResolve: Boolean(voiceInputResolveRef.current)
|
|
4609
4237
|
});
|
|
4610
4238
|
}, [isActive, playbackState, voice.isListening, voice.isSpeaking]);
|
|
4611
|
-
const syncAOM =
|
|
4239
|
+
const syncAOM = useCallback6(async () => {
|
|
4612
4240
|
if (!isActiveRef.current) return;
|
|
4613
|
-
const { generateMinifiedAOM: generateMinifiedAOM2 } = await import("./aom-
|
|
4241
|
+
const { generateMinifiedAOM: generateMinifiedAOM2 } = await import("./aom-SP2LMWQI.mjs");
|
|
4614
4242
|
const aom = generateMinifiedAOM2();
|
|
4615
4243
|
emitSocketEvent(socketRef.current, "tour:sync_dom", {
|
|
4616
4244
|
url: window.location.pathname + window.location.search + window.location.hash,
|
|
@@ -4618,7 +4246,7 @@ function useTourPlayback({
|
|
|
4618
4246
|
domSummary: captureDomSummary()
|
|
4619
4247
|
});
|
|
4620
4248
|
}, []);
|
|
4621
|
-
const scheduleManualInputSync =
|
|
4249
|
+
const scheduleManualInputSync = useCallback6(() => {
|
|
4622
4250
|
if (pendingManualInputSyncRef.current) {
|
|
4623
4251
|
clearTimeout(pendingManualInputSyncRef.current);
|
|
4624
4252
|
}
|
|
@@ -4630,13 +4258,13 @@ function useTourPlayback({
|
|
|
4630
4258
|
await syncAOM();
|
|
4631
4259
|
}, 150);
|
|
4632
4260
|
}, [syncAOM]);
|
|
4633
|
-
const clearPendingManualInputSync =
|
|
4261
|
+
const clearPendingManualInputSync = useCallback6(() => {
|
|
4634
4262
|
if (pendingManualInputSyncRef.current) {
|
|
4635
4263
|
clearTimeout(pendingManualInputSyncRef.current);
|
|
4636
4264
|
pendingManualInputSyncRef.current = null;
|
|
4637
4265
|
}
|
|
4638
4266
|
}, []);
|
|
4639
|
-
const interruptExecution =
|
|
4267
|
+
const interruptExecution = useCallback6((transcript) => {
|
|
4640
4268
|
if (!isSocketWritable(socketRef.current) || !isActiveRef.current) return false;
|
|
4641
4269
|
if (!commandInFlightRef.current && !voice.isSpeaking) return false;
|
|
4642
4270
|
interruptedForQuestionRef.current = true;
|
|
@@ -4664,7 +4292,7 @@ function useTourPlayback({
|
|
|
4664
4292
|
setPlaybackState("thinking");
|
|
4665
4293
|
return true;
|
|
4666
4294
|
}, [voice]);
|
|
4667
|
-
const stopTour =
|
|
4295
|
+
const stopTour = useCallback6(() => {
|
|
4668
4296
|
skipRequestedRef.current = true;
|
|
4669
4297
|
isActiveRef.current = false;
|
|
4670
4298
|
startRequestedRef.current = false;
|
|
@@ -4715,7 +4343,7 @@ function useTourPlayback({
|
|
|
4715
4343
|
pendingInputBufRef.current = null;
|
|
4716
4344
|
onTourEnd?.();
|
|
4717
4345
|
}, [voice, onTourEnd, serverUrl, websiteId, releasePlaybackOwnership]);
|
|
4718
|
-
const handleTourEnd =
|
|
4346
|
+
const handleTourEnd = useCallback6(() => {
|
|
4719
4347
|
const endingTourId = tourRef.current?.id;
|
|
4720
4348
|
const endingPreviewRunId = previewRunIdRef.current;
|
|
4721
4349
|
const endingStepOrder = stepIndexRef.current;
|
|
@@ -4762,7 +4390,7 @@ function useTourPlayback({
|
|
|
4762
4390
|
}
|
|
4763
4391
|
onTourEnd?.();
|
|
4764
4392
|
}, [experienceType, userProfile, serverUrl, voice, onTourEnd, websiteId, releasePlaybackOwnership]);
|
|
4765
|
-
const runTour =
|
|
4393
|
+
const runTour = useCallback6(async (tour, options) => {
|
|
4766
4394
|
if (!shouldAcceptTourStart({
|
|
4767
4395
|
isPlaybackActive: isActiveRef.current,
|
|
4768
4396
|
startRequested: startRequestedRef.current
|
|
@@ -4827,7 +4455,7 @@ function useTourPlayback({
|
|
|
4827
4455
|
tourContext: compactTourForTransport(tour)
|
|
4828
4456
|
});
|
|
4829
4457
|
}, [serverUrl, websiteId]);
|
|
4830
|
-
|
|
4458
|
+
useEffect10(() => {
|
|
4831
4459
|
if (!shouldRunTourAutoDiscovery({
|
|
4832
4460
|
enableAutoDiscovery,
|
|
4833
4461
|
disabled,
|
|
@@ -4891,7 +4519,7 @@ function useTourPlayback({
|
|
|
4891
4519
|
cancelled = true;
|
|
4892
4520
|
};
|
|
4893
4521
|
}, [serverUrl, toursApiBase, disabled, websiteId, experienceType, enableAutoDiscovery, locationSignature]);
|
|
4894
|
-
|
|
4522
|
+
useEffect10(() => {
|
|
4895
4523
|
if (!shouldRunTourAutoDiscovery({
|
|
4896
4524
|
enableAutoDiscovery,
|
|
4897
4525
|
disabled,
|
|
@@ -4938,22 +4566,22 @@ function useTourPlayback({
|
|
|
4938
4566
|
clearTimeout(timer);
|
|
4939
4567
|
};
|
|
4940
4568
|
}, [websiteId, serverUrl, toursApiBase, disabled, experienceType, userProfile?.userId, userProfile?.type, userProfile?.isNewUser, enableAutoDiscovery, locationSignature]);
|
|
4941
|
-
|
|
4569
|
+
useEffect10(() => {
|
|
4942
4570
|
if (!disabled || !isActiveRef.current) return;
|
|
4943
4571
|
stopTour();
|
|
4944
4572
|
}, [disabled, stopTour]);
|
|
4945
|
-
const startTour =
|
|
4573
|
+
const startTour = useCallback6((tour, options) => {
|
|
4946
4574
|
if (disabled) return;
|
|
4947
4575
|
void runTour(tour, options);
|
|
4948
4576
|
}, [disabled, runTour]);
|
|
4949
|
-
const acceptPendingTour =
|
|
4577
|
+
const acceptPendingTour = useCallback6(() => {
|
|
4950
4578
|
const tour = pendingTourRef.current;
|
|
4951
4579
|
if (!tour || disabled) return;
|
|
4952
4580
|
const opts = pendingTourOptionsRef.current;
|
|
4953
4581
|
pendingTourOptionsRef.current = null;
|
|
4954
4582
|
void runTour(tour, opts ?? void 0);
|
|
4955
4583
|
}, [disabled, runTour]);
|
|
4956
|
-
const dismissPendingTour =
|
|
4584
|
+
const dismissPendingTour = useCallback6(() => {
|
|
4957
4585
|
const tour = pendingTourRef.current;
|
|
4958
4586
|
setPendingTour(null);
|
|
4959
4587
|
pendingTourRef.current = null;
|
|
@@ -4961,7 +4589,7 @@ function useTourPlayback({
|
|
|
4961
4589
|
if (!tour || !userProfile?.userId) return;
|
|
4962
4590
|
void markTourDismissed(serverUrl, toursApiBaseRef.current, tour.id, userProfile.userId, experienceType, websiteId);
|
|
4963
4591
|
}, [experienceType, serverUrl, userProfile, websiteId]);
|
|
4964
|
-
const submitReviewFeedbackAction =
|
|
4592
|
+
const submitReviewFeedbackAction = useCallback6(async (utterance, apply = false) => {
|
|
4965
4593
|
const trimmed = utterance.trim();
|
|
4966
4594
|
const currentTour = tourRef.current;
|
|
4967
4595
|
const currentPreviewRunId = previewRunIdRef.current;
|
|
@@ -5001,10 +4629,10 @@ function useTourPlayback({
|
|
|
5001
4629
|
setReviewSubmitting(false);
|
|
5002
4630
|
}
|
|
5003
4631
|
}, [playbackState, serverUrl, websiteId]);
|
|
5004
|
-
const advanceStep =
|
|
4632
|
+
const advanceStep = useCallback6(() => {
|
|
5005
4633
|
advanceRequestedRef.current = true;
|
|
5006
4634
|
}, []);
|
|
5007
|
-
const skipTour =
|
|
4635
|
+
const skipTour = useCallback6(() => {
|
|
5008
4636
|
skipRequestedRef.current = true;
|
|
5009
4637
|
voiceInputResolveRef.current?.("");
|
|
5010
4638
|
voiceInputResolveRef.current = null;
|
|
@@ -5014,19 +4642,19 @@ function useTourPlayback({
|
|
|
5014
4642
|
askOrFillRef.current = null;
|
|
5015
4643
|
stopTour();
|
|
5016
4644
|
}, [stopTour]);
|
|
5017
|
-
const pauseTour =
|
|
4645
|
+
const pauseTour = useCallback6(() => {
|
|
5018
4646
|
if (isSocketWritable(socketRef.current) && isActiveRef.current) {
|
|
5019
4647
|
emitSocketEvent(socketRef.current, "tour:pause");
|
|
5020
4648
|
setPlaybackState("paused");
|
|
5021
4649
|
}
|
|
5022
4650
|
}, []);
|
|
5023
|
-
const resumeTour =
|
|
4651
|
+
const resumeTour = useCallback6(() => {
|
|
5024
4652
|
if (isSocketWritable(socketRef.current) && isActiveRef.current) {
|
|
5025
4653
|
emitSocketEvent(socketRef.current, "tour:resume");
|
|
5026
4654
|
setPlaybackState("executing");
|
|
5027
4655
|
}
|
|
5028
4656
|
}, []);
|
|
5029
|
-
const repeatStep =
|
|
4657
|
+
const repeatStep = useCallback6(() => {
|
|
5030
4658
|
const tour = tourRef.current;
|
|
5031
4659
|
const step = tour?.steps[stepIndexRef.current];
|
|
5032
4660
|
if (step) {
|
|
@@ -5034,7 +4662,7 @@ function useTourPlayback({
|
|
|
5034
4662
|
voice.speak(text, tour?.voice.ttsVoice);
|
|
5035
4663
|
}
|
|
5036
4664
|
}, [voice]);
|
|
5037
|
-
const handleVoiceInput =
|
|
4665
|
+
const handleVoiceInput = useCallback6((transcript) => {
|
|
5038
4666
|
const text = transcript.trim();
|
|
5039
4667
|
emitSdkDebugLog("[TourAgent] Voice input received", {
|
|
5040
4668
|
textLength: text.length
|
|
@@ -5062,7 +4690,7 @@ function useTourPlayback({
|
|
|
5062
4690
|
pendingInputBufRef.current = text;
|
|
5063
4691
|
}
|
|
5064
4692
|
}, [interruptExecution]);
|
|
5065
|
-
const handleTextInput =
|
|
4693
|
+
const handleTextInput = useCallback6((text) => {
|
|
5066
4694
|
if (voiceInputResolveRef.current) {
|
|
5067
4695
|
const resolve = voiceInputResolveRef.current;
|
|
5068
4696
|
voiceInputResolveRef.current = null;
|
|
@@ -5075,7 +4703,7 @@ function useTourPlayback({
|
|
|
5075
4703
|
handleVoiceInput(text.trim());
|
|
5076
4704
|
}
|
|
5077
4705
|
}, [handleVoiceInput]);
|
|
5078
|
-
|
|
4706
|
+
useEffect10(() => {
|
|
5079
4707
|
return () => {
|
|
5080
4708
|
removeHighlight();
|
|
5081
4709
|
removeCaption();
|
|
@@ -5156,14 +4784,14 @@ function useExperiencePlaybackController({
|
|
|
5156
4784
|
initialExperienceType = "tour"
|
|
5157
4785
|
}) {
|
|
5158
4786
|
const locationSignature = typeof window === "undefined" ? "" : getLocationSignature(window.location);
|
|
5159
|
-
const [activeExperienceType, setActiveExperienceType] =
|
|
5160
|
-
const [startingExperienceType, setStartingExperienceType] =
|
|
5161
|
-
const [pendingPrompt, setPendingPrompt] =
|
|
5162
|
-
const pendingPromptRef =
|
|
5163
|
-
const queuedStartRef =
|
|
5164
|
-
const bufferedVoiceInputsRef =
|
|
5165
|
-
const previewDiscoveryInFlightRef =
|
|
5166
|
-
const previewSessionRef =
|
|
4787
|
+
const [activeExperienceType, setActiveExperienceType] = useState7(initialExperienceType);
|
|
4788
|
+
const [startingExperienceType, setStartingExperienceType] = useState7(null);
|
|
4789
|
+
const [pendingPrompt, setPendingPrompt] = useState7(null);
|
|
4790
|
+
const pendingPromptRef = useRef8(null);
|
|
4791
|
+
const queuedStartRef = useRef8(null);
|
|
4792
|
+
const bufferedVoiceInputsRef = useRef8([]);
|
|
4793
|
+
const previewDiscoveryInFlightRef = useRef8(false);
|
|
4794
|
+
const previewSessionRef = useRef8(readPreviewSessionSuppression());
|
|
5167
4795
|
pendingPromptRef.current = pendingPrompt;
|
|
5168
4796
|
const playback = useTourPlayback({
|
|
5169
4797
|
serverUrl,
|
|
@@ -5182,7 +4810,7 @@ function useExperiencePlaybackController({
|
|
|
5182
4810
|
showCaptions,
|
|
5183
4811
|
enableAutoDiscovery: false
|
|
5184
4812
|
});
|
|
5185
|
-
const queueExperienceStart =
|
|
4813
|
+
const queueExperienceStart = useCallback7((tour, experienceType, options) => {
|
|
5186
4814
|
setPendingPrompt(null);
|
|
5187
4815
|
pendingPromptRef.current = null;
|
|
5188
4816
|
setStartingExperienceType(experienceType);
|
|
@@ -5197,17 +4825,17 @@ function useExperiencePlaybackController({
|
|
|
5197
4825
|
}
|
|
5198
4826
|
playback.startTour(tour, options);
|
|
5199
4827
|
}, [activeExperienceType, playback]);
|
|
5200
|
-
const startExperience =
|
|
4828
|
+
const startExperience = useCallback7((tour, experienceType, options) => {
|
|
5201
4829
|
const resolvedExperienceType = experienceType ?? tour.type ?? activeExperienceType;
|
|
5202
4830
|
queueExperienceStart(tour, resolvedExperienceType, options);
|
|
5203
4831
|
}, [activeExperienceType, queueExperienceStart]);
|
|
5204
|
-
const acceptPendingPrompt =
|
|
4832
|
+
const acceptPendingPrompt = useCallback7((experienceType) => {
|
|
5205
4833
|
const prompt = pendingPromptRef.current;
|
|
5206
4834
|
if (!prompt) return;
|
|
5207
4835
|
if (experienceType && prompt.experienceType !== experienceType) return;
|
|
5208
4836
|
queueExperienceStart(prompt.tour, prompt.experienceType, prompt.options);
|
|
5209
4837
|
}, [queueExperienceStart]);
|
|
5210
|
-
const dismissPendingPrompt =
|
|
4838
|
+
const dismissPendingPrompt = useCallback7((experienceType) => {
|
|
5211
4839
|
const prompt = pendingPromptRef.current;
|
|
5212
4840
|
if (!prompt) return;
|
|
5213
4841
|
if (experienceType && prompt.experienceType !== experienceType) return;
|
|
@@ -5230,7 +4858,7 @@ function useExperiencePlaybackController({
|
|
|
5230
4858
|
websiteId
|
|
5231
4859
|
);
|
|
5232
4860
|
}, [serverUrl, toursApiBase, userProfile, websiteId]);
|
|
5233
|
-
const handleVoiceInput =
|
|
4861
|
+
const handleVoiceInput = useCallback7((transcript, experienceType) => {
|
|
5234
4862
|
const trimmed = transcript.trim();
|
|
5235
4863
|
if (!trimmed) return;
|
|
5236
4864
|
const targetExperienceType = experienceType ?? activeExperienceType;
|
|
@@ -5250,12 +4878,12 @@ function useExperiencePlaybackController({
|
|
|
5250
4878
|
}
|
|
5251
4879
|
playback.handleVoiceInput(trimmed);
|
|
5252
4880
|
}, [activeExperienceType, playback]);
|
|
5253
|
-
|
|
4881
|
+
useEffect11(() => {
|
|
5254
4882
|
if (playback.isActive && startingExperienceType !== null) {
|
|
5255
4883
|
setStartingExperienceType(null);
|
|
5256
4884
|
}
|
|
5257
4885
|
}, [playback.isActive, startingExperienceType]);
|
|
5258
|
-
|
|
4886
|
+
useEffect11(() => {
|
|
5259
4887
|
const queuedStart = queuedStartRef.current;
|
|
5260
4888
|
if (!queuedStart) return;
|
|
5261
4889
|
if (playback.isActive) return;
|
|
@@ -5263,14 +4891,14 @@ function useExperiencePlaybackController({
|
|
|
5263
4891
|
queuedStartRef.current = null;
|
|
5264
4892
|
playback.startTour(queuedStart.tour, queuedStart.options);
|
|
5265
4893
|
}, [activeExperienceType, playback]);
|
|
5266
|
-
|
|
4894
|
+
useEffect11(() => {
|
|
5267
4895
|
if (!playback.isActive) return;
|
|
5268
4896
|
const readyInputs = bufferedVoiceInputsRef.current.filter((item) => item.experienceType === activeExperienceType);
|
|
5269
4897
|
if (readyInputs.length === 0) return;
|
|
5270
4898
|
bufferedVoiceInputsRef.current = bufferedVoiceInputsRef.current.filter((item) => item.experienceType !== activeExperienceType);
|
|
5271
4899
|
readyInputs.forEach((item) => playback.handleVoiceInput(item.transcript));
|
|
5272
4900
|
}, [activeExperienceType, playback]);
|
|
5273
|
-
|
|
4901
|
+
useEffect11(() => {
|
|
5274
4902
|
if (!shouldDiscoverDraftPreview({
|
|
5275
4903
|
disabled,
|
|
5276
4904
|
hasPendingPrompt: Boolean(pendingPromptRef.current),
|
|
@@ -5352,7 +4980,7 @@ function useExperiencePlaybackController({
|
|
|
5352
4980
|
previewDiscoveryInFlightRef.current = false;
|
|
5353
4981
|
};
|
|
5354
4982
|
}, [disabled, playback.isActive, queueExperienceStart, serverUrl, startingExperienceType, toursApiBase, websiteId, locationSignature]);
|
|
5355
|
-
|
|
4983
|
+
useEffect11(() => {
|
|
5356
4984
|
if (!shouldDiscoverEligibleTours({
|
|
5357
4985
|
disabled,
|
|
5358
4986
|
hasPendingPrompt: Boolean(pendingPromptRef.current),
|
|
@@ -5416,7 +5044,7 @@ function useExperiencePlaybackController({
|
|
|
5416
5044
|
}
|
|
5417
5045
|
|
|
5418
5046
|
// src/hooks/useVoice.ts
|
|
5419
|
-
import { useState as
|
|
5047
|
+
import { useState as useState8, useRef as useRef9, useCallback as useCallback8, useEffect as useEffect12 } from "react";
|
|
5420
5048
|
|
|
5421
5049
|
// src/utils/webrtc-aec.ts
|
|
5422
5050
|
function isWebRtcAecSupported() {
|
|
@@ -5785,36 +5413,36 @@ function isFatalSpeechError(error) {
|
|
|
5785
5413
|
return error === "not-allowed" || error === "service-not-allowed" || error === "audio-capture";
|
|
5786
5414
|
}
|
|
5787
5415
|
function useVoice(serverUrl) {
|
|
5788
|
-
const [isSpeaking, setIsSpeaking] =
|
|
5789
|
-
const [isListening, setIsListening] =
|
|
5790
|
-
const [isMuted, setIsMuted] =
|
|
5791
|
-
const audioRef =
|
|
5792
|
-
const audioBlobUrlRef =
|
|
5793
|
-
const speakResolveRef =
|
|
5794
|
-
const recognitionRef =
|
|
5795
|
-
const isMutedRef =
|
|
5796
|
-
const sttCallbacksRef =
|
|
5797
|
-
const stripIndicesRef =
|
|
5798
|
-
const accumulatedRef =
|
|
5799
|
-
const interimDebounceRef =
|
|
5800
|
-
const lastInterimRef =
|
|
5801
|
-
const lastDeliveredRef =
|
|
5802
|
-
const isSpeakingRef =
|
|
5803
|
-
const speechEndTimeRef =
|
|
5804
|
-
const recentTtsRef =
|
|
5805
|
-
const prefetchedSpeechRef =
|
|
5806
|
-
const nearEndTimeoutRef =
|
|
5807
|
-
const queuePromiseRef =
|
|
5808
|
-
const queueSeqRef =
|
|
5809
|
-
const lastStopSeqRef =
|
|
5810
|
-
const listeningSessionIdRef =
|
|
5811
|
-
const listeningStartedAtRef =
|
|
5812
|
-
const loopbackRef =
|
|
5813
|
-
const aecActiveRef =
|
|
5814
|
-
const mediaRecorderRef =
|
|
5815
|
-
const micStreamRef =
|
|
5816
|
-
const sttSocketRef =
|
|
5817
|
-
const stopLiveSttTransport =
|
|
5416
|
+
const [isSpeaking, setIsSpeaking] = useState8(false);
|
|
5417
|
+
const [isListening, setIsListening] = useState8(false);
|
|
5418
|
+
const [isMuted, setIsMuted] = useState8(false);
|
|
5419
|
+
const audioRef = useRef9(null);
|
|
5420
|
+
const audioBlobUrlRef = useRef9(null);
|
|
5421
|
+
const speakResolveRef = useRef9(null);
|
|
5422
|
+
const recognitionRef = useRef9(null);
|
|
5423
|
+
const isMutedRef = useRef9(false);
|
|
5424
|
+
const sttCallbacksRef = useRef9(null);
|
|
5425
|
+
const stripIndicesRef = useRef9({});
|
|
5426
|
+
const accumulatedRef = useRef9([]);
|
|
5427
|
+
const interimDebounceRef = useRef9(null);
|
|
5428
|
+
const lastInterimRef = useRef9("");
|
|
5429
|
+
const lastDeliveredRef = useRef9("");
|
|
5430
|
+
const isSpeakingRef = useRef9(false);
|
|
5431
|
+
const speechEndTimeRef = useRef9(0);
|
|
5432
|
+
const recentTtsRef = useRef9([]);
|
|
5433
|
+
const prefetchedSpeechRef = useRef9(/* @__PURE__ */ new Map());
|
|
5434
|
+
const nearEndTimeoutRef = useRef9(null);
|
|
5435
|
+
const queuePromiseRef = useRef9(Promise.resolve());
|
|
5436
|
+
const queueSeqRef = useRef9(0);
|
|
5437
|
+
const lastStopSeqRef = useRef9(0);
|
|
5438
|
+
const listeningSessionIdRef = useRef9(null);
|
|
5439
|
+
const listeningStartedAtRef = useRef9(0);
|
|
5440
|
+
const loopbackRef = useRef9(null);
|
|
5441
|
+
const aecActiveRef = useRef9(false);
|
|
5442
|
+
const mediaRecorderRef = useRef9(null);
|
|
5443
|
+
const micStreamRef = useRef9(null);
|
|
5444
|
+
const sttSocketRef = useRef9(null);
|
|
5445
|
+
const stopLiveSttTransport = useCallback8(() => {
|
|
5818
5446
|
const socket = sttSocketRef.current;
|
|
5819
5447
|
sttSocketRef.current = null;
|
|
5820
5448
|
if (socket) {
|
|
@@ -5843,16 +5471,16 @@ function useVoice(serverUrl) {
|
|
|
5843
5471
|
}
|
|
5844
5472
|
mediaRecorderRef.current = null;
|
|
5845
5473
|
}, []);
|
|
5846
|
-
|
|
5474
|
+
useEffect12(() => {
|
|
5847
5475
|
isMutedRef.current = isMuted;
|
|
5848
5476
|
}, [isMuted]);
|
|
5849
|
-
|
|
5477
|
+
useEffect12(() => {
|
|
5850
5478
|
isSpeakingRef.current = isSpeaking;
|
|
5851
5479
|
}, [isSpeaking]);
|
|
5852
5480
|
const webSpeechSupported = typeof window !== "undefined" && !!(window.SpeechRecognition || window.webkitSpeechRecognition);
|
|
5853
5481
|
const mediaCaptureSupported = typeof window !== "undefined" && typeof navigator !== "undefined" && !!navigator.mediaDevices?.getUserMedia && typeof MediaRecorder !== "undefined";
|
|
5854
5482
|
const sttSupported = typeof window !== "undefined" && (mediaCaptureSupported || webSpeechSupported);
|
|
5855
|
-
const stopSpeaking =
|
|
5483
|
+
const stopSpeaking = useCallback8(() => {
|
|
5856
5484
|
emitVoiceDebug("tts_stop", {
|
|
5857
5485
|
queueSeq: queueSeqRef.current,
|
|
5858
5486
|
wasSpeaking: isSpeakingRef.current
|
|
@@ -5879,8 +5507,8 @@ function useVoice(serverUrl) {
|
|
|
5879
5507
|
speakResolveRef.current?.();
|
|
5880
5508
|
speakResolveRef.current = null;
|
|
5881
5509
|
}, []);
|
|
5882
|
-
const getSpeechCacheKey =
|
|
5883
|
-
const loadAudioDurationMs =
|
|
5510
|
+
const getSpeechCacheKey = useCallback8((text, voiceId) => `${voiceId}::${text}`, []);
|
|
5511
|
+
const loadAudioDurationMs = useCallback8(async (url, fallbackText) => {
|
|
5884
5512
|
try {
|
|
5885
5513
|
const probe = new Audio();
|
|
5886
5514
|
probe.preload = "metadata";
|
|
@@ -5902,7 +5530,7 @@ function useVoice(serverUrl) {
|
|
|
5902
5530
|
return estimateSpeechDurationMs(fallbackText);
|
|
5903
5531
|
}
|
|
5904
5532
|
}, []);
|
|
5905
|
-
const fetchSpeechClip =
|
|
5533
|
+
const fetchSpeechClip = useCallback8(async (text, voiceId) => {
|
|
5906
5534
|
const baseUrl = serverUrl.replace(/\/$/, "");
|
|
5907
5535
|
const debugEnabled = isVoiceDebugEnabled();
|
|
5908
5536
|
const requestId = createVoiceDebugId("tts");
|
|
@@ -5964,7 +5592,7 @@ function useVoice(serverUrl) {
|
|
|
5964
5592
|
});
|
|
5965
5593
|
return { url, durationMs, requestId, buffered: true };
|
|
5966
5594
|
}, [loadAudioDurationMs, serverUrl]);
|
|
5967
|
-
const createStreamingSpeechClipForPlayback =
|
|
5595
|
+
const createStreamingSpeechClipForPlayback = useCallback8((text, voiceId) => {
|
|
5968
5596
|
const requestId = createVoiceDebugId("tts");
|
|
5969
5597
|
const clip = createStreamingSpeechClip(serverUrl, text, voiceId, {
|
|
5970
5598
|
requestId,
|
|
@@ -5979,7 +5607,7 @@ function useVoice(serverUrl) {
|
|
|
5979
5607
|
});
|
|
5980
5608
|
return clip;
|
|
5981
5609
|
}, [serverUrl]);
|
|
5982
|
-
const prefetchSpeech =
|
|
5610
|
+
const prefetchSpeech = useCallback8(async (text, voiceId = DEFAULT_VOICE_ID) => {
|
|
5983
5611
|
if (isMutedRef.current || !text.trim()) return;
|
|
5984
5612
|
const key = getSpeechCacheKey(text, voiceId);
|
|
5985
5613
|
if (!prefetchedSpeechRef.current.has(key)) {
|
|
@@ -5993,7 +5621,7 @@ function useVoice(serverUrl) {
|
|
|
5993
5621
|
}
|
|
5994
5622
|
await prefetchedSpeechRef.current.get(key);
|
|
5995
5623
|
}, [fetchSpeechClip, getSpeechCacheKey]);
|
|
5996
|
-
const playClipDirect =
|
|
5624
|
+
const playClipDirect = useCallback8(async (clip, timeoutMs) => {
|
|
5997
5625
|
const { url } = clip;
|
|
5998
5626
|
const audio = new Audio();
|
|
5999
5627
|
audio.crossOrigin = "anonymous";
|
|
@@ -6089,7 +5717,7 @@ function useVoice(serverUrl) {
|
|
|
6089
5717
|
});
|
|
6090
5718
|
});
|
|
6091
5719
|
}, []);
|
|
6092
|
-
const speak =
|
|
5720
|
+
const speak = useCallback8(async (text, voiceId = DEFAULT_VOICE_ID, options = {}) => {
|
|
6093
5721
|
if (isMutedRef.current) return;
|
|
6094
5722
|
const mySeq = ++queueSeqRef.current;
|
|
6095
5723
|
const interrupt = options.interrupt === true;
|
|
@@ -6181,7 +5809,7 @@ function useVoice(serverUrl) {
|
|
|
6181
5809
|
}
|
|
6182
5810
|
return taskPromise;
|
|
6183
5811
|
}, [createStreamingSpeechClipForPlayback, fetchSpeechClip, getSpeechCacheKey, playClipDirect, stopSpeaking]);
|
|
6184
|
-
const stopListening =
|
|
5812
|
+
const stopListening = useCallback8(() => {
|
|
6185
5813
|
emitVoiceDebug("stt_stop_listening", {
|
|
6186
5814
|
listeningSessionId: listeningSessionIdRef.current,
|
|
6187
5815
|
listeningMs: listeningStartedAtRef.current ? Math.round(performance.now() - listeningStartedAtRef.current) : null
|
|
@@ -6213,7 +5841,7 @@ function useVoice(serverUrl) {
|
|
|
6213
5841
|
accumulatedRef.current = [];
|
|
6214
5842
|
setIsListening(false);
|
|
6215
5843
|
}, [stopLiveSttTransport]);
|
|
6216
|
-
const startListening =
|
|
5844
|
+
const startListening = useCallback8((onResult, onInterruption, onError, options = {}) => {
|
|
6217
5845
|
stopListening();
|
|
6218
5846
|
listeningSessionIdRef.current = createVoiceDebugId("stt");
|
|
6219
5847
|
listeningStartedAtRef.current = performance.now();
|
|
@@ -6497,7 +6125,7 @@ function useVoice(serverUrl) {
|
|
|
6497
6125
|
}
|
|
6498
6126
|
fallbackToWebSpeech();
|
|
6499
6127
|
}, [serverUrl, stopListening, stopSpeaking, stopLiveSttTransport]);
|
|
6500
|
-
const toggleMute =
|
|
6128
|
+
const toggleMute = useCallback8(() => {
|
|
6501
6129
|
setIsMuted((prev) => {
|
|
6502
6130
|
const next = !prev;
|
|
6503
6131
|
if (next) {
|
|
@@ -6509,7 +6137,7 @@ function useVoice(serverUrl) {
|
|
|
6509
6137
|
return next;
|
|
6510
6138
|
});
|
|
6511
6139
|
}, []);
|
|
6512
|
-
|
|
6140
|
+
useEffect12(() => {
|
|
6513
6141
|
return () => {
|
|
6514
6142
|
stopSpeaking();
|
|
6515
6143
|
stopListening();
|
|
@@ -6538,18 +6166,18 @@ function useVoice(serverUrl) {
|
|
|
6538
6166
|
}
|
|
6539
6167
|
|
|
6540
6168
|
// src/hooks/useAudioLevel.ts
|
|
6541
|
-
import { useState as
|
|
6169
|
+
import { useState as useState9, useEffect as useEffect13, useRef as useRef10 } from "react";
|
|
6542
6170
|
var BAR_COUNT = 9;
|
|
6543
6171
|
var SENSITIVITY = 2.8;
|
|
6544
6172
|
var FLOOR = 0.08;
|
|
6545
6173
|
function useAudioLevel(active) {
|
|
6546
|
-
const [levels, setLevels] =
|
|
6547
|
-
const streamRef =
|
|
6548
|
-
const ctxRef =
|
|
6549
|
-
const analyserRef =
|
|
6550
|
-
const rafRef =
|
|
6551
|
-
const timeDataRef =
|
|
6552
|
-
|
|
6174
|
+
const [levels, setLevels] = useState9(() => Array(BAR_COUNT).fill(FLOOR));
|
|
6175
|
+
const streamRef = useRef10(null);
|
|
6176
|
+
const ctxRef = useRef10(null);
|
|
6177
|
+
const analyserRef = useRef10(null);
|
|
6178
|
+
const rafRef = useRef10(0);
|
|
6179
|
+
const timeDataRef = useRef10(null);
|
|
6180
|
+
useEffect13(() => {
|
|
6553
6181
|
if (!active || typeof window === "undefined") {
|
|
6554
6182
|
setLevels(Array(BAR_COUNT).fill(FLOOR));
|
|
6555
6183
|
return;
|
|
@@ -6621,7 +6249,7 @@ function useAudioLevel(active) {
|
|
|
6621
6249
|
}
|
|
6622
6250
|
|
|
6623
6251
|
// src/hooks/useRecordingMode.ts
|
|
6624
|
-
import { useState as
|
|
6252
|
+
import { useState as useState10, useRef as useRef11, useCallback as useCallback9, useEffect as useEffect14 } from "react";
|
|
6625
6253
|
|
|
6626
6254
|
// src/utils/tourStepTypes.ts
|
|
6627
6255
|
function isAskDrivenInputStepType(stepType) {
|
|
@@ -6902,46 +6530,46 @@ function useRecordingMode({
|
|
|
6902
6530
|
onPreview,
|
|
6903
6531
|
experienceType = "tour"
|
|
6904
6532
|
}) {
|
|
6905
|
-
const restoredSessionRef =
|
|
6533
|
+
const restoredSessionRef = useRef11(void 0);
|
|
6906
6534
|
if (restoredSessionRef.current === void 0) {
|
|
6907
6535
|
restoredSessionRef.current = readPersistedRecordingSession();
|
|
6908
6536
|
}
|
|
6909
6537
|
const restoredSession = restoredSessionRef.current;
|
|
6910
6538
|
const restoredPhase = restoredSession ? "active" : "idle";
|
|
6911
|
-
const [phase, setPhase] =
|
|
6912
|
-
const [steps, setSteps] =
|
|
6913
|
-
const [selectedElement, setSelectedElement] =
|
|
6914
|
-
const [selectedStepType, setSelectedStepType] =
|
|
6915
|
-
const [pendingNarration, setPendingNarration] =
|
|
6916
|
-
const [polishedNarration, setPolishedNarration] =
|
|
6917
|
-
const [captureEvents, setCaptureEvents] =
|
|
6918
|
-
const [capturedTranscript, setCapturedTranscript] =
|
|
6919
|
-
const [isVoiceCaptureActive, setIsVoiceCaptureActive] =
|
|
6920
|
-
const stepsRef =
|
|
6539
|
+
const [phase, setPhase] = useState10(restoredPhase);
|
|
6540
|
+
const [steps, setSteps] = useState10(() => restoredSession?.steps ?? []);
|
|
6541
|
+
const [selectedElement, setSelectedElement] = useState10(null);
|
|
6542
|
+
const [selectedStepType, setSelectedStepType] = useState10(() => restoredSession?.selectedStepType ?? "ask_or_fill");
|
|
6543
|
+
const [pendingNarration, setPendingNarration] = useState10("");
|
|
6544
|
+
const [polishedNarration, setPolishedNarration] = useState10("");
|
|
6545
|
+
const [captureEvents, setCaptureEvents] = useState10(() => restoredSession?.captureEvents ?? []);
|
|
6546
|
+
const [capturedTranscript, setCapturedTranscript] = useState10(() => restoredSession?.capturedTranscript ?? "");
|
|
6547
|
+
const [isVoiceCaptureActive, setIsVoiceCaptureActive] = useState10(false);
|
|
6548
|
+
const stepsRef = useRef11([]);
|
|
6921
6549
|
stepsRef.current = steps;
|
|
6922
|
-
const captureEventsRef =
|
|
6923
|
-
const capturedTranscriptRef =
|
|
6550
|
+
const captureEventsRef = useRef11([]);
|
|
6551
|
+
const capturedTranscriptRef = useRef11(capturedTranscript);
|
|
6924
6552
|
capturedTranscriptRef.current = capturedTranscript;
|
|
6925
|
-
const phaseRef =
|
|
6553
|
+
const phaseRef = useRef11(phase);
|
|
6926
6554
|
phaseRef.current = phase;
|
|
6927
|
-
const safeSpeak =
|
|
6555
|
+
const safeSpeak = useCallback9((text) => {
|
|
6928
6556
|
void voice.speak(text).catch((err) => {
|
|
6929
6557
|
console.warn("[Recording] Voice playback unavailable:", err);
|
|
6930
6558
|
});
|
|
6931
6559
|
}, [voice]);
|
|
6932
6560
|
captureEventsRef.current = captureEvents;
|
|
6933
|
-
const pendingClicksRef =
|
|
6934
|
-
const shouldKeepVoiceCaptureRef =
|
|
6935
|
-
const resumeVoiceAfterNarrationRef =
|
|
6936
|
-
const lastAutoNoteRef =
|
|
6937
|
-
const lastHoverKeyRef =
|
|
6938
|
-
const lastHoverAtRef =
|
|
6939
|
-
const selectedStepTypeRef =
|
|
6561
|
+
const pendingClicksRef = useRef11(restoredSession?.pendingClicks ?? []);
|
|
6562
|
+
const shouldKeepVoiceCaptureRef = useRef11(restoredSession?.voiceCaptureEnabled === true);
|
|
6563
|
+
const resumeVoiceAfterNarrationRef = useRef11(false);
|
|
6564
|
+
const lastAutoNoteRef = useRef11("");
|
|
6565
|
+
const lastHoverKeyRef = useRef11("");
|
|
6566
|
+
const lastHoverAtRef = useRef11(0);
|
|
6567
|
+
const selectedStepTypeRef = useRef11("ask_or_fill");
|
|
6940
6568
|
selectedStepTypeRef.current = selectedStepType;
|
|
6941
6569
|
const isRecording = phase !== "idle";
|
|
6942
6570
|
const stepCount = steps.length;
|
|
6943
6571
|
const captureEventCount = captureEvents.length;
|
|
6944
|
-
const persistSnapshot =
|
|
6572
|
+
const persistSnapshot = useCallback9((overrides) => {
|
|
6945
6573
|
const nextPhase = overrides?.phase ?? phaseRef.current;
|
|
6946
6574
|
const nextSteps = overrides?.steps ?? stepsRef.current;
|
|
6947
6575
|
const nextCaptureEvents = overrides?.captureEvents ?? captureEventsRef.current;
|
|
@@ -6964,7 +6592,7 @@ function useRecordingMode({
|
|
|
6964
6592
|
voiceCaptureEnabled: nextVoiceCaptureEnabled
|
|
6965
6593
|
});
|
|
6966
6594
|
}, [experienceType]);
|
|
6967
|
-
const appendCaptureEvent =
|
|
6595
|
+
const appendCaptureEvent = useCallback9((event) => {
|
|
6968
6596
|
const nextEvent = {
|
|
6969
6597
|
id: event.id || newCaptureId(event.type),
|
|
6970
6598
|
order: captureEventsRef.current.length,
|
|
@@ -6976,7 +6604,7 @@ function useRecordingMode({
|
|
|
6976
6604
|
setCaptureEvents(nextCaptureEvents);
|
|
6977
6605
|
persistSnapshot({ captureEvents: nextCaptureEvents });
|
|
6978
6606
|
}, [persistSnapshot]);
|
|
6979
|
-
const updateCaptureEvent =
|
|
6607
|
+
const updateCaptureEvent = useCallback9((id, metadataPatch) => {
|
|
6980
6608
|
const nextCaptureEvents = captureEventsRef.current.map((event) => {
|
|
6981
6609
|
if (event.id === id) {
|
|
6982
6610
|
return {
|
|
@@ -6993,7 +6621,7 @@ function useRecordingMode({
|
|
|
6993
6621
|
setCaptureEvents(nextCaptureEvents);
|
|
6994
6622
|
persistSnapshot({ captureEvents: nextCaptureEvents });
|
|
6995
6623
|
}, [persistSnapshot]);
|
|
6996
|
-
const appendVoiceNote =
|
|
6624
|
+
const appendVoiceNote = useCallback9((transcript) => {
|
|
6997
6625
|
const text = transcript.trim();
|
|
6998
6626
|
if (!text) return;
|
|
6999
6627
|
if (lastAutoNoteRef.current === text) return;
|
|
@@ -7054,11 +6682,11 @@ function useRecordingMode({
|
|
|
7054
6682
|
}
|
|
7055
6683
|
});
|
|
7056
6684
|
}, [appendCaptureEvent, persistSnapshot]);
|
|
7057
|
-
const stopBackgroundVoiceCapture =
|
|
6685
|
+
const stopBackgroundVoiceCapture = useCallback9(() => {
|
|
7058
6686
|
voice.stopListening();
|
|
7059
6687
|
setIsVoiceCaptureActive(false);
|
|
7060
6688
|
}, [voice]);
|
|
7061
|
-
const startBackgroundVoiceCapture =
|
|
6689
|
+
const startBackgroundVoiceCapture = useCallback9(() => {
|
|
7062
6690
|
if (!shouldKeepVoiceCaptureRef.current) return;
|
|
7063
6691
|
if (!isRecording) return;
|
|
7064
6692
|
if (phase === "narrating" || phase === "reviewing") return;
|
|
@@ -7075,7 +6703,7 @@ function useRecordingMode({
|
|
|
7075
6703
|
);
|
|
7076
6704
|
setIsVoiceCaptureActive(true);
|
|
7077
6705
|
}, [appendVoiceNote, isRecording, phase, voice]);
|
|
7078
|
-
const startRecording =
|
|
6706
|
+
const startRecording = useCallback9(() => {
|
|
7079
6707
|
const nextPhase = "active";
|
|
7080
6708
|
const nextCaptureEvents = [{
|
|
7081
6709
|
id: newCaptureId("session_start"),
|
|
@@ -7107,34 +6735,34 @@ function useRecordingMode({
|
|
|
7107
6735
|
voiceCaptureEnabled: false
|
|
7108
6736
|
});
|
|
7109
6737
|
}, [persistSnapshot]);
|
|
7110
|
-
const markStep =
|
|
6738
|
+
const markStep = useCallback9(() => {
|
|
7111
6739
|
if (phase !== "active") return;
|
|
7112
6740
|
setPhase("selecting");
|
|
7113
6741
|
}, [phase]);
|
|
7114
|
-
const selectElement =
|
|
6742
|
+
const selectElement = useCallback9((recorded) => {
|
|
7115
6743
|
setSelectedElement(recorded);
|
|
7116
6744
|
setPhase("configuring");
|
|
7117
6745
|
const isFormField = ["INPUT", "SELECT", "TEXTAREA"].includes(recorded.el.tagName);
|
|
7118
6746
|
setSelectedStepType(isFormField ? "ask_or_fill" : "narrate");
|
|
7119
6747
|
}, []);
|
|
7120
|
-
const selectPageLevel =
|
|
6748
|
+
const selectPageLevel = useCallback9(() => {
|
|
7121
6749
|
setSelectedElement(null);
|
|
7122
6750
|
setSelectedStepType("narrate");
|
|
7123
6751
|
setPhase("configuring");
|
|
7124
6752
|
}, []);
|
|
7125
|
-
const cancelSelection =
|
|
6753
|
+
const cancelSelection = useCallback9(() => {
|
|
7126
6754
|
setSelectedElement(null);
|
|
7127
6755
|
setPhase("active");
|
|
7128
6756
|
}, []);
|
|
7129
|
-
const setStepType =
|
|
6757
|
+
const setStepType = useCallback9((type) => {
|
|
7130
6758
|
setSelectedStepType(type);
|
|
7131
6759
|
}, []);
|
|
7132
|
-
const runPolishAndReview =
|
|
6760
|
+
const runPolishAndReview = useCallback9(async (transcript) => {
|
|
7133
6761
|
setPolishedNarration(transcript);
|
|
7134
6762
|
setPhase("reviewing");
|
|
7135
6763
|
}, []);
|
|
7136
|
-
const pendingNarrationRef =
|
|
7137
|
-
const startNarration =
|
|
6764
|
+
const pendingNarrationRef = useRef11("");
|
|
6765
|
+
const startNarration = useCallback9(() => {
|
|
7138
6766
|
resumeVoiceAfterNarrationRef.current = shouldKeepVoiceCaptureRef.current && isVoiceCaptureActive;
|
|
7139
6767
|
if (isVoiceCaptureActive) {
|
|
7140
6768
|
stopBackgroundVoiceCapture();
|
|
@@ -7156,7 +6784,7 @@ function useRecordingMode({
|
|
|
7156
6784
|
{ continuous: true }
|
|
7157
6785
|
);
|
|
7158
6786
|
}, [isVoiceCaptureActive, stopBackgroundVoiceCapture, voice]);
|
|
7159
|
-
const finishNarration =
|
|
6787
|
+
const finishNarration = useCallback9(async () => {
|
|
7160
6788
|
if (phase !== "narrating") return;
|
|
7161
6789
|
voice.stopListening();
|
|
7162
6790
|
const text = pendingNarrationRef.current;
|
|
@@ -7171,13 +6799,13 @@ function useRecordingMode({
|
|
|
7171
6799
|
}
|
|
7172
6800
|
}
|
|
7173
6801
|
}, [phase, runPolishAndReview, startBackgroundVoiceCapture, voice]);
|
|
7174
|
-
const submitTextNarration =
|
|
6802
|
+
const submitTextNarration = useCallback9(async (text) => {
|
|
7175
6803
|
if (phase !== "narrating" || !text.trim()) return;
|
|
7176
6804
|
voice.stopListening();
|
|
7177
6805
|
setPendingNarration(text);
|
|
7178
6806
|
await runPolishAndReview(text);
|
|
7179
6807
|
}, [phase, voice, runPolishAndReview]);
|
|
7180
|
-
const approveNarration =
|
|
6808
|
+
const approveNarration = useCallback9(() => {
|
|
7181
6809
|
if (phase !== "reviewing") return;
|
|
7182
6810
|
const el = selectedElement;
|
|
7183
6811
|
const narration = polishedNarration || pendingNarration;
|
|
@@ -7267,17 +6895,17 @@ function useRecordingMode({
|
|
|
7267
6895
|
}, 0);
|
|
7268
6896
|
}
|
|
7269
6897
|
}, [appendCaptureEvent, phase, polishedNarration, pendingNarration, persistSnapshot, selectedElement, selectedStepType, startBackgroundVoiceCapture, voice]);
|
|
7270
|
-
const redoNarration =
|
|
6898
|
+
const redoNarration = useCallback9(() => {
|
|
7271
6899
|
if (phase !== "reviewing") return;
|
|
7272
6900
|
setPendingNarration("");
|
|
7273
6901
|
setPolishedNarration("");
|
|
7274
6902
|
startNarration();
|
|
7275
6903
|
}, [phase, startNarration]);
|
|
7276
|
-
const editNarration =
|
|
6904
|
+
const editNarration = useCallback9((text) => {
|
|
7277
6905
|
setPendingNarration(text);
|
|
7278
6906
|
setPolishedNarration(text);
|
|
7279
6907
|
}, []);
|
|
7280
|
-
const continueRecording =
|
|
6908
|
+
const continueRecording = useCallback9(() => {
|
|
7281
6909
|
phaseRef.current = "active";
|
|
7282
6910
|
setPhase("active");
|
|
7283
6911
|
persistSnapshot({ phase: "active" });
|
|
@@ -7287,7 +6915,7 @@ function useRecordingMode({
|
|
|
7287
6915
|
}, 0);
|
|
7288
6916
|
}
|
|
7289
6917
|
}, [persistSnapshot, startBackgroundVoiceCapture]);
|
|
7290
|
-
const undoLastStep =
|
|
6918
|
+
const undoLastStep = useCallback9(() => {
|
|
7291
6919
|
const previous = stepsRef.current;
|
|
7292
6920
|
const nextSteps = previous.slice(0, -1);
|
|
7293
6921
|
stepsRef.current = nextSteps;
|
|
@@ -7299,7 +6927,7 @@ function useRecordingMode({
|
|
|
7299
6927
|
setPhase("active");
|
|
7300
6928
|
persistSnapshot({ steps: nextSteps, phase: "active" });
|
|
7301
6929
|
}, [persistSnapshot, voice]);
|
|
7302
|
-
const previewSteps =
|
|
6930
|
+
const previewSteps = useCallback9(() => {
|
|
7303
6931
|
if (steps.length === 0) {
|
|
7304
6932
|
safeSpeak("No steps recorded yet.");
|
|
7305
6933
|
return;
|
|
@@ -7307,13 +6935,13 @@ function useRecordingMode({
|
|
|
7307
6935
|
onPreview?.(steps);
|
|
7308
6936
|
safeSpeak(`Previewing ${steps.length} step${steps.length !== 1 ? "s" : ""}.`);
|
|
7309
6937
|
}, [onPreview, safeSpeak, steps]);
|
|
7310
|
-
const prepareToStopRecording =
|
|
6938
|
+
const prepareToStopRecording = useCallback9(() => {
|
|
7311
6939
|
shouldKeepVoiceCaptureRef.current = false;
|
|
7312
6940
|
resumeVoiceAfterNarrationRef.current = false;
|
|
7313
6941
|
stopBackgroundVoiceCapture();
|
|
7314
6942
|
persistSnapshot({ voiceCaptureEnabled: false });
|
|
7315
6943
|
}, [persistSnapshot, stopBackgroundVoiceCapture]);
|
|
7316
|
-
const cancelRecording =
|
|
6944
|
+
const cancelRecording = useCallback9(() => {
|
|
7317
6945
|
shouldKeepVoiceCaptureRef.current = false;
|
|
7318
6946
|
stopBackgroundVoiceCapture();
|
|
7319
6947
|
phaseRef.current = "idle";
|
|
@@ -7331,7 +6959,7 @@ function useRecordingMode({
|
|
|
7331
6959
|
clearPersistedRecordingSession();
|
|
7332
6960
|
safeSpeak("Recording cancelled.");
|
|
7333
6961
|
}, [safeSpeak, stopBackgroundVoiceCapture]);
|
|
7334
|
-
|
|
6962
|
+
useEffect14(() => {
|
|
7335
6963
|
if (!isRecording || typeof document === "undefined") return;
|
|
7336
6964
|
const handleMouseMove = (event) => {
|
|
7337
6965
|
const target = event.target;
|
|
@@ -7441,7 +7069,7 @@ function useRecordingMode({
|
|
|
7441
7069
|
window.clearInterval(routePoll);
|
|
7442
7070
|
};
|
|
7443
7071
|
}, [appendCaptureEvent, isRecording]);
|
|
7444
|
-
|
|
7072
|
+
useEffect14(() => {
|
|
7445
7073
|
if (!isRecording || typeof window === "undefined") return;
|
|
7446
7074
|
const flushRecordingSession = () => {
|
|
7447
7075
|
persistSnapshot();
|
|
@@ -7453,7 +7081,7 @@ function useRecordingMode({
|
|
|
7453
7081
|
window.removeEventListener("beforeunload", flushRecordingSession);
|
|
7454
7082
|
};
|
|
7455
7083
|
}, [isRecording, persistSnapshot]);
|
|
7456
|
-
const stopRecording =
|
|
7084
|
+
const stopRecording = useCallback9(async (tourName, targetUserTypes) => {
|
|
7457
7085
|
phaseRef.current = "finishing";
|
|
7458
7086
|
setPhase("finishing");
|
|
7459
7087
|
shouldKeepVoiceCaptureRef.current = false;
|
|
@@ -7527,7 +7155,7 @@ function useRecordingMode({
|
|
|
7527
7155
|
return null;
|
|
7528
7156
|
}
|
|
7529
7157
|
}, [capturedTranscript, experienceType, persistSnapshot, safeSpeak, serverUrl, stopBackgroundVoiceCapture, steps, toursApiBase, websiteId]);
|
|
7530
|
-
const toggleVoiceCapture =
|
|
7158
|
+
const toggleVoiceCapture = useCallback9(() => {
|
|
7531
7159
|
if (isVoiceCaptureActive || shouldKeepVoiceCaptureRef.current) {
|
|
7532
7160
|
shouldKeepVoiceCaptureRef.current = false;
|
|
7533
7161
|
stopBackgroundVoiceCapture();
|
|
@@ -7538,7 +7166,7 @@ function useRecordingMode({
|
|
|
7538
7166
|
persistSnapshot({ voiceCaptureEnabled: true });
|
|
7539
7167
|
startBackgroundVoiceCapture();
|
|
7540
7168
|
}, [isVoiceCaptureActive, persistSnapshot, startBackgroundVoiceCapture, stopBackgroundVoiceCapture]);
|
|
7541
|
-
|
|
7169
|
+
useEffect14(() => {
|
|
7542
7170
|
if (!isRecording) return;
|
|
7543
7171
|
if (phase === "active" && shouldKeepVoiceCaptureRef.current && !isVoiceCaptureActive) {
|
|
7544
7172
|
startBackgroundVoiceCapture();
|
|
@@ -7547,7 +7175,7 @@ function useRecordingMode({
|
|
|
7547
7175
|
stopBackgroundVoiceCapture();
|
|
7548
7176
|
}
|
|
7549
7177
|
}, [isRecording, isVoiceCaptureActive, phase, startBackgroundVoiceCapture, stopBackgroundVoiceCapture]);
|
|
7550
|
-
const handleVoiceCommand =
|
|
7178
|
+
const handleVoiceCommand = useCallback9((transcript) => {
|
|
7551
7179
|
const lower = transcript.toLowerCase().trim();
|
|
7552
7180
|
if (!isRecording) return;
|
|
7553
7181
|
if (lower.includes("mark step") && phase === "active") {
|
|
@@ -7609,7 +7237,7 @@ function useRecordingMode({
|
|
|
7609
7237
|
}
|
|
7610
7238
|
|
|
7611
7239
|
// src/components/RecordingOverlay.tsx
|
|
7612
|
-
import { useEffect as
|
|
7240
|
+
import { useEffect as useEffect15, useState as useState11, useCallback as useCallback10 } from "react";
|
|
7613
7241
|
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
7614
7242
|
function buildFingerprint(el) {
|
|
7615
7243
|
const tag = el.tagName.toLowerCase();
|
|
@@ -7637,8 +7265,8 @@ var panelBase = {
|
|
|
7637
7265
|
color: "#18181b"
|
|
7638
7266
|
};
|
|
7639
7267
|
function ActiveHUD({ stepCount, captureEventCount, isVoiceCaptureActive, minimized, onToggleVoiceCapture, onToggleMinimized, onStop, onCancel }) {
|
|
7640
|
-
const [hasActivatedVoiceCapture, setHasActivatedVoiceCapture] =
|
|
7641
|
-
|
|
7268
|
+
const [hasActivatedVoiceCapture, setHasActivatedVoiceCapture] = useState11(isVoiceCaptureActive);
|
|
7269
|
+
useEffect15(() => {
|
|
7642
7270
|
if (isVoiceCaptureActive) {
|
|
7643
7271
|
setHasActivatedVoiceCapture(true);
|
|
7644
7272
|
}
|
|
@@ -7883,8 +7511,8 @@ var STEP_TYPES_ADVANCED = [
|
|
|
7883
7511
|
];
|
|
7884
7512
|
function StepPopover({ element, stepIndex, onConfirm, onCancel }) {
|
|
7885
7513
|
const defaultType = element && ["INPUT", "SELECT", "TEXTAREA"].includes(element.el.tagName) ? "ask_or_fill" : "narrate";
|
|
7886
|
-
const [selected, setSelected] =
|
|
7887
|
-
const [showAdvanced, setShowAdvanced] =
|
|
7514
|
+
const [selected, setSelected] = useState11(defaultType);
|
|
7515
|
+
const [showAdvanced, setShowAdvanced] = useState11(false);
|
|
7888
7516
|
const hasTestId = !!element?.testId;
|
|
7889
7517
|
const allTypes = showAdvanced ? [...STEP_TYPES_PRIMARY, ...STEP_TYPES_ADVANCED] : STEP_TYPES_PRIMARY;
|
|
7890
7518
|
const popoverStyle = {
|
|
@@ -8028,8 +7656,8 @@ function StepPopover({ element, stepIndex, onConfirm, onCancel }) {
|
|
|
8028
7656
|
] });
|
|
8029
7657
|
}
|
|
8030
7658
|
function NarrationPanel({ stepIndex, stepCount, pendingNarration, isListening, onSubmitText, onCancel, onStopRecording }) {
|
|
8031
|
-
const [textInput, setTextInput] =
|
|
8032
|
-
const [showTextInput, setShowTextInput] =
|
|
7659
|
+
const [textInput, setTextInput] = useState11("");
|
|
7660
|
+
const [showTextInput, setShowTextInput] = useState11(false);
|
|
8033
7661
|
const audioLevels = useAudioLevel(isListening);
|
|
8034
7662
|
return /* @__PURE__ */ jsxs2(
|
|
8035
7663
|
"div",
|
|
@@ -8196,8 +7824,8 @@ function NarrationPanel({ stepIndex, stepCount, pendingNarration, isListening, o
|
|
|
8196
7824
|
);
|
|
8197
7825
|
}
|
|
8198
7826
|
function ReviewPanel({ stepIndex, stepCount, polishedNarration, rawNarration, onApprove, onRedo, onEdit }) {
|
|
8199
|
-
const [editMode, setEditMode] =
|
|
8200
|
-
const [editText, setEditText] =
|
|
7827
|
+
const [editMode, setEditMode] = useState11(false);
|
|
7828
|
+
const [editText, setEditText] = useState11(polishedNarration || rawNarration);
|
|
8201
7829
|
const displayText = polishedNarration || rawNarration;
|
|
8202
7830
|
return /* @__PURE__ */ jsxs2(
|
|
8203
7831
|
"div",
|
|
@@ -8453,7 +8081,7 @@ function FinishingPanel() {
|
|
|
8453
8081
|
}
|
|
8454
8082
|
);
|
|
8455
8083
|
}
|
|
8456
|
-
var
|
|
8084
|
+
var INTERACTIVE_SELECTOR = [
|
|
8457
8085
|
"button",
|
|
8458
8086
|
"a[href]",
|
|
8459
8087
|
'input:not([type="hidden"])',
|
|
@@ -8491,19 +8119,19 @@ function RecordingOverlay({
|
|
|
8491
8119
|
onCancelRecording,
|
|
8492
8120
|
onStopRecording
|
|
8493
8121
|
}) {
|
|
8494
|
-
const [hoveredEl, setHoveredEl] =
|
|
8495
|
-
const [pendingElement, setPendingElement] =
|
|
8496
|
-
const [showPopover, setShowPopover] =
|
|
8497
|
-
const [hudMinimized, setHudMinimized] =
|
|
8498
|
-
const [voicePanelMinimized, setVoicePanelMinimized] =
|
|
8122
|
+
const [hoveredEl, setHoveredEl] = useState11(null);
|
|
8123
|
+
const [pendingElement, setPendingElement] = useState11(null);
|
|
8124
|
+
const [showPopover, setShowPopover] = useState11(false);
|
|
8125
|
+
const [hudMinimized, setHudMinimized] = useState11(false);
|
|
8126
|
+
const [voicePanelMinimized, setVoicePanelMinimized] = useState11(false);
|
|
8499
8127
|
const isSelecting = phase === "selecting";
|
|
8500
|
-
const handleMouseMove =
|
|
8501
|
-
const target = e.target.closest(
|
|
8128
|
+
const handleMouseMove = useCallback10((e) => {
|
|
8129
|
+
const target = e.target.closest(INTERACTIVE_SELECTOR);
|
|
8502
8130
|
setHoveredEl(target);
|
|
8503
8131
|
}, []);
|
|
8504
|
-
const handleClick =
|
|
8132
|
+
const handleClick = useCallback10((e) => {
|
|
8505
8133
|
if (e.target.closest("[data-modelnex-internal]")) return;
|
|
8506
|
-
const target = e.target.closest(
|
|
8134
|
+
const target = e.target.closest(INTERACTIVE_SELECTOR);
|
|
8507
8135
|
if (target) {
|
|
8508
8136
|
e.preventDefault();
|
|
8509
8137
|
e.stopPropagation();
|
|
@@ -8526,7 +8154,7 @@ function RecordingOverlay({
|
|
|
8526
8154
|
setShowPopover(true);
|
|
8527
8155
|
}
|
|
8528
8156
|
}, []);
|
|
8529
|
-
|
|
8157
|
+
useEffect15(() => {
|
|
8530
8158
|
if (!isSelecting) return;
|
|
8531
8159
|
document.addEventListener("mousemove", handleMouseMove, true);
|
|
8532
8160
|
document.addEventListener("click", handleClick, true);
|
|
@@ -8538,14 +8166,14 @@ function RecordingOverlay({
|
|
|
8538
8166
|
document.body.style.cursor = prev;
|
|
8539
8167
|
};
|
|
8540
8168
|
}, [isSelecting, handleMouseMove, handleClick]);
|
|
8541
|
-
|
|
8169
|
+
useEffect15(() => {
|
|
8542
8170
|
if (isSelecting) {
|
|
8543
8171
|
setShowPopover(false);
|
|
8544
8172
|
setPendingElement(null);
|
|
8545
8173
|
setHoveredEl(null);
|
|
8546
8174
|
}
|
|
8547
8175
|
}, [isSelecting]);
|
|
8548
|
-
const handlePopoverConfirm =
|
|
8176
|
+
const handlePopoverConfirm = useCallback10((type) => {
|
|
8549
8177
|
setShowPopover(false);
|
|
8550
8178
|
if (pendingElement) {
|
|
8551
8179
|
onElementSelected(pendingElement);
|
|
@@ -8555,7 +8183,7 @@ function RecordingOverlay({
|
|
|
8555
8183
|
onStepTypeConfirmed(type);
|
|
8556
8184
|
onStartNarration();
|
|
8557
8185
|
}, [pendingElement, onElementSelected, onPageLevelStep, onStepTypeConfirmed, onStartNarration]);
|
|
8558
|
-
const handlePopoverCancel =
|
|
8186
|
+
const handlePopoverCancel = useCallback10(() => {
|
|
8559
8187
|
setShowPopover(false);
|
|
8560
8188
|
setPendingElement(null);
|
|
8561
8189
|
}, []);
|
|
@@ -9102,8 +8730,8 @@ function getViewportHeight() {
|
|
|
9102
8730
|
return layoutViewportHeight;
|
|
9103
8731
|
}
|
|
9104
8732
|
function useViewportHeight() {
|
|
9105
|
-
const [viewportHeight, setViewportHeight] =
|
|
9106
|
-
|
|
8733
|
+
const [viewportHeight, setViewportHeight] = useState12(() => getViewportHeight());
|
|
8734
|
+
useEffect16(() => {
|
|
9107
8735
|
if (typeof window === "undefined") return;
|
|
9108
8736
|
const updateViewportHeight = () => {
|
|
9109
8737
|
setViewportHeight(getViewportHeight());
|
|
@@ -9122,8 +8750,8 @@ function useViewportHeight() {
|
|
|
9122
8750
|
return viewportHeight;
|
|
9123
8751
|
}
|
|
9124
8752
|
function useMediaQuery(query) {
|
|
9125
|
-
const [matches, setMatches] =
|
|
9126
|
-
|
|
8753
|
+
const [matches, setMatches] = useState12(false);
|
|
8754
|
+
useEffect16(() => {
|
|
9127
8755
|
const media = window.matchMedia(query);
|
|
9128
8756
|
if (media.matches !== matches) setMatches(media.matches);
|
|
9129
8757
|
const listener = () => setMatches(media.matches);
|
|
@@ -9195,8 +8823,8 @@ var GLOBAL_STYLES = `
|
|
|
9195
8823
|
}
|
|
9196
8824
|
`;
|
|
9197
8825
|
function Tooltip({ children, title }) {
|
|
9198
|
-
const [show, setShow] =
|
|
9199
|
-
const ref =
|
|
8826
|
+
const [show, setShow] = useState12(false);
|
|
8827
|
+
const ref = useRef12(null);
|
|
9200
8828
|
const handleShow = () => setShow(true);
|
|
9201
8829
|
const handleHide = () => setShow(false);
|
|
9202
8830
|
return /* @__PURE__ */ jsxs3(
|
|
@@ -9290,11 +8918,11 @@ var TrashIcon = () => /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16",
|
|
|
9290
8918
|
var StopIcon = () => /* @__PURE__ */ jsx4("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx4("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }) });
|
|
9291
8919
|
var ChevronDown = ({ open }) => /* @__PURE__ */ jsx4("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", style: { transform: open ? "rotate(180deg)" : "none", transition: "transform 0.2s" }, children: /* @__PURE__ */ jsx4("path", { d: "m6 9 6 6 6-6" }) });
|
|
9292
8920
|
function AgentTraces({ debug, command, defaultExpanded = true }) {
|
|
9293
|
-
const [expanded, setExpanded] =
|
|
9294
|
-
const [expandedSteps, setExpandedSteps] =
|
|
8921
|
+
const [expanded, setExpanded] = useState12(defaultExpanded);
|
|
8922
|
+
const [expandedSteps, setExpandedSteps] = useState12(/* @__PURE__ */ new Set());
|
|
9295
8923
|
const traces = debug.traces ?? [];
|
|
9296
8924
|
const hasTraceContent = traces.length > 0 || debug.llmInput || (debug.llmOutput?.length ?? 0) > 0 || (debug.actions?.length ?? 0) > 0;
|
|
9297
|
-
|
|
8925
|
+
useEffect16(() => {
|
|
9298
8926
|
setExpandedSteps(new Set(traces.map((t) => t.step)));
|
|
9299
8927
|
}, [debug]);
|
|
9300
8928
|
const toggleStep = (step) => {
|
|
@@ -9455,21 +9083,21 @@ function ModelNexChatBubble({
|
|
|
9455
9083
|
}) {
|
|
9456
9084
|
const onCommand = void 0;
|
|
9457
9085
|
const recordingExperienceType = "tour";
|
|
9458
|
-
const noop =
|
|
9459
|
-
const noopAsync =
|
|
9086
|
+
const noop = useCallback11(() => void 0, []);
|
|
9087
|
+
const noopAsync = useCallback11(async () => void 0, []);
|
|
9460
9088
|
const runCommand = useRunCommand();
|
|
9461
9089
|
const ctx = useContext5(ModelNexContext);
|
|
9462
|
-
const [hydrated, setHydrated] =
|
|
9463
|
-
const [expanded, setExpanded] =
|
|
9464
|
-
const [docked, setDocked] =
|
|
9465
|
-
const [input, setInput] =
|
|
9090
|
+
const [hydrated, setHydrated] = useState12(false);
|
|
9091
|
+
const [expanded, setExpanded] = useState12(false);
|
|
9092
|
+
const [docked, setDocked] = useState12(false);
|
|
9093
|
+
const [input, setInput] = useState12("");
|
|
9466
9094
|
const messages = ctx?.chatMessages ?? [];
|
|
9467
9095
|
const setMessages = ctx?.setChatMessages ?? (() => {
|
|
9468
9096
|
});
|
|
9469
|
-
const [loading, setLoading] =
|
|
9470
|
-
const messagesEndRef =
|
|
9471
|
-
const abortControllerRef =
|
|
9472
|
-
const panelRef =
|
|
9097
|
+
const [loading, setLoading] = useState12(false);
|
|
9098
|
+
const messagesEndRef = useRef12(null);
|
|
9099
|
+
const abortControllerRef = useRef12(null);
|
|
9100
|
+
const panelRef = useRef12(null);
|
|
9473
9101
|
const serverUrl = ctx?.serverUrl ?? DEFAULT_MODELNEX_SERVER_URL;
|
|
9474
9102
|
const voice = useVoice(serverUrl);
|
|
9475
9103
|
const audioLevels = useAudioLevel(voice.isListening);
|
|
@@ -9478,13 +9106,13 @@ function ModelNexChatBubble({
|
|
|
9478
9106
|
});
|
|
9479
9107
|
const devMode = ctx?.devMode ?? false;
|
|
9480
9108
|
const authoringMode = ctx?.authoringMode ?? devMode;
|
|
9481
|
-
const [recordingTourName, setRecordingTourName] =
|
|
9482
|
-
const [recordingTargetTypes, setRecordingTargetTypes] =
|
|
9483
|
-
const [showStopModal, setShowStopModal] =
|
|
9484
|
-
const [savedDraft, setSavedDraft] =
|
|
9485
|
-
const [reviewDraft, setReviewDraft] =
|
|
9486
|
-
const [tourLiveTranscript, setTourLiveTranscript] =
|
|
9487
|
-
const [activeRecordingExperienceType, setActiveRecordingExperienceType] =
|
|
9109
|
+
const [recordingTourName, setRecordingTourName] = useState12("");
|
|
9110
|
+
const [recordingTargetTypes, setRecordingTargetTypes] = useState12("admin");
|
|
9111
|
+
const [showStopModal, setShowStopModal] = useState12(false);
|
|
9112
|
+
const [savedDraft, setSavedDraft] = useState12(null);
|
|
9113
|
+
const [reviewDraft, setReviewDraft] = useState12("");
|
|
9114
|
+
const [tourLiveTranscript, setTourLiveTranscript] = useState12("");
|
|
9115
|
+
const [activeRecordingExperienceType, setActiveRecordingExperienceType] = useState12(
|
|
9488
9116
|
() => readPersistedRecordingExperienceType() ?? recordingExperienceType
|
|
9489
9117
|
);
|
|
9490
9118
|
const recording = useRecordingMode({
|
|
@@ -9496,7 +9124,7 @@ function ModelNexChatBubble({
|
|
|
9496
9124
|
});
|
|
9497
9125
|
const isGeneratingDraft = isRecordingDraftGenerating(recording.phase);
|
|
9498
9126
|
const showRecordingOverlay = recordingMode && shouldShowRecordingOverlay(recording.phase);
|
|
9499
|
-
|
|
9127
|
+
useEffect16(() => {
|
|
9500
9128
|
const shouldBeRecording = recording.phase !== "idle";
|
|
9501
9129
|
if (shouldBeRecording && !recordingMode) {
|
|
9502
9130
|
setRecordingMode(true);
|
|
@@ -9529,12 +9157,12 @@ function ModelNexChatBubble({
|
|
|
9529
9157
|
const activePlayback = playbackController.playback;
|
|
9530
9158
|
const activeExperienceType = playbackController.activeExperienceType;
|
|
9531
9159
|
const startingExperienceType = playbackController.startingExperienceType;
|
|
9532
|
-
|
|
9160
|
+
useEffect16(() => {
|
|
9533
9161
|
return registerExperienceToolBridge({
|
|
9534
9162
|
startExperience: playbackController.startExperience
|
|
9535
9163
|
});
|
|
9536
9164
|
}, [playbackController.startExperience]);
|
|
9537
|
-
const createPlaybackView =
|
|
9165
|
+
const createPlaybackView = useCallback11((experienceType) => {
|
|
9538
9166
|
const isActiveExperience = activePlayback.isActive && activeExperienceType === experienceType;
|
|
9539
9167
|
const pendingTour = playbackController.pendingPrompt?.experienceType === experienceType ? playbackController.pendingPrompt.tour : null;
|
|
9540
9168
|
return {
|
|
@@ -9566,8 +9194,8 @@ function ModelNexChatBubble({
|
|
|
9566
9194
|
const onboardingPlayback = useMemo3(() => createPlaybackView("onboarding"), [createPlaybackView]);
|
|
9567
9195
|
const tourReviewToggle = getReviewModeToggleConfig(tourPlayback.playbackState);
|
|
9568
9196
|
const tourReviewModeEnabled = isReviewModeEnabled(devMode, tourPlayback.isReviewMode);
|
|
9569
|
-
const lastAutoTaggedUrlRef =
|
|
9570
|
-
const handleAutoTag =
|
|
9197
|
+
const lastAutoTaggedUrlRef = useRef12(null);
|
|
9198
|
+
const handleAutoTag = useCallback11(async () => {
|
|
9571
9199
|
if (!ctx) return;
|
|
9572
9200
|
const { extractedElements, tagStore, commandUrl, serverUrl: serverUrl2, websiteId } = ctx;
|
|
9573
9201
|
if (extractedElements.length === 0) return;
|
|
@@ -9606,7 +9234,7 @@ function ModelNexChatBubble({
|
|
|
9606
9234
|
console.warn("[ModelNex] Auto-tag error:", err);
|
|
9607
9235
|
}
|
|
9608
9236
|
}, [ctx]);
|
|
9609
|
-
|
|
9237
|
+
useEffect16(() => {
|
|
9610
9238
|
if (authoringMode && ctx?.extractedElements.length) {
|
|
9611
9239
|
const timer = setTimeout(handleAutoTag, 1e3);
|
|
9612
9240
|
return () => clearTimeout(timer);
|
|
@@ -9628,7 +9256,7 @@ function ModelNexChatBubble({
|
|
|
9628
9256
|
recordingMode,
|
|
9629
9257
|
pendingNotificationType
|
|
9630
9258
|
});
|
|
9631
|
-
|
|
9259
|
+
useEffect16(() => {
|
|
9632
9260
|
setHydrated(true);
|
|
9633
9261
|
try {
|
|
9634
9262
|
setExpanded(sessionStorage.getItem(BUBBLE_EXPANDED_STORAGE_KEY) === "true");
|
|
@@ -9638,18 +9266,18 @@ function ModelNexChatBubble({
|
|
|
9638
9266
|
setDocked(false);
|
|
9639
9267
|
}
|
|
9640
9268
|
}, []);
|
|
9641
|
-
const sttActiveRef =
|
|
9642
|
-
const [tourListenReady, setTourListenReady] =
|
|
9643
|
-
const [tourSttError, setTourSttError] =
|
|
9644
|
-
const previousTourActiveRef =
|
|
9645
|
-
const tourListenReadyRef =
|
|
9646
|
-
const tourSttErrorRef =
|
|
9647
|
-
const updateTourListenReady =
|
|
9269
|
+
const sttActiveRef = useRef12(false);
|
|
9270
|
+
const [tourListenReady, setTourListenReady] = useState12(false);
|
|
9271
|
+
const [tourSttError, setTourSttError] = useState12(null);
|
|
9272
|
+
const previousTourActiveRef = useRef12(false);
|
|
9273
|
+
const tourListenReadyRef = useRef12(false);
|
|
9274
|
+
const tourSttErrorRef = useRef12(null);
|
|
9275
|
+
const updateTourListenReady = useCallback11((next) => {
|
|
9648
9276
|
if (tourListenReadyRef.current === next) return;
|
|
9649
9277
|
tourListenReadyRef.current = next;
|
|
9650
9278
|
setTourListenReady(next);
|
|
9651
9279
|
}, []);
|
|
9652
|
-
const updateTourSttError =
|
|
9280
|
+
const updateTourSttError = useCallback11((next) => {
|
|
9653
9281
|
if (tourSttErrorRef.current === next) return;
|
|
9654
9282
|
tourSttErrorRef.current = next;
|
|
9655
9283
|
setTourSttError(next);
|
|
@@ -9658,7 +9286,7 @@ function ModelNexChatBubble({
|
|
|
9658
9286
|
() => buildTranscriptPreviewLines(tourLiveTranscript, { maxCharsPerLine: 36, maxLines: 2 }),
|
|
9659
9287
|
[tourLiveTranscript]
|
|
9660
9288
|
);
|
|
9661
|
-
|
|
9289
|
+
useEffect16(() => {
|
|
9662
9290
|
const shouldShowFloatingTranscript = (tourPlayback.isActive || onboardingPlayback.isActive) && tourListenReady && voice.isListening;
|
|
9663
9291
|
if (shouldShowFloatingTranscript) {
|
|
9664
9292
|
showFloatingLiveTranscript({
|
|
@@ -9680,10 +9308,10 @@ function ModelNexChatBubble({
|
|
|
9680
9308
|
tourPlayback.isActive,
|
|
9681
9309
|
voice.isListening
|
|
9682
9310
|
]);
|
|
9683
|
-
|
|
9311
|
+
useEffect16(() => () => {
|
|
9684
9312
|
hideFloatingLiveTranscript();
|
|
9685
9313
|
}, []);
|
|
9686
|
-
const setExpandedState =
|
|
9314
|
+
const setExpandedState = useCallback11((next, opts) => {
|
|
9687
9315
|
setExpanded(next);
|
|
9688
9316
|
try {
|
|
9689
9317
|
sessionStorage.setItem(BUBBLE_EXPANDED_STORAGE_KEY, String(next));
|
|
@@ -9695,14 +9323,14 @@ function ModelNexChatBubble({
|
|
|
9695
9323
|
} catch {
|
|
9696
9324
|
}
|
|
9697
9325
|
}, [tourPlayback.isActive, onboardingPlayback.isActive]);
|
|
9698
|
-
const setDockedState =
|
|
9326
|
+
const setDockedState = useCallback11((next) => {
|
|
9699
9327
|
setDocked(next);
|
|
9700
9328
|
try {
|
|
9701
9329
|
sessionStorage.setItem(BUBBLE_DOCKED_STORAGE_KEY, String(next));
|
|
9702
9330
|
} catch {
|
|
9703
9331
|
}
|
|
9704
9332
|
}, []);
|
|
9705
|
-
|
|
9333
|
+
useEffect16(() => {
|
|
9706
9334
|
if (shouldAutoExpandForPendingPrompt({
|
|
9707
9335
|
pendingPrompt,
|
|
9708
9336
|
isPlaybackActive,
|
|
@@ -9712,8 +9340,8 @@ function ModelNexChatBubble({
|
|
|
9712
9340
|
setExpandedState(true);
|
|
9713
9341
|
}
|
|
9714
9342
|
}, [isPlaybackActive, pendingNotificationType, pendingPrompt, recordingMode, setExpandedState]);
|
|
9715
|
-
const preferredListeningExperienceRef =
|
|
9716
|
-
const playbackVoiceRoutingRef =
|
|
9343
|
+
const preferredListeningExperienceRef = useRef12(null);
|
|
9344
|
+
const playbackVoiceRoutingRef = useRef12({
|
|
9717
9345
|
activeExperienceType,
|
|
9718
9346
|
isActive: activePlayback.isActive,
|
|
9719
9347
|
isReviewMode: activePlayback.isReviewMode,
|
|
@@ -9721,7 +9349,7 @@ function ModelNexChatBubble({
|
|
|
9721
9349
|
playbackState: activePlayback.playbackState,
|
|
9722
9350
|
handleVoiceInput: playbackController.handleVoiceInput
|
|
9723
9351
|
});
|
|
9724
|
-
|
|
9352
|
+
useEffect16(() => {
|
|
9725
9353
|
playbackVoiceRoutingRef.current = {
|
|
9726
9354
|
activeExperienceType,
|
|
9727
9355
|
isActive: activePlayback.isActive,
|
|
@@ -9738,7 +9366,7 @@ function ModelNexChatBubble({
|
|
|
9738
9366
|
playbackController.handleVoiceInput,
|
|
9739
9367
|
playbackController.pendingPrompt?.experienceType
|
|
9740
9368
|
]);
|
|
9741
|
-
const handleVoiceTourInput =
|
|
9369
|
+
const handleVoiceTourInput = useCallback11(createSinglePlaybackTranscriptRouter(
|
|
9742
9370
|
() => ({
|
|
9743
9371
|
isReviewMode: playbackVoiceRoutingRef.current.isReviewMode,
|
|
9744
9372
|
playbackState: playbackVoiceRoutingRef.current.playbackState
|
|
@@ -9753,7 +9381,7 @@ function ModelNexChatBubble({
|
|
|
9753
9381
|
}
|
|
9754
9382
|
}
|
|
9755
9383
|
), []);
|
|
9756
|
-
const startTourListening =
|
|
9384
|
+
const startTourListening = useCallback11((preferredExperience) => {
|
|
9757
9385
|
const listeningState = {
|
|
9758
9386
|
isTourActive: tourPlayback.isActive,
|
|
9759
9387
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
@@ -9808,7 +9436,7 @@ function ModelNexChatBubble({
|
|
|
9808
9436
|
updateTourListenReady,
|
|
9809
9437
|
updateTourSttError
|
|
9810
9438
|
]);
|
|
9811
|
-
|
|
9439
|
+
useEffect16(() => {
|
|
9812
9440
|
const isPlaybackActive2 = isTourListeningSessionActive({
|
|
9813
9441
|
isTourActive: tourPlayback.isActive,
|
|
9814
9442
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
@@ -9831,12 +9459,12 @@ function ModelNexChatBubble({
|
|
|
9831
9459
|
}
|
|
9832
9460
|
}
|
|
9833
9461
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, setExpandedState, startingExperienceType, updateTourSttError]);
|
|
9834
|
-
|
|
9462
|
+
useEffect16(() => {
|
|
9835
9463
|
if (!tourPlayback.isReviewMode && !onboardingPlayback.isReviewMode) {
|
|
9836
9464
|
setReviewDraft("");
|
|
9837
9465
|
}
|
|
9838
9466
|
}, [tourPlayback.isReviewMode, onboardingPlayback.isReviewMode]);
|
|
9839
|
-
|
|
9467
|
+
useEffect16(() => {
|
|
9840
9468
|
if (!isTourListeningSessionActive({
|
|
9841
9469
|
isTourActive: tourPlayback.isActive,
|
|
9842
9470
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
@@ -9845,12 +9473,12 @@ function ModelNexChatBubble({
|
|
|
9845
9473
|
preferredListeningExperienceRef.current = null;
|
|
9846
9474
|
}
|
|
9847
9475
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, startingExperienceType]);
|
|
9848
|
-
|
|
9476
|
+
useEffect16(() => {
|
|
9849
9477
|
if (recordingMode) {
|
|
9850
9478
|
setExpandedState(false);
|
|
9851
9479
|
}
|
|
9852
9480
|
}, [recordingMode, setExpandedState]);
|
|
9853
|
-
|
|
9481
|
+
useEffect16(() => {
|
|
9854
9482
|
const isPlaybackActive2 = isTourListeningSessionActive({
|
|
9855
9483
|
isTourActive: tourPlayback.isActive,
|
|
9856
9484
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
@@ -9864,7 +9492,7 @@ function ModelNexChatBubble({
|
|
|
9864
9492
|
}
|
|
9865
9493
|
updateTourListenReady(Boolean(voice.isListening && sttActiveRef.current));
|
|
9866
9494
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, voice.isListening, startingExperienceType, updateTourListenReady]);
|
|
9867
|
-
|
|
9495
|
+
useEffect16(() => {
|
|
9868
9496
|
const isPlaybackActive2 = isTourListeningSessionActive({
|
|
9869
9497
|
isTourActive: tourPlayback.isActive,
|
|
9870
9498
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
@@ -9879,7 +9507,7 @@ function ModelNexChatBubble({
|
|
|
9879
9507
|
voice.stopListening();
|
|
9880
9508
|
}
|
|
9881
9509
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, voice, startingExperienceType, updateTourListenReady, updateTourSttError]);
|
|
9882
|
-
|
|
9510
|
+
useEffect16(() => {
|
|
9883
9511
|
const isPlaybackActive2 = isTourListeningSessionActive({
|
|
9884
9512
|
isTourActive: tourPlayback.isActive,
|
|
9885
9513
|
isOnboardingActive: onboardingPlayback.isActive,
|
|
@@ -9901,8 +9529,8 @@ function ModelNexChatBubble({
|
|
|
9901
9529
|
window.removeEventListener("keydown", enableTourListeningFromGesture, true);
|
|
9902
9530
|
};
|
|
9903
9531
|
}, [tourPlayback.isActive, onboardingPlayback.isActive, tourListenReady, tourSttError, voice.sttSupported, startTourListening, startingExperienceType]);
|
|
9904
|
-
const [voiceInputMode, setVoiceInputMode] =
|
|
9905
|
-
const toggleVoiceInput =
|
|
9532
|
+
const [voiceInputMode, setVoiceInputMode] = useState12(false);
|
|
9533
|
+
const toggleVoiceInput = useCallback11(() => {
|
|
9906
9534
|
if (voiceInputMode) {
|
|
9907
9535
|
voice.stopListening();
|
|
9908
9536
|
setVoiceInputMode(false);
|
|
@@ -9925,7 +9553,7 @@ function ModelNexChatBubble({
|
|
|
9925
9553
|
);
|
|
9926
9554
|
}
|
|
9927
9555
|
}, [voiceInputMode, voice, recordingMode, recording]);
|
|
9928
|
-
|
|
9556
|
+
useEffect16(() => {
|
|
9929
9557
|
const panel = panelRef.current;
|
|
9930
9558
|
if (!panel) return;
|
|
9931
9559
|
const stopKeyPropagation = (e) => {
|
|
@@ -9949,7 +9577,7 @@ function ModelNexChatBubble({
|
|
|
9949
9577
|
const tourCompletionRatio = tourPlayback.totalSteps > 0 ? Math.min(tourPlayback.currentStepIndex / tourPlayback.totalSteps, 1) : 0;
|
|
9950
9578
|
const tourCurrentStep = tourPlayback.activeTour?.steps?.[tourPlayback.currentStepIndex] || null;
|
|
9951
9579
|
const scrollToBottom = () => messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
9952
|
-
|
|
9580
|
+
useEffect16(() => {
|
|
9953
9581
|
if (messages.length > 0) scrollToBottom();
|
|
9954
9582
|
}, [messages, loading]);
|
|
9955
9583
|
const runAgent = async () => {
|
|
@@ -10006,7 +9634,7 @@ function ModelNexChatBubble({
|
|
|
10006
9634
|
const clearChat = () => {
|
|
10007
9635
|
setMessages([]);
|
|
10008
9636
|
};
|
|
10009
|
-
const startRecordingSession =
|
|
9637
|
+
const startRecordingSession = useCallback11((experienceType) => {
|
|
10010
9638
|
abortControllerRef.current?.abort();
|
|
10011
9639
|
abortControllerRef.current = null;
|
|
10012
9640
|
setLoading(false);
|
|
@@ -11259,7 +10887,7 @@ function ModelNexChatBubble({
|
|
|
11259
10887
|
}
|
|
11260
10888
|
|
|
11261
10889
|
// src/onboarding-panel.tsx
|
|
11262
|
-
import { useCallback as
|
|
10890
|
+
import { useCallback as useCallback12, useContext as useContext6, useEffect as useEffect17, useMemo as useMemo4, useRef as useRef13, useState as useState13 } from "react";
|
|
11263
10891
|
import { createPortal as createPortal2 } from "react-dom";
|
|
11264
10892
|
|
|
11265
10893
|
// src/hooks/useOnboardingPlayback.ts
|
|
@@ -11294,14 +10922,14 @@ function ModelNexOnboardingPanel({
|
|
|
11294
10922
|
const devMode = ctx?.devMode ?? false;
|
|
11295
10923
|
const voice = useVoice(serverUrl);
|
|
11296
10924
|
const audioLevels = useAudioLevel(voice.isListening);
|
|
11297
|
-
const [input, setInput] =
|
|
11298
|
-
const [reviewDraft, setReviewDraft] =
|
|
11299
|
-
const [open, setOpen] =
|
|
11300
|
-
const [currentStepIndex, setCurrentStepIndex] =
|
|
11301
|
-
const [liveTranscript, setLiveTranscript] =
|
|
11302
|
-
const [voiceEnabled, setVoiceEnabled] =
|
|
11303
|
-
const [sttError, setSttError] =
|
|
11304
|
-
const voiceEnabledRef =
|
|
10925
|
+
const [input, setInput] = useState13("");
|
|
10926
|
+
const [reviewDraft, setReviewDraft] = useState13("");
|
|
10927
|
+
const [open, setOpen] = useState13(true);
|
|
10928
|
+
const [currentStepIndex, setCurrentStepIndex] = useState13(0);
|
|
10929
|
+
const [liveTranscript, setLiveTranscript] = useState13("");
|
|
10930
|
+
const [voiceEnabled, setVoiceEnabled] = useState13(false);
|
|
10931
|
+
const [sttError, setSttError] = useState13(null);
|
|
10932
|
+
const voiceEnabledRef = useRef13(false);
|
|
11305
10933
|
const playback = useOnboardingPlayback({
|
|
11306
10934
|
serverUrl,
|
|
11307
10935
|
commandUrl: ctx?.commandUrl,
|
|
@@ -11321,26 +10949,26 @@ function ModelNexOnboardingPanel({
|
|
|
11321
10949
|
voiceEnabledRef.current = false;
|
|
11322
10950
|
}
|
|
11323
10951
|
});
|
|
11324
|
-
const playbackVoiceRoutingRef =
|
|
10952
|
+
const playbackVoiceRoutingRef = useRef13({
|
|
11325
10953
|
isReviewMode: false,
|
|
11326
10954
|
playbackState: playback.playbackState,
|
|
11327
10955
|
handleVoiceInput: playback.handleVoiceInput
|
|
11328
10956
|
});
|
|
11329
10957
|
const reviewToggle = getReviewModeToggleConfig(playback.playbackState);
|
|
11330
10958
|
const reviewModeEnabled = isReviewModeEnabled(devMode, playback.isReviewMode);
|
|
11331
|
-
|
|
10959
|
+
useEffect17(() => {
|
|
11332
10960
|
playbackVoiceRoutingRef.current = {
|
|
11333
10961
|
isReviewMode: playback.isReviewMode,
|
|
11334
10962
|
playbackState: playback.playbackState,
|
|
11335
10963
|
handleVoiceInput: playback.handleVoiceInput
|
|
11336
10964
|
};
|
|
11337
10965
|
}, [playback.isReviewMode, playback.playbackState, playback.handleVoiceInput]);
|
|
11338
|
-
|
|
10966
|
+
useEffect17(() => {
|
|
11339
10967
|
if (playback.isActive && !playback.isReviewMode) {
|
|
11340
10968
|
setOpen(true);
|
|
11341
10969
|
}
|
|
11342
10970
|
}, [playback.activeTour?.id, playback.isActive, playback.isReviewMode]);
|
|
11343
|
-
const startVoiceListening =
|
|
10971
|
+
const startVoiceListening = useCallback12(() => {
|
|
11344
10972
|
if (voiceEnabledRef.current || !voice.sttSupported) return;
|
|
11345
10973
|
voiceEnabledRef.current = true;
|
|
11346
10974
|
setVoiceEnabled(true);
|
|
@@ -11387,7 +11015,7 @@ function ModelNexOnboardingPanel({
|
|
|
11387
11015
|
}
|
|
11388
11016
|
);
|
|
11389
11017
|
}, [playback.isActive, voice]);
|
|
11390
|
-
|
|
11018
|
+
useEffect17(() => {
|
|
11391
11019
|
if (!playback.isActive || voiceEnabledRef.current || !voice.sttSupported) return;
|
|
11392
11020
|
const startOnGesture = (event) => {
|
|
11393
11021
|
if (shouldIgnorePanelGestureStart(event.target)) {
|
|
@@ -11402,7 +11030,7 @@ function ModelNexOnboardingPanel({
|
|
|
11402
11030
|
window.removeEventListener("keydown", startOnGesture, true);
|
|
11403
11031
|
};
|
|
11404
11032
|
}, [playback.isActive, voice.sttSupported, startVoiceListening]);
|
|
11405
|
-
|
|
11033
|
+
useEffect17(() => {
|
|
11406
11034
|
if (!playback.isActive && voiceEnabledRef.current) {
|
|
11407
11035
|
voiceEnabledRef.current = false;
|
|
11408
11036
|
setVoiceEnabled(false);
|
|
@@ -11422,7 +11050,7 @@ function ModelNexOnboardingPanel({
|
|
|
11422
11050
|
() => buildTranscriptPreviewLines(liveTranscript, { maxCharsPerLine: 34, maxLines: 2 }),
|
|
11423
11051
|
[liveTranscript]
|
|
11424
11052
|
);
|
|
11425
|
-
|
|
11053
|
+
useEffect17(() => {
|
|
11426
11054
|
if (voiceEnabled && voice.isListening) {
|
|
11427
11055
|
showFloatingLiveTranscript({
|
|
11428
11056
|
levels: audioLevels,
|
|
@@ -11436,7 +11064,7 @@ function ModelNexOnboardingPanel({
|
|
|
11436
11064
|
}
|
|
11437
11065
|
hideFloatingLiveTranscript();
|
|
11438
11066
|
}, [audioLevels, liveTranscriptLines, voiceEnabled, voice.isListening]);
|
|
11439
|
-
|
|
11067
|
+
useEffect17(() => () => {
|
|
11440
11068
|
hideFloatingLiveTranscript();
|
|
11441
11069
|
}, []);
|
|
11442
11070
|
const actionButtonStyle = {
|
|
@@ -12001,7 +11629,7 @@ var ModelNexProvider = ({
|
|
|
12001
11629
|
const serverUrl = serverUrlProp ?? DEFAULT_MODELNEX_SERVER_URL;
|
|
12002
11630
|
const commandUrl = void 0;
|
|
12003
11631
|
const disableSocket = false;
|
|
12004
|
-
|
|
11632
|
+
useEffect18(() => {
|
|
12005
11633
|
if (process.env.NODE_ENV !== "production" && !serverUrlProp) {
|
|
12006
11634
|
console.warn(
|
|
12007
11635
|
`[ModelNex SDK] ModelNexProvider is using the default server URL (${DEFAULT_MODELNEX_SERVER_URL}). Pass \`serverUrl\` explicitly in local development to avoid accidentally targeting the hosted backend.`
|
|
@@ -12009,21 +11637,21 @@ var ModelNexProvider = ({
|
|
|
12009
11637
|
}
|
|
12010
11638
|
}, [serverUrlProp]);
|
|
12011
11639
|
const renderedChildren = children;
|
|
12012
|
-
const [activeAgentActions, setActiveAgentActions] =
|
|
12013
|
-
const [stagingFields, setStagingFields] =
|
|
12014
|
-
const [executedFields, setExecutedFields] =
|
|
12015
|
-
const [highlightActions, setHighlightActions] =
|
|
12016
|
-
const [studioMode, setStudioMode] =
|
|
12017
|
-
const [recordingMode, setRecordingMode] =
|
|
12018
|
-
const [voiceMuted, setVoiceMuted] =
|
|
12019
|
-
const [socketId, setSocketId] =
|
|
12020
|
-
const [actions, setActions] =
|
|
12021
|
-
const [validatedBrowserDevMode, setValidatedBrowserDevMode] =
|
|
12022
|
-
const [resolvedDevModeKey, setResolvedDevModeKey] =
|
|
12023
|
-
const [previewRuntimeMode, setPreviewRuntimeMode] =
|
|
12024
|
-
|
|
12025
|
-
|
|
12026
|
-
|
|
11640
|
+
const [activeAgentActions, setActiveAgentActions] = useState14(/* @__PURE__ */ new Set());
|
|
11641
|
+
const [stagingFields, setStagingFields] = useState14(/* @__PURE__ */ new Set());
|
|
11642
|
+
const [executedFields, setExecutedFields] = useState14(/* @__PURE__ */ new Set());
|
|
11643
|
+
const [highlightActions, setHighlightActions] = useState14(false);
|
|
11644
|
+
const [studioMode, setStudioMode] = useState14(false);
|
|
11645
|
+
const [recordingMode, setRecordingMode] = useState14(() => hasPersistedRecordingSession());
|
|
11646
|
+
const [voiceMuted, setVoiceMuted] = useState14(false);
|
|
11647
|
+
const [socketId, setSocketId] = useState14(null);
|
|
11648
|
+
const [actions, setActions] = useState14(/* @__PURE__ */ new Map());
|
|
11649
|
+
const [validatedBrowserDevMode, setValidatedBrowserDevMode] = useState14(false);
|
|
11650
|
+
const [resolvedDevModeKey, setResolvedDevModeKey] = useState14(() => resolveInjectedDevModeKey());
|
|
11651
|
+
const [previewRuntimeMode, setPreviewRuntimeMode] = useState14(() => hasDraftPreviewModeSignal());
|
|
11652
|
+
useEffect18(() => observeInjectedDevModeKey(setResolvedDevModeKey), []);
|
|
11653
|
+
useEffect18(() => observeDraftPreviewModeSignal(setPreviewRuntimeMode), []);
|
|
11654
|
+
useEffect18(() => {
|
|
12027
11655
|
let cancelled = false;
|
|
12028
11656
|
if (!websiteId || !resolvedDevModeKey) {
|
|
12029
11657
|
setValidatedBrowserDevMode(false);
|
|
@@ -12040,14 +11668,14 @@ var ModelNexProvider = ({
|
|
|
12040
11668
|
};
|
|
12041
11669
|
}, [resolvedDevModeKey, serverUrl, websiteId]);
|
|
12042
11670
|
const effectiveDevMode = validatedBrowserDevMode || previewRuntimeMode;
|
|
12043
|
-
const registerAction =
|
|
11671
|
+
const registerAction = useCallback13((action) => {
|
|
12044
11672
|
setActions((prev) => {
|
|
12045
11673
|
const next = new Map(prev);
|
|
12046
11674
|
next.set(action.id, action);
|
|
12047
11675
|
return next;
|
|
12048
11676
|
});
|
|
12049
11677
|
}, []);
|
|
12050
|
-
const unregisterAction =
|
|
11678
|
+
const unregisterAction = useCallback13((id) => {
|
|
12051
11679
|
setActions((prev) => {
|
|
12052
11680
|
const next = new Map(prev);
|
|
12053
11681
|
next.delete(id);
|
|
@@ -12058,8 +11686,8 @@ var ModelNexProvider = ({
|
|
|
12058
11686
|
const tagStore = useTagStore({ serverUrl, websiteId });
|
|
12059
11687
|
useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl, websiteId, toursApiBase, userProfile);
|
|
12060
11688
|
const CHAT_STORAGE_KEY = "modelnex-chat-messages";
|
|
12061
|
-
const [chatMessages, setChatMessagesRaw] =
|
|
12062
|
-
|
|
11689
|
+
const [chatMessages, setChatMessagesRaw] = useState14([]);
|
|
11690
|
+
useEffect18(() => {
|
|
12063
11691
|
try {
|
|
12064
11692
|
const stored = sessionStorage.getItem(CHAT_STORAGE_KEY);
|
|
12065
11693
|
if (stored) {
|
|
@@ -12068,7 +11696,7 @@ var ModelNexProvider = ({
|
|
|
12068
11696
|
} catch {
|
|
12069
11697
|
}
|
|
12070
11698
|
}, [effectiveDevMode]);
|
|
12071
|
-
|
|
11699
|
+
useEffect18(() => {
|
|
12072
11700
|
setChatMessagesRaw((prev) => {
|
|
12073
11701
|
const next = sanitizeChatMessages(prev, effectiveDevMode);
|
|
12074
11702
|
try {
|
|
@@ -12078,7 +11706,7 @@ var ModelNexProvider = ({
|
|
|
12078
11706
|
return next;
|
|
12079
11707
|
});
|
|
12080
11708
|
}, [effectiveDevMode]);
|
|
12081
|
-
const setChatMessages =
|
|
11709
|
+
const setChatMessages = useCallback13((action) => {
|
|
12082
11710
|
setChatMessagesRaw((prev) => {
|
|
12083
11711
|
const resolved = typeof action === "function" ? action(prev) : action;
|
|
12084
11712
|
const next = sanitizeChatMessages(resolved, effectiveDevMode);
|
|
@@ -12104,14 +11732,14 @@ var ModelNexProvider = ({
|
|
|
12104
11732
|
devMode: effectiveDevMode
|
|
12105
11733
|
});
|
|
12106
11734
|
useFieldHighlight(stagingFields, executedFields, setExecutedFields);
|
|
12107
|
-
|
|
11735
|
+
useEffect18(() => {
|
|
12108
11736
|
document.body.classList.toggle("modelnex-highlight-actions", highlightActions);
|
|
12109
11737
|
return () => {
|
|
12110
11738
|
document.body.classList.remove("modelnex-highlight-actions");
|
|
12111
11739
|
};
|
|
12112
11740
|
}, [highlightActions]);
|
|
12113
|
-
const [mounted, setMounted] =
|
|
12114
|
-
|
|
11741
|
+
const [mounted, setMounted] = useState14(false);
|
|
11742
|
+
useEffect18(() => {
|
|
12115
11743
|
setMounted(true);
|
|
12116
11744
|
}, []);
|
|
12117
11745
|
const value = useMemo5(
|