@webless/agent 0.2.10 → 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-DSNTEDXA.js → chunk-XAUJPXWR.js} +326 -93
- package/dist/chunk-XAUJPXWR.js.map +1 -0
- package/dist/embed.cjs +328 -92
- package/dist/embed.cjs.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 +325 -92
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-DSNTEDXA.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
|
+
[]
|
|
596
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]
|
|
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 {
|
|
@@ -1188,4 +1421,4 @@ export {
|
|
|
1188
1421
|
AssistEdgeTab,
|
|
1189
1422
|
AgentWidget
|
|
1190
1423
|
};
|
|
1191
|
-
//# sourceMappingURL=chunk-
|
|
1424
|
+
//# sourceMappingURL=chunk-XAUJPXWR.js.map
|