@webless/agent 0.2.9 → 0.2.11
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/{chunk-7XB5OBTP.js → chunk-XAUJPXWR.js} +359 -114
- package/dist/chunk-XAUJPXWR.js.map +1 -0
- package/dist/embed.cjs +344 -96
- package/dist/embed.cjs.map +1 -1
- package/dist/embed.css +46 -0
- package/dist/embed.css.map +1 -1
- package/dist/embed.js +1 -1
- package/dist/index.cjs +146 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +146 -26
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +341 -96
- package/dist/react.cjs.map +1 -1
- package/dist/react.css +46 -0
- package/dist/react.css.map +1 -1
- package/dist/react.js +1 -1
- package/package.json +3 -2
- package/dist/chunk-7XB5OBTP.js.map +0 -1
|
@@ -186,6 +186,54 @@ function clearPersistedAgentSession(visitorSessionId, options) {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
// src/runtime/client.ts
|
|
189
|
+
function isTurnBoundary(event) {
|
|
190
|
+
return event.type === "session.waiting" || event.type === "session.completed" || event.type === "session.failed";
|
|
191
|
+
}
|
|
192
|
+
function applyMessageEvent(event, rendered, handlers) {
|
|
193
|
+
const step = mapStepLabel(event);
|
|
194
|
+
if (step) handlers.onStep?.(step.label, step.detail);
|
|
195
|
+
if (event.type === "session.failed") {
|
|
196
|
+
throw new Error(event.data.message || event.data.code);
|
|
197
|
+
}
|
|
198
|
+
if (event.type === "message.completed") {
|
|
199
|
+
handlers.onComplete?.();
|
|
200
|
+
}
|
|
201
|
+
if (event.type !== "message.appended") return rendered;
|
|
202
|
+
const { messageDelta, messageSoFar } = event.data;
|
|
203
|
+
let delta = messageDelta;
|
|
204
|
+
let next = rendered;
|
|
205
|
+
if (messageSoFar.startsWith(rendered)) {
|
|
206
|
+
delta = messageSoFar.slice(rendered.length);
|
|
207
|
+
next = messageSoFar;
|
|
208
|
+
} else if (messageDelta) {
|
|
209
|
+
next += messageDelta;
|
|
210
|
+
}
|
|
211
|
+
if (delta) handlers.onDelta(delta);
|
|
212
|
+
return next;
|
|
213
|
+
}
|
|
214
|
+
function latestTurnEvents(events) {
|
|
215
|
+
let startIndex = -1;
|
|
216
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
217
|
+
if (events[index]?.type === "message.received") {
|
|
218
|
+
startIndex = index;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return startIndex >= 0 ? events.slice(startIndex) : [];
|
|
223
|
+
}
|
|
224
|
+
function renderTurn(events) {
|
|
225
|
+
let rendered = "";
|
|
226
|
+
for (const event of events) {
|
|
227
|
+
if (event.type !== "message.appended") continue;
|
|
228
|
+
const { messageDelta, messageSoFar } = event.data;
|
|
229
|
+
if (messageSoFar.startsWith(rendered)) {
|
|
230
|
+
rendered = messageSoFar;
|
|
231
|
+
} else if (messageDelta) {
|
|
232
|
+
rendered += messageDelta;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return rendered;
|
|
236
|
+
}
|
|
189
237
|
function mapStepLabel(event) {
|
|
190
238
|
if (event.type !== "step.started") return null;
|
|
191
239
|
const stepIndex = event.data.stepIndex;
|
|
@@ -221,8 +269,13 @@ var AgentSession = class {
|
|
|
221
269
|
return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
|
|
222
270
|
}
|
|
223
271
|
reset() {
|
|
224
|
-
|
|
225
|
-
|
|
272
|
+
if (this.activeResponse) {
|
|
273
|
+
void this.activeResponse.cancel().catch(() => {
|
|
274
|
+
});
|
|
275
|
+
} else {
|
|
276
|
+
void this.session?.cancel().catch(() => {
|
|
277
|
+
});
|
|
278
|
+
}
|
|
226
279
|
this.activeResponse = void 0;
|
|
227
280
|
this.session = void 0;
|
|
228
281
|
clearPersistedAgentSession(this.visitorSessionId, this.storeOptions);
|
|
@@ -247,7 +300,8 @@ var AgentSession = class {
|
|
|
247
300
|
if (this.client && this.clientHost === config.host) {
|
|
248
301
|
return this.client;
|
|
249
302
|
}
|
|
250
|
-
this.
|
|
303
|
+
this.activeResponse = void 0;
|
|
304
|
+
this.session = void 0;
|
|
251
305
|
this.client = new Client({
|
|
252
306
|
auth: { bearer: () => this.capability.getAccessToken() },
|
|
253
307
|
host: config.host,
|
|
@@ -296,28 +350,20 @@ var AgentSession = class {
|
|
|
296
350
|
this.persistSessionCursor(session);
|
|
297
351
|
}
|
|
298
352
|
this.activeResponse = response;
|
|
353
|
+
let streamIndex = session?.state.streamIndex ?? 0;
|
|
299
354
|
let rendered = "";
|
|
300
355
|
try {
|
|
301
356
|
for await (const event of response) {
|
|
302
357
|
if (signal.aborted) break;
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if (
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
rendered += messageDelta;
|
|
313
|
-
}
|
|
314
|
-
if (delta) handlers.onDelta(delta);
|
|
315
|
-
}
|
|
316
|
-
if (event.type === "message.completed") {
|
|
317
|
-
handlers.onComplete?.();
|
|
318
|
-
}
|
|
319
|
-
if (event.type === "session.failed") {
|
|
320
|
-
throw new Error(event.data.message || event.data.code);
|
|
358
|
+
rendered = applyMessageEvent(event, rendered, handlers);
|
|
359
|
+
streamIndex += 1;
|
|
360
|
+
if (session) {
|
|
361
|
+
savePersistedAgentSession(
|
|
362
|
+
this.visitorSessionId,
|
|
363
|
+
session.state.sessionId,
|
|
364
|
+
streamIndex,
|
|
365
|
+
this.storeOptions
|
|
366
|
+
);
|
|
321
367
|
}
|
|
322
368
|
}
|
|
323
369
|
} finally {
|
|
@@ -329,15 +375,83 @@ var AgentSession = class {
|
|
|
329
375
|
if (!rendered.trim() && !signal.aborted) {
|
|
330
376
|
throw new Error("Empty response from runtime");
|
|
331
377
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
378
|
+
return rendered.trim();
|
|
379
|
+
}
|
|
380
|
+
async resumeTurn(message, signal, handlers, initialText = "") {
|
|
381
|
+
const persisted = loadPersistedAgentSession(this.visitorSessionId, this.storeOptions);
|
|
382
|
+
if (!persisted) return null;
|
|
383
|
+
const client = this.ensureClient();
|
|
384
|
+
const attached = client.sessions.attach(persisted.sessionId, {
|
|
385
|
+
streamIndex: persisted.streamIndex
|
|
386
|
+
});
|
|
387
|
+
const snapshot = await withCapabilityRefresh(
|
|
388
|
+
this.capability,
|
|
389
|
+
() => attached.snapshot({ signal })
|
|
390
|
+
);
|
|
391
|
+
const turnEvents = latestTurnEvents(snapshot.events);
|
|
392
|
+
const received = turnEvents[0];
|
|
393
|
+
if (received?.type !== "message.received" || received.data.message !== message) {
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
let rendered = renderTurn(turnEvents);
|
|
397
|
+
if (rendered.startsWith(initialText)) {
|
|
398
|
+
const missedText = rendered.slice(initialText.length);
|
|
399
|
+
if (missedText) handlers.onDelta(missedText);
|
|
400
|
+
} else if (initialText.startsWith(rendered)) {
|
|
401
|
+
rendered = initialText;
|
|
402
|
+
} else if (!initialText.startsWith(rendered)) {
|
|
403
|
+
rendered = initialText + rendered;
|
|
404
|
+
}
|
|
405
|
+
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
406
|
+
streamIndex: snapshot.session.streamIndex
|
|
407
|
+
});
|
|
408
|
+
this.session = session;
|
|
409
|
+
this.persistSessionCursor(session);
|
|
410
|
+
let snapshotBoundary;
|
|
411
|
+
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
412
|
+
const event = turnEvents[index];
|
|
413
|
+
if (event && isTurnBoundary(event)) {
|
|
414
|
+
snapshotBoundary = event;
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (snapshotBoundary) {
|
|
419
|
+
if (snapshotBoundary.type === "session.failed") {
|
|
420
|
+
throw new Error(snapshotBoundary.data.message || snapshotBoundary.data.code);
|
|
421
|
+
}
|
|
422
|
+
handlers.onComplete?.();
|
|
423
|
+
if (!rendered.trim()) throw new Error("Empty response from runtime");
|
|
424
|
+
return rendered.trim();
|
|
425
|
+
}
|
|
426
|
+
let streamIndex = snapshot.session.streamIndex;
|
|
427
|
+
for await (const event of session.stream({ signal })) {
|
|
428
|
+
if (signal.aborted) break;
|
|
429
|
+
rendered = applyMessageEvent(event, rendered, handlers);
|
|
430
|
+
streamIndex += 1;
|
|
431
|
+
savePersistedAgentSession(
|
|
432
|
+
this.visitorSessionId,
|
|
433
|
+
session.state.sessionId,
|
|
434
|
+
streamIndex,
|
|
435
|
+
this.storeOptions
|
|
436
|
+
);
|
|
437
|
+
if (isTurnBoundary(event)) break;
|
|
438
|
+
}
|
|
439
|
+
session = client.sessions.attach(session.state.sessionId, { streamIndex });
|
|
440
|
+
this.session = session;
|
|
441
|
+
this.persistSessionCursor(session);
|
|
442
|
+
if (!rendered.trim() && !signal.aborted) {
|
|
443
|
+
throw new Error("Empty response from runtime");
|
|
335
444
|
}
|
|
336
445
|
return rendered.trim();
|
|
337
446
|
}
|
|
338
447
|
cancelActive() {
|
|
339
|
-
this.activeResponse
|
|
340
|
-
|
|
448
|
+
if (this.activeResponse) {
|
|
449
|
+
this.activeResponse.cancel().catch(() => {
|
|
450
|
+
});
|
|
451
|
+
} else {
|
|
452
|
+
this.session?.cancel().catch(() => {
|
|
453
|
+
});
|
|
454
|
+
}
|
|
341
455
|
}
|
|
342
456
|
};
|
|
343
457
|
function createAgentClient(options) {
|
|
@@ -371,6 +485,12 @@ function createAgentClient(options) {
|
|
|
371
485
|
sendOptions.signal ?? new AbortController().signal,
|
|
372
486
|
sendOptions.handlers
|
|
373
487
|
),
|
|
488
|
+
resumeTurn: (resumeOptions) => session.resumeTurn(
|
|
489
|
+
resumeOptions.message,
|
|
490
|
+
resumeOptions.signal ?? new AbortController().signal,
|
|
491
|
+
resumeOptions.handlers,
|
|
492
|
+
resumeOptions.initialText
|
|
493
|
+
),
|
|
374
494
|
reset: () => session.reset(),
|
|
375
495
|
cancelActive: () => session.cancelActive(),
|
|
376
496
|
getActiveSessionId: () => session.getActiveSessionId()
|
|
@@ -399,6 +519,58 @@ function formatAgentError(error) {
|
|
|
399
519
|
return "Runtime request failed";
|
|
400
520
|
}
|
|
401
521
|
|
|
522
|
+
// src/react/persisted-conversation.ts
|
|
523
|
+
var CONVERSATION_VERSION = 1;
|
|
524
|
+
function conversationKey(storageKeyPrefix, visitorSessionId) {
|
|
525
|
+
return `${storageKeyPrefix}:conversation:${visitorSessionId}`;
|
|
526
|
+
}
|
|
527
|
+
function parseMessage(value) {
|
|
528
|
+
if (typeof value !== "object" || value === null) return null;
|
|
529
|
+
const record = value;
|
|
530
|
+
if (typeof record.id !== "string" || record.role !== "agent" && record.role !== "visitor" || typeof record.text !== "string" || typeof record.createdAt !== "number" || !Number.isFinite(record.createdAt)) {
|
|
531
|
+
return null;
|
|
532
|
+
}
|
|
533
|
+
return {
|
|
534
|
+
id: record.id,
|
|
535
|
+
role: record.role,
|
|
536
|
+
text: record.text,
|
|
537
|
+
createdAt: record.createdAt
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function loadPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
|
|
541
|
+
if (typeof sessionStorage === "undefined") return null;
|
|
542
|
+
const raw = sessionStorage.getItem(conversationKey(storageKeyPrefix, visitorSessionId));
|
|
543
|
+
if (!raw) return null;
|
|
544
|
+
try {
|
|
545
|
+
const value = JSON.parse(raw);
|
|
546
|
+
if (typeof value !== "object" || value === null) return null;
|
|
547
|
+
const record = value;
|
|
548
|
+
if (record.version !== CONVERSATION_VERSION || !Array.isArray(record.messages) || typeof record.pending !== "boolean" || typeof record.streamingText !== "string") {
|
|
549
|
+
return null;
|
|
550
|
+
}
|
|
551
|
+
const messages = record.messages.map(parseMessage);
|
|
552
|
+
if (messages.some((message) => message === null)) return null;
|
|
553
|
+
return {
|
|
554
|
+
messages: messages.filter((message) => message !== null),
|
|
555
|
+
pending: record.pending,
|
|
556
|
+
streamingText: record.streamingText
|
|
557
|
+
};
|
|
558
|
+
} catch {
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
function savePersistedAgentConversation(storageKeyPrefix, visitorSessionId, conversation) {
|
|
563
|
+
if (typeof sessionStorage === "undefined") return;
|
|
564
|
+
sessionStorage.setItem(
|
|
565
|
+
conversationKey(storageKeyPrefix, visitorSessionId),
|
|
566
|
+
JSON.stringify({ version: CONVERSATION_VERSION, ...conversation })
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
function clearPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
|
|
570
|
+
if (typeof sessionStorage === "undefined") return;
|
|
571
|
+
sessionStorage.removeItem(conversationKey(storageKeyPrefix, visitorSessionId));
|
|
572
|
+
}
|
|
573
|
+
|
|
402
574
|
// src/react/hooks/useAgentChat.ts
|
|
403
575
|
var GREETING_MESSAGE = {
|
|
404
576
|
id: "greeting",
|
|
@@ -415,6 +587,15 @@ var INITIAL_STATE = {
|
|
|
415
587
|
streamingText: "",
|
|
416
588
|
error: null
|
|
417
589
|
};
|
|
590
|
+
function stateFromConversation(conversation) {
|
|
591
|
+
if (!conversation || conversation.messages.length === 0) return INITIAL_STATE;
|
|
592
|
+
return {
|
|
593
|
+
...INITIAL_STATE,
|
|
594
|
+
messages: conversation.messages,
|
|
595
|
+
phase: conversation.pending ? conversation.streamingText ? "streaming" : "thinking" : "complete",
|
|
596
|
+
streamingText: conversation.streamingText
|
|
597
|
+
};
|
|
598
|
+
}
|
|
418
599
|
var STATUS_SEQUENCE = [
|
|
419
600
|
{ id: "s1", label: "Starting Eve session", ms: 400 },
|
|
420
601
|
{ id: "s2", label: "Connecting to runtime", ms: 500 }
|
|
@@ -446,8 +627,6 @@ function useAgentChat({
|
|
|
446
627
|
visitorSessionId,
|
|
447
628
|
storageKeyPrefix
|
|
448
629
|
}) {
|
|
449
|
-
const [state, setState] = useState(INITIAL_STATE);
|
|
450
|
-
const runRef = useRef(null);
|
|
451
630
|
const resolvedStorageKeyPrefix = useMemo(
|
|
452
631
|
() => storageKeyPrefix?.trim() || buildAgentStorageKeyPrefix({ customerId, indexId, version, runtimeOrigin }),
|
|
453
632
|
[customerId, indexId, runtimeOrigin, storageKeyPrefix, version]
|
|
@@ -456,6 +635,12 @@ function useAgentChat({
|
|
|
456
635
|
() => visitorSessionId?.trim() || getOrCreateVisitorSessionId({ storageKeyPrefix: resolvedStorageKeyPrefix }),
|
|
457
636
|
[resolvedStorageKeyPrefix, visitorSessionId]
|
|
458
637
|
);
|
|
638
|
+
const [state, setState] = useState(
|
|
639
|
+
() => stateFromConversation(
|
|
640
|
+
loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
|
|
641
|
+
)
|
|
642
|
+
);
|
|
643
|
+
const runRef = useRef(null);
|
|
459
644
|
const clientRef = useRef(
|
|
460
645
|
createAgentClient({
|
|
461
646
|
customerId,
|
|
@@ -466,20 +651,15 @@ function useAgentChat({
|
|
|
466
651
|
storageKeyPrefix: resolvedStorageKeyPrefix
|
|
467
652
|
})
|
|
468
653
|
);
|
|
469
|
-
const identityRef = useRef(null);
|
|
470
654
|
const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}`;
|
|
655
|
+
const identityRef = useRef(identityKey);
|
|
471
656
|
useEffect(() => {
|
|
472
|
-
if (identityRef.current === null) {
|
|
473
|
-
identityRef.current = identityKey;
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
657
|
if (identityRef.current === identityKey) {
|
|
477
658
|
return;
|
|
478
659
|
}
|
|
479
660
|
identityRef.current = identityKey;
|
|
480
661
|
runRef.current?.abort();
|
|
481
662
|
runRef.current = null;
|
|
482
|
-
clientRef.current.reset();
|
|
483
663
|
clientRef.current = createAgentClient({
|
|
484
664
|
customerId,
|
|
485
665
|
indexId,
|
|
@@ -488,81 +668,81 @@ function useAgentChat({
|
|
|
488
668
|
visitorSessionId: visitorId,
|
|
489
669
|
storageKeyPrefix: resolvedStorageKeyPrefix
|
|
490
670
|
});
|
|
491
|
-
setState(
|
|
671
|
+
setState(
|
|
672
|
+
stateFromConversation(
|
|
673
|
+
loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
|
|
674
|
+
)
|
|
675
|
+
);
|
|
492
676
|
}, [customerId, identityKey, indexId, runtimeOrigin, resolvedStorageKeyPrefix, version, visitorId]);
|
|
677
|
+
useEffect(() => {
|
|
678
|
+
if (!hasVisitorMessages(state.messages)) return;
|
|
679
|
+
savePersistedAgentConversation(resolvedStorageKeyPrefix, visitorId, {
|
|
680
|
+
messages: state.messages,
|
|
681
|
+
pending: isAgentBusy(state.phase),
|
|
682
|
+
streamingText: state.streamingText
|
|
683
|
+
});
|
|
684
|
+
}, [resolvedStorageKeyPrefix, state.messages, state.phase, state.streamingText, visitorId]);
|
|
493
685
|
const reset = useCallback(() => {
|
|
494
686
|
runRef.current?.abort();
|
|
495
687
|
runRef.current = null;
|
|
496
688
|
clientRef.current.reset();
|
|
689
|
+
clearPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId);
|
|
497
690
|
setState(INITIAL_STATE);
|
|
498
|
-
}, []);
|
|
499
|
-
const
|
|
500
|
-
async (
|
|
501
|
-
|
|
502
|
-
clientRef.current.cancelActive();
|
|
503
|
-
const controller = new AbortController();
|
|
504
|
-
runRef.current = controller;
|
|
691
|
+
}, [resolvedStorageKeyPrefix, visitorId]);
|
|
692
|
+
const runTurn = useCallback(
|
|
693
|
+
async (input) => {
|
|
694
|
+
const { controller, initialText = "", resume, visitorText } = input;
|
|
505
695
|
const { signal } = controller;
|
|
506
696
|
const isActiveRun = () => runRef.current === controller && !signal.aborted;
|
|
507
|
-
const visitorMessage = {
|
|
508
|
-
id: `visitor-${Date.now()}`,
|
|
509
|
-
role: "visitor",
|
|
510
|
-
text: visitorText,
|
|
511
|
-
createdAt: Date.now()
|
|
512
|
-
};
|
|
513
|
-
setState((prev) => ({
|
|
514
|
-
...prev,
|
|
515
|
-
phase: "thinking",
|
|
516
|
-
messages: [...prev.messages, visitorMessage],
|
|
517
|
-
toolSteps: [{ id: "s1", label: "Starting Eve session", state: "active" }],
|
|
518
|
-
journey: null,
|
|
519
|
-
followUps: [],
|
|
520
|
-
streamingText: "",
|
|
521
|
-
error: null
|
|
522
|
-
}));
|
|
523
697
|
try {
|
|
524
|
-
let streamStarted =
|
|
525
|
-
|
|
698
|
+
let streamStarted = Boolean(initialText);
|
|
699
|
+
let streamed = initialText;
|
|
700
|
+
const planningPromise = resume ? Promise.resolve() : runStatusSequence(signal, (step) => {
|
|
526
701
|
if (streamStarted || !isActiveRun()) return;
|
|
527
702
|
setState((prev) => ({ ...prev, phase: "running-tools", toolSteps: [step] }));
|
|
528
703
|
});
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
704
|
+
const handlers = {
|
|
705
|
+
onStep: (label, detail) => {
|
|
706
|
+
if (streamStarted || !isActiveRun()) return;
|
|
707
|
+
setState((prev) => ({
|
|
708
|
+
...prev,
|
|
709
|
+
phase: "running-tools",
|
|
710
|
+
toolSteps: [{ id: `step-${label}`, label, detail, state: "active" }]
|
|
711
|
+
}));
|
|
712
|
+
},
|
|
713
|
+
onDelta: (delta) => {
|
|
714
|
+
if (!isActiveRun()) return;
|
|
715
|
+
void planningPromise.catch(() => {
|
|
716
|
+
});
|
|
717
|
+
if (!streamStarted) {
|
|
718
|
+
streamStarted = true;
|
|
535
719
|
setState((prev) => ({
|
|
536
720
|
...prev,
|
|
537
|
-
phase: "
|
|
538
|
-
toolSteps: [
|
|
721
|
+
phase: "streaming",
|
|
722
|
+
toolSteps: [],
|
|
723
|
+
streamingText: ""
|
|
539
724
|
}));
|
|
540
|
-
},
|
|
541
|
-
onDelta: (delta) => {
|
|
542
|
-
if (!isActiveRun()) return;
|
|
543
|
-
void planningPromise.catch(() => {
|
|
544
|
-
});
|
|
545
|
-
if (!streamStarted) {
|
|
546
|
-
streamStarted = true;
|
|
547
|
-
setState((prev) => ({
|
|
548
|
-
...prev,
|
|
549
|
-
phase: "streaming",
|
|
550
|
-
toolSteps: [],
|
|
551
|
-
streamingText: ""
|
|
552
|
-
}));
|
|
553
|
-
}
|
|
554
|
-
streamed += delta;
|
|
555
|
-
setState((prev) => ({ ...prev, phase: "streaming", streamingText: streamed }));
|
|
556
|
-
},
|
|
557
|
-
onComplete: () => {
|
|
558
|
-
if (!isActiveRun()) return;
|
|
559
|
-
streamStarted = true;
|
|
560
725
|
}
|
|
726
|
+
streamed += delta;
|
|
727
|
+
setState((prev) => ({ ...prev, phase: "streaming", streamingText: streamed }));
|
|
728
|
+
},
|
|
729
|
+
onComplete: () => {
|
|
730
|
+
if (!isActiveRun()) return;
|
|
731
|
+
streamStarted = true;
|
|
561
732
|
}
|
|
562
|
-
}
|
|
733
|
+
};
|
|
734
|
+
let finalText = resume ? await clientRef.current.resumeTurn({
|
|
735
|
+
handlers,
|
|
736
|
+
initialText,
|
|
737
|
+
message: visitorText,
|
|
738
|
+
signal
|
|
739
|
+
}) : await clientRef.current.sendTurn(visitorText, { handlers, signal });
|
|
740
|
+
if (resume && finalText === null) {
|
|
741
|
+
finalText = await clientRef.current.sendTurn(visitorText, { handlers, signal });
|
|
742
|
+
}
|
|
563
743
|
await planningPromise.catch(() => {
|
|
564
744
|
});
|
|
565
|
-
if (!isActiveRun()) return;
|
|
745
|
+
if (!isActiveRun() || finalText === null) return;
|
|
566
746
|
const agentMessage = {
|
|
567
747
|
id: `agent-${Date.now()}`,
|
|
568
748
|
role: "agent",
|
|
@@ -578,6 +758,7 @@ function useAgentChat({
|
|
|
578
758
|
followUps: [],
|
|
579
759
|
journey: null
|
|
580
760
|
}));
|
|
761
|
+
runRef.current = null;
|
|
581
762
|
} catch (error) {
|
|
582
763
|
if (error instanceof DOMException && error.name === "AbortError") return;
|
|
583
764
|
if (!isActiveRun()) return;
|
|
@@ -590,14 +771,66 @@ function useAgentChat({
|
|
|
590
771
|
streamingText: "",
|
|
591
772
|
error: message
|
|
592
773
|
}));
|
|
774
|
+
runRef.current = null;
|
|
593
775
|
}
|
|
594
776
|
},
|
|
595
|
-
[
|
|
777
|
+
[]
|
|
778
|
+
);
|
|
779
|
+
const submit = useCallback(
|
|
780
|
+
async (visitorText) => {
|
|
781
|
+
if (runRef.current) {
|
|
782
|
+
runRef.current.abort();
|
|
783
|
+
clientRef.current.cancelActive();
|
|
784
|
+
}
|
|
785
|
+
const controller = new AbortController();
|
|
786
|
+
runRef.current = controller;
|
|
787
|
+
const visitorMessage = {
|
|
788
|
+
id: `visitor-${Date.now()}`,
|
|
789
|
+
role: "visitor",
|
|
790
|
+
text: visitorText,
|
|
791
|
+
createdAt: Date.now()
|
|
792
|
+
};
|
|
793
|
+
setState((prev) => ({
|
|
794
|
+
...prev,
|
|
795
|
+
phase: "thinking",
|
|
796
|
+
messages: [...prev.messages, visitorMessage],
|
|
797
|
+
toolSteps: [{ id: "s1", label: "Starting Eve session", state: "active" }],
|
|
798
|
+
journey: null,
|
|
799
|
+
followUps: [],
|
|
800
|
+
streamingText: "",
|
|
801
|
+
error: null
|
|
802
|
+
}));
|
|
803
|
+
await runTurn({ controller, resume: false, visitorText });
|
|
804
|
+
},
|
|
805
|
+
[runTurn]
|
|
596
806
|
);
|
|
807
|
+
useEffect(() => {
|
|
808
|
+
const conversation = loadPersistedAgentConversation(
|
|
809
|
+
resolvedStorageKeyPrefix,
|
|
810
|
+
visitorId
|
|
811
|
+
);
|
|
812
|
+
if (!conversation?.pending) return;
|
|
813
|
+
const visitorMessage = [...conversation.messages].reverse().find((message) => message.role === "visitor");
|
|
814
|
+
if (!visitorMessage) return;
|
|
815
|
+
const controller = new AbortController();
|
|
816
|
+
runRef.current = controller;
|
|
817
|
+
void runTurn({
|
|
818
|
+
controller,
|
|
819
|
+
initialText: conversation.streamingText,
|
|
820
|
+
resume: true,
|
|
821
|
+
visitorText: visitorMessage.text
|
|
822
|
+
});
|
|
823
|
+
return () => {
|
|
824
|
+
if (runRef.current === controller) {
|
|
825
|
+
runRef.current = null;
|
|
826
|
+
}
|
|
827
|
+
controller.abort();
|
|
828
|
+
};
|
|
829
|
+
}, [identityKey, resolvedStorageKeyPrefix, runTurn, visitorId]);
|
|
597
830
|
useEffect(() => {
|
|
598
831
|
return () => {
|
|
599
832
|
runRef.current?.abort();
|
|
600
|
-
|
|
833
|
+
runRef.current = null;
|
|
601
834
|
};
|
|
602
835
|
}, []);
|
|
603
836
|
return {
|
|
@@ -809,19 +1042,31 @@ function FollowUpChips({
|
|
|
809
1042
|
}
|
|
810
1043
|
|
|
811
1044
|
// src/react/components/MessageBubble/MessageBubble.tsx
|
|
812
|
-
import {
|
|
1045
|
+
import { Streamdown } from "streamdown";
|
|
1046
|
+
import "streamdown/styles.css";
|
|
1047
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
813
1048
|
function MessageBubble({ message }) {
|
|
814
1049
|
if (message.role === "visitor") {
|
|
815
1050
|
return /* @__PURE__ */ jsx5("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ jsx5("p", { className: "message-bubble__text", children: message.text }) });
|
|
816
1051
|
}
|
|
817
|
-
return /* @__PURE__ */ jsx5("article", { className: "message-bubble message-bubble--agent", children: /* @__PURE__ */
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
1052
|
+
return /* @__PURE__ */ jsx5("article", { className: "message-bubble message-bubble--agent", children: /* @__PURE__ */ jsx5("div", { className: "message-bubble__text", children: /* @__PURE__ */ jsx5(
|
|
1053
|
+
Streamdown,
|
|
1054
|
+
{
|
|
1055
|
+
animated: true,
|
|
1056
|
+
caret: "circle",
|
|
1057
|
+
className: "message-bubble__markdown",
|
|
1058
|
+
controls: false,
|
|
1059
|
+
isAnimating: message.streaming,
|
|
1060
|
+
linkSafety: { enabled: false },
|
|
1061
|
+
mode: message.streaming ? "streaming" : "static",
|
|
1062
|
+
skipHtml: true,
|
|
1063
|
+
children: message.text
|
|
1064
|
+
}
|
|
1065
|
+
) }) });
|
|
821
1066
|
}
|
|
822
1067
|
|
|
823
1068
|
// src/react/components/AgentRail/AgentRail.tsx
|
|
824
|
-
import { jsx as jsx6, jsxs as
|
|
1069
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
825
1070
|
function MinimizeIcon() {
|
|
826
1071
|
return /* @__PURE__ */ jsx6("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx6("path", { d: "M3.5 8h9", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
|
|
827
1072
|
}
|
|
@@ -882,14 +1127,14 @@ function AgentRail({
|
|
|
882
1127
|
if (!node) return;
|
|
883
1128
|
node.scrollTop = node.scrollHeight;
|
|
884
1129
|
}, [state.messages, state.toolSteps, state.streamingText, state.followUps, state.journey]);
|
|
885
|
-
return /* @__PURE__ */
|
|
1130
|
+
return /* @__PURE__ */ jsxs4(
|
|
886
1131
|
"aside",
|
|
887
1132
|
{
|
|
888
1133
|
className: `agent-rail${mobileFullscreen ? " agent-rail--mobile-fullscreen" : ""}${expanded ? " agent-rail--expanded" : ""}`,
|
|
889
1134
|
style: railStyle,
|
|
890
1135
|
"aria-label": "Agent conversation",
|
|
891
1136
|
children: [
|
|
892
|
-
/* @__PURE__ */ jsx6("header", { className: "agent-rail__header", children: /* @__PURE__ */
|
|
1137
|
+
/* @__PURE__ */ jsx6("header", { className: "agent-rail__header", children: /* @__PURE__ */ jsxs4("div", { className: "agent-rail__brand-row", children: [
|
|
893
1138
|
onCollapse ? /* @__PURE__ */ jsx6(
|
|
894
1139
|
"button",
|
|
895
1140
|
{
|
|
@@ -912,7 +1157,7 @@ function AgentRail({
|
|
|
912
1157
|
}
|
|
913
1158
|
) : /* @__PURE__ */ jsx6("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" })
|
|
914
1159
|
] }) }),
|
|
915
|
-
/* @__PURE__ */
|
|
1160
|
+
/* @__PURE__ */ jsxs4("div", { ref: transcriptRef, className: "agent-rail__transcript", children: [
|
|
916
1161
|
state.messages.map((message) => /* @__PURE__ */ jsx6(MessageBubble, { message }, message.id)),
|
|
917
1162
|
streamingMessage ? /* @__PURE__ */ jsx6(MessageBubble, { message: streamingMessage }) : null,
|
|
918
1163
|
showActivity ? /* @__PURE__ */ jsx6(AgentActivityBubble, { steps: state.toolSteps }) : null,
|
|
@@ -927,7 +1172,7 @@ function AgentRail({
|
|
|
927
1172
|
) }) : null,
|
|
928
1173
|
state.error ? /* @__PURE__ */ jsx6("p", { role: "alert", style: { fontSize: 13, color: "var(--as-danger)", margin: 0 }, children: state.error }) : null
|
|
929
1174
|
] }),
|
|
930
|
-
expanded ? /* @__PURE__ */
|
|
1175
|
+
expanded ? /* @__PURE__ */ jsxs4("div", { className: "agent-rail__dock-wrap", children: [
|
|
931
1176
|
showDockFollowUps ? /* @__PURE__ */ jsx6("div", { className: "agent-rail__dock-followups", children: /* @__PURE__ */ jsx6(
|
|
932
1177
|
FollowUpChips,
|
|
933
1178
|
{
|
|
@@ -946,11 +1191,11 @@ function AgentRail({
|
|
|
946
1191
|
onSubmit
|
|
947
1192
|
}
|
|
948
1193
|
) }),
|
|
949
|
-
/* @__PURE__ */
|
|
1194
|
+
/* @__PURE__ */ jsxs4("div", { className: "agent-rail__footer", children: [
|
|
950
1195
|
/* @__PURE__ */ jsx6("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
|
|
951
1196
|
/* @__PURE__ */ jsx6("p", { className: "agent-rail__footer-note", children: poweredByLabel })
|
|
952
1197
|
] })
|
|
953
|
-
] }) : /* @__PURE__ */
|
|
1198
|
+
] }) : /* @__PURE__ */ jsxs4("div", { className: "agent-rail__composer-wrap", children: [
|
|
954
1199
|
/* @__PURE__ */ jsx6(
|
|
955
1200
|
Composer,
|
|
956
1201
|
{
|
|
@@ -959,7 +1204,7 @@ function AgentRail({
|
|
|
959
1204
|
onSubmit
|
|
960
1205
|
}
|
|
961
1206
|
),
|
|
962
|
-
/* @__PURE__ */
|
|
1207
|
+
/* @__PURE__ */ jsxs4("div", { className: "agent-rail__footer", children: [
|
|
963
1208
|
/* @__PURE__ */ jsx6("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
|
|
964
1209
|
/* @__PURE__ */ jsx6("p", { className: "agent-rail__footer-note", children: poweredByLabel })
|
|
965
1210
|
] })
|
|
@@ -970,9 +1215,9 @@ function AgentRail({
|
|
|
970
1215
|
}
|
|
971
1216
|
|
|
972
1217
|
// src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
|
|
973
|
-
import { Fragment, jsx as jsx7, jsxs as
|
|
1218
|
+
import { Fragment, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
974
1219
|
function SparklesIcon() {
|
|
975
|
-
return /* @__PURE__ */
|
|
1220
|
+
return /* @__PURE__ */ jsxs5("svg", { className: "assist-edge-tab__sparkles", viewBox: "0 0 18 16", fill: "none", "aria-hidden": "true", children: [
|
|
976
1221
|
/* @__PURE__ */ jsx7("path", { d: "M8 1.2l.95 2.7 2.85.05-2.25 1.75.8 2.75L8 6.7 5.65 8.45l.8-2.75L4.2 3.95l2.85-.05L8 1.2z", fill: "currentColor" }),
|
|
977
1222
|
/* @__PURE__ */ jsx7("path", { d: "M14.2 6.4l.55 1.55 1.65.03-1.3 1 .46 1.58-1.36-1-1.36 1 .46-1.58-1.3-1 1.65-.03.55-1.55z", fill: "currentColor" }),
|
|
978
1223
|
/* @__PURE__ */ jsx7("path", { d: "M3.1 9.1l.4 1.15 1.22.02-.96.74.34 1.17-1-.74-1 .74.34-1.17-.96-.74 1.22-.02.4-1.15z", fill: "currentColor" })
|
|
@@ -1005,7 +1250,7 @@ function AssistEdgeTab({
|
|
|
1005
1250
|
"--tab-along": `${along}%`,
|
|
1006
1251
|
"--tab-inset": `${inset}px`
|
|
1007
1252
|
};
|
|
1008
|
-
return /* @__PURE__ */
|
|
1253
|
+
return /* @__PURE__ */ jsxs5(
|
|
1009
1254
|
"button",
|
|
1010
1255
|
{
|
|
1011
1256
|
type: "button",
|
|
@@ -1016,17 +1261,17 @@ function AssistEdgeTab({
|
|
|
1016
1261
|
tabIndex: visible ? 0 : -1,
|
|
1017
1262
|
onClick: onOpen,
|
|
1018
1263
|
children: [
|
|
1019
|
-
variant === "outline" ? /* @__PURE__ */
|
|
1264
|
+
variant === "outline" ? /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1020
1265
|
/* @__PURE__ */ jsx7(SparklesIcon, {}),
|
|
1021
1266
|
/* @__PURE__ */ jsx7("span", { className: "assist-edge-tab__label", children: copy.label }),
|
|
1022
1267
|
/* @__PURE__ */ jsx7(ChevronDownIcon, {})
|
|
1023
1268
|
] }) : null,
|
|
1024
|
-
variant === "ask" ? /* @__PURE__ */
|
|
1269
|
+
variant === "ask" ? /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1025
1270
|
/* @__PURE__ */ jsx7(ChevronLeftIcon, {}),
|
|
1026
1271
|
/* @__PURE__ */ jsx7("span", { className: "assist-edge-tab__label", children: copy.label }),
|
|
1027
1272
|
/* @__PURE__ */ jsx7(DragDots, {})
|
|
1028
1273
|
] }) : null,
|
|
1029
|
-
variant === "fill" ? /* @__PURE__ */
|
|
1274
|
+
variant === "fill" ? /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1030
1275
|
/* @__PURE__ */ jsx7(SparklesIcon, {}),
|
|
1031
1276
|
/* @__PURE__ */ jsx7("span", { className: "assist-edge-tab__label", children: copy.label }),
|
|
1032
1277
|
/* @__PURE__ */ jsx7(ChevronLeftIcon, {})
|
|
@@ -1071,7 +1316,7 @@ function closeAgentPanel(customerId) {
|
|
|
1071
1316
|
}
|
|
1072
1317
|
|
|
1073
1318
|
// src/react/components/AgentWidget/AgentWidget.tsx
|
|
1074
|
-
import { jsx as jsx8, jsxs as
|
|
1319
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1075
1320
|
function AgentWidget({
|
|
1076
1321
|
indexId,
|
|
1077
1322
|
customerId,
|
|
@@ -1107,7 +1352,7 @@ function AgentWidget({
|
|
|
1107
1352
|
if (isMobile) setRailCollapsed(false);
|
|
1108
1353
|
await submit(message);
|
|
1109
1354
|
}
|
|
1110
|
-
return /* @__PURE__ */
|
|
1355
|
+
return /* @__PURE__ */ jsxs6("div", { className: "webless-agent-root", children: [
|
|
1111
1356
|
/* @__PURE__ */ jsx8(
|
|
1112
1357
|
"div",
|
|
1113
1358
|
{
|
|
@@ -1176,4 +1421,4 @@ export {
|
|
|
1176
1421
|
AssistEdgeTab,
|
|
1177
1422
|
AgentWidget
|
|
1178
1423
|
};
|
|
1179
|
-
//# sourceMappingURL=chunk-
|
|
1424
|
+
//# sourceMappingURL=chunk-XAUJPXWR.js.map
|