@webless/agent 0.2.10 → 0.2.12
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-K52TJUV6.js} +329 -94
- package/dist/chunk-K52TJUV6.js.map +1 -0
- package/dist/embed.cjs +331 -93
- package/dist/embed.cjs.map +1 -1
- package/dist/embed.js +1 -1
- package/dist/index.cjs +149 -27
- 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 +149 -27
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +328 -93
- 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
|
@@ -45,7 +45,8 @@ function createAgentRuntimeCapability(options) {
|
|
|
45
45
|
const response = await fetchImplementation(`${options.runtimeOrigin}/webless/v1/bootstrap`, {
|
|
46
46
|
body: JSON.stringify({
|
|
47
47
|
clientSessionId: options.visitorSessionId,
|
|
48
|
-
indexId: options.indexId
|
|
48
|
+
indexId: options.indexId,
|
|
49
|
+
version: options.version
|
|
49
50
|
}),
|
|
50
51
|
headers: { "content-type": "application/json" },
|
|
51
52
|
method: "POST"
|
|
@@ -186,6 +187,54 @@ function clearPersistedAgentSession(visitorSessionId, options) {
|
|
|
186
187
|
}
|
|
187
188
|
|
|
188
189
|
// src/runtime/client.ts
|
|
190
|
+
function isTurnBoundary(event) {
|
|
191
|
+
return event.type === "session.waiting" || event.type === "session.completed" || event.type === "session.failed";
|
|
192
|
+
}
|
|
193
|
+
function applyMessageEvent(event, rendered, handlers) {
|
|
194
|
+
const step = mapStepLabel(event);
|
|
195
|
+
if (step) handlers.onStep?.(step.label, step.detail);
|
|
196
|
+
if (event.type === "session.failed") {
|
|
197
|
+
throw new Error(event.data.message || event.data.code);
|
|
198
|
+
}
|
|
199
|
+
if (event.type === "message.completed") {
|
|
200
|
+
handlers.onComplete?.();
|
|
201
|
+
}
|
|
202
|
+
if (event.type !== "message.appended") return rendered;
|
|
203
|
+
const { messageDelta, messageSoFar } = event.data;
|
|
204
|
+
let delta = messageDelta;
|
|
205
|
+
let next = rendered;
|
|
206
|
+
if (messageSoFar.startsWith(rendered)) {
|
|
207
|
+
delta = messageSoFar.slice(rendered.length);
|
|
208
|
+
next = messageSoFar;
|
|
209
|
+
} else if (messageDelta) {
|
|
210
|
+
next += messageDelta;
|
|
211
|
+
}
|
|
212
|
+
if (delta) handlers.onDelta(delta);
|
|
213
|
+
return next;
|
|
214
|
+
}
|
|
215
|
+
function latestTurnEvents(events) {
|
|
216
|
+
let startIndex = -1;
|
|
217
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
218
|
+
if (events[index]?.type === "message.received") {
|
|
219
|
+
startIndex = index;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return startIndex >= 0 ? events.slice(startIndex) : [];
|
|
224
|
+
}
|
|
225
|
+
function renderTurn(events) {
|
|
226
|
+
let rendered = "";
|
|
227
|
+
for (const event of events) {
|
|
228
|
+
if (event.type !== "message.appended") continue;
|
|
229
|
+
const { messageDelta, messageSoFar } = event.data;
|
|
230
|
+
if (messageSoFar.startsWith(rendered)) {
|
|
231
|
+
rendered = messageSoFar;
|
|
232
|
+
} else if (messageDelta) {
|
|
233
|
+
rendered += messageDelta;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return rendered;
|
|
237
|
+
}
|
|
189
238
|
function mapStepLabel(event) {
|
|
190
239
|
if (event.type !== "step.started") return null;
|
|
191
240
|
const stepIndex = event.data.stepIndex;
|
|
@@ -204,6 +253,7 @@ var AgentSession = class {
|
|
|
204
253
|
this.capability = createAgentRuntimeCapability({
|
|
205
254
|
indexId,
|
|
206
255
|
runtimeOrigin,
|
|
256
|
+
version,
|
|
207
257
|
visitorSessionId
|
|
208
258
|
});
|
|
209
259
|
}
|
|
@@ -221,8 +271,13 @@ var AgentSession = class {
|
|
|
221
271
|
return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
|
|
222
272
|
}
|
|
223
273
|
reset() {
|
|
224
|
-
|
|
225
|
-
|
|
274
|
+
if (this.activeResponse) {
|
|
275
|
+
void this.activeResponse.cancel().catch(() => {
|
|
276
|
+
});
|
|
277
|
+
} else {
|
|
278
|
+
void this.session?.cancel().catch(() => {
|
|
279
|
+
});
|
|
280
|
+
}
|
|
226
281
|
this.activeResponse = void 0;
|
|
227
282
|
this.session = void 0;
|
|
228
283
|
clearPersistedAgentSession(this.visitorSessionId, this.storeOptions);
|
|
@@ -247,7 +302,8 @@ var AgentSession = class {
|
|
|
247
302
|
if (this.client && this.clientHost === config.host) {
|
|
248
303
|
return this.client;
|
|
249
304
|
}
|
|
250
|
-
this.
|
|
305
|
+
this.activeResponse = void 0;
|
|
306
|
+
this.session = void 0;
|
|
251
307
|
this.client = new Client({
|
|
252
308
|
auth: { bearer: () => this.capability.getAccessToken() },
|
|
253
309
|
host: config.host,
|
|
@@ -296,28 +352,20 @@ var AgentSession = class {
|
|
|
296
352
|
this.persistSessionCursor(session);
|
|
297
353
|
}
|
|
298
354
|
this.activeResponse = response;
|
|
355
|
+
let streamIndex = session?.state.streamIndex ?? 0;
|
|
299
356
|
let rendered = "";
|
|
300
357
|
try {
|
|
301
358
|
for await (const event of response) {
|
|
302
359
|
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);
|
|
360
|
+
rendered = applyMessageEvent(event, rendered, handlers);
|
|
361
|
+
streamIndex += 1;
|
|
362
|
+
if (session) {
|
|
363
|
+
savePersistedAgentSession(
|
|
364
|
+
this.visitorSessionId,
|
|
365
|
+
session.state.sessionId,
|
|
366
|
+
streamIndex,
|
|
367
|
+
this.storeOptions
|
|
368
|
+
);
|
|
321
369
|
}
|
|
322
370
|
}
|
|
323
371
|
} finally {
|
|
@@ -329,15 +377,83 @@ var AgentSession = class {
|
|
|
329
377
|
if (!rendered.trim() && !signal.aborted) {
|
|
330
378
|
throw new Error("Empty response from runtime");
|
|
331
379
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
380
|
+
return rendered.trim();
|
|
381
|
+
}
|
|
382
|
+
async resumeTurn(message, signal, handlers, initialText = "") {
|
|
383
|
+
const persisted = loadPersistedAgentSession(this.visitorSessionId, this.storeOptions);
|
|
384
|
+
if (!persisted) return null;
|
|
385
|
+
const client = this.ensureClient();
|
|
386
|
+
const attached = client.sessions.attach(persisted.sessionId, {
|
|
387
|
+
streamIndex: persisted.streamIndex
|
|
388
|
+
});
|
|
389
|
+
const snapshot = await withCapabilityRefresh(
|
|
390
|
+
this.capability,
|
|
391
|
+
() => attached.snapshot({ signal })
|
|
392
|
+
);
|
|
393
|
+
const turnEvents = latestTurnEvents(snapshot.events);
|
|
394
|
+
const received = turnEvents[0];
|
|
395
|
+
if (received?.type !== "message.received" || received.data.message !== message) {
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
let rendered = renderTurn(turnEvents);
|
|
399
|
+
if (rendered.startsWith(initialText)) {
|
|
400
|
+
const missedText = rendered.slice(initialText.length);
|
|
401
|
+
if (missedText) handlers.onDelta(missedText);
|
|
402
|
+
} else if (initialText.startsWith(rendered)) {
|
|
403
|
+
rendered = initialText;
|
|
404
|
+
} else if (!initialText.startsWith(rendered)) {
|
|
405
|
+
rendered = initialText + rendered;
|
|
406
|
+
}
|
|
407
|
+
let session = client.sessions.attach(snapshot.session.sessionId, {
|
|
408
|
+
streamIndex: snapshot.session.streamIndex
|
|
409
|
+
});
|
|
410
|
+
this.session = session;
|
|
411
|
+
this.persistSessionCursor(session);
|
|
412
|
+
let snapshotBoundary;
|
|
413
|
+
for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
|
|
414
|
+
const event = turnEvents[index];
|
|
415
|
+
if (event && isTurnBoundary(event)) {
|
|
416
|
+
snapshotBoundary = event;
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (snapshotBoundary) {
|
|
421
|
+
if (snapshotBoundary.type === "session.failed") {
|
|
422
|
+
throw new Error(snapshotBoundary.data.message || snapshotBoundary.data.code);
|
|
423
|
+
}
|
|
424
|
+
handlers.onComplete?.();
|
|
425
|
+
if (!rendered.trim()) throw new Error("Empty response from runtime");
|
|
426
|
+
return rendered.trim();
|
|
427
|
+
}
|
|
428
|
+
let streamIndex = snapshot.session.streamIndex;
|
|
429
|
+
for await (const event of session.stream({ signal })) {
|
|
430
|
+
if (signal.aborted) break;
|
|
431
|
+
rendered = applyMessageEvent(event, rendered, handlers);
|
|
432
|
+
streamIndex += 1;
|
|
433
|
+
savePersistedAgentSession(
|
|
434
|
+
this.visitorSessionId,
|
|
435
|
+
session.state.sessionId,
|
|
436
|
+
streamIndex,
|
|
437
|
+
this.storeOptions
|
|
438
|
+
);
|
|
439
|
+
if (isTurnBoundary(event)) break;
|
|
440
|
+
}
|
|
441
|
+
session = client.sessions.attach(session.state.sessionId, { streamIndex });
|
|
442
|
+
this.session = session;
|
|
443
|
+
this.persistSessionCursor(session);
|
|
444
|
+
if (!rendered.trim() && !signal.aborted) {
|
|
445
|
+
throw new Error("Empty response from runtime");
|
|
335
446
|
}
|
|
336
447
|
return rendered.trim();
|
|
337
448
|
}
|
|
338
449
|
cancelActive() {
|
|
339
|
-
this.activeResponse
|
|
340
|
-
|
|
450
|
+
if (this.activeResponse) {
|
|
451
|
+
this.activeResponse.cancel().catch(() => {
|
|
452
|
+
});
|
|
453
|
+
} else {
|
|
454
|
+
this.session?.cancel().catch(() => {
|
|
455
|
+
});
|
|
456
|
+
}
|
|
341
457
|
}
|
|
342
458
|
};
|
|
343
459
|
function createAgentClient(options) {
|
|
@@ -371,6 +487,12 @@ function createAgentClient(options) {
|
|
|
371
487
|
sendOptions.signal ?? new AbortController().signal,
|
|
372
488
|
sendOptions.handlers
|
|
373
489
|
),
|
|
490
|
+
resumeTurn: (resumeOptions) => session.resumeTurn(
|
|
491
|
+
resumeOptions.message,
|
|
492
|
+
resumeOptions.signal ?? new AbortController().signal,
|
|
493
|
+
resumeOptions.handlers,
|
|
494
|
+
resumeOptions.initialText
|
|
495
|
+
),
|
|
374
496
|
reset: () => session.reset(),
|
|
375
497
|
cancelActive: () => session.cancelActive(),
|
|
376
498
|
getActiveSessionId: () => session.getActiveSessionId()
|
|
@@ -399,6 +521,58 @@ function formatAgentError(error) {
|
|
|
399
521
|
return "Runtime request failed";
|
|
400
522
|
}
|
|
401
523
|
|
|
524
|
+
// src/react/persisted-conversation.ts
|
|
525
|
+
var CONVERSATION_VERSION = 1;
|
|
526
|
+
function conversationKey(storageKeyPrefix, visitorSessionId) {
|
|
527
|
+
return `${storageKeyPrefix}:conversation:${visitorSessionId}`;
|
|
528
|
+
}
|
|
529
|
+
function parseMessage(value) {
|
|
530
|
+
if (typeof value !== "object" || value === null) return null;
|
|
531
|
+
const record = value;
|
|
532
|
+
if (typeof record.id !== "string" || record.role !== "agent" && record.role !== "visitor" || typeof record.text !== "string" || typeof record.createdAt !== "number" || !Number.isFinite(record.createdAt)) {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
return {
|
|
536
|
+
id: record.id,
|
|
537
|
+
role: record.role,
|
|
538
|
+
text: record.text,
|
|
539
|
+
createdAt: record.createdAt
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
function loadPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
|
|
543
|
+
if (typeof sessionStorage === "undefined") return null;
|
|
544
|
+
const raw = sessionStorage.getItem(conversationKey(storageKeyPrefix, visitorSessionId));
|
|
545
|
+
if (!raw) return null;
|
|
546
|
+
try {
|
|
547
|
+
const value = JSON.parse(raw);
|
|
548
|
+
if (typeof value !== "object" || value === null) return null;
|
|
549
|
+
const record = value;
|
|
550
|
+
if (record.version !== CONVERSATION_VERSION || !Array.isArray(record.messages) || typeof record.pending !== "boolean" || typeof record.streamingText !== "string") {
|
|
551
|
+
return null;
|
|
552
|
+
}
|
|
553
|
+
const messages = record.messages.map(parseMessage);
|
|
554
|
+
if (messages.some((message) => message === null)) return null;
|
|
555
|
+
return {
|
|
556
|
+
messages: messages.filter((message) => message !== null),
|
|
557
|
+
pending: record.pending,
|
|
558
|
+
streamingText: record.streamingText
|
|
559
|
+
};
|
|
560
|
+
} catch {
|
|
561
|
+
return null;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
function savePersistedAgentConversation(storageKeyPrefix, visitorSessionId, conversation) {
|
|
565
|
+
if (typeof sessionStorage === "undefined") return;
|
|
566
|
+
sessionStorage.setItem(
|
|
567
|
+
conversationKey(storageKeyPrefix, visitorSessionId),
|
|
568
|
+
JSON.stringify({ version: CONVERSATION_VERSION, ...conversation })
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
function clearPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
|
|
572
|
+
if (typeof sessionStorage === "undefined") return;
|
|
573
|
+
sessionStorage.removeItem(conversationKey(storageKeyPrefix, visitorSessionId));
|
|
574
|
+
}
|
|
575
|
+
|
|
402
576
|
// src/react/hooks/useAgentChat.ts
|
|
403
577
|
var GREETING_MESSAGE = {
|
|
404
578
|
id: "greeting",
|
|
@@ -415,6 +589,15 @@ var INITIAL_STATE = {
|
|
|
415
589
|
streamingText: "",
|
|
416
590
|
error: null
|
|
417
591
|
};
|
|
592
|
+
function stateFromConversation(conversation) {
|
|
593
|
+
if (!conversation || conversation.messages.length === 0) return INITIAL_STATE;
|
|
594
|
+
return {
|
|
595
|
+
...INITIAL_STATE,
|
|
596
|
+
messages: conversation.messages,
|
|
597
|
+
phase: conversation.pending ? conversation.streamingText ? "streaming" : "thinking" : "complete",
|
|
598
|
+
streamingText: conversation.streamingText
|
|
599
|
+
};
|
|
600
|
+
}
|
|
418
601
|
var STATUS_SEQUENCE = [
|
|
419
602
|
{ id: "s1", label: "Starting Eve session", ms: 400 },
|
|
420
603
|
{ id: "s2", label: "Connecting to runtime", ms: 500 }
|
|
@@ -446,8 +629,6 @@ function useAgentChat({
|
|
|
446
629
|
visitorSessionId,
|
|
447
630
|
storageKeyPrefix
|
|
448
631
|
}) {
|
|
449
|
-
const [state, setState] = useState(INITIAL_STATE);
|
|
450
|
-
const runRef = useRef(null);
|
|
451
632
|
const resolvedStorageKeyPrefix = useMemo(
|
|
452
633
|
() => storageKeyPrefix?.trim() || buildAgentStorageKeyPrefix({ customerId, indexId, version, runtimeOrigin }),
|
|
453
634
|
[customerId, indexId, runtimeOrigin, storageKeyPrefix, version]
|
|
@@ -456,6 +637,12 @@ function useAgentChat({
|
|
|
456
637
|
() => visitorSessionId?.trim() || getOrCreateVisitorSessionId({ storageKeyPrefix: resolvedStorageKeyPrefix }),
|
|
457
638
|
[resolvedStorageKeyPrefix, visitorSessionId]
|
|
458
639
|
);
|
|
640
|
+
const [state, setState] = useState(
|
|
641
|
+
() => stateFromConversation(
|
|
642
|
+
loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
|
|
643
|
+
)
|
|
644
|
+
);
|
|
645
|
+
const runRef = useRef(null);
|
|
459
646
|
const clientRef = useRef(
|
|
460
647
|
createAgentClient({
|
|
461
648
|
customerId,
|
|
@@ -466,20 +653,15 @@ function useAgentChat({
|
|
|
466
653
|
storageKeyPrefix: resolvedStorageKeyPrefix
|
|
467
654
|
})
|
|
468
655
|
);
|
|
469
|
-
const identityRef = useRef(null);
|
|
470
656
|
const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}`;
|
|
657
|
+
const identityRef = useRef(identityKey);
|
|
471
658
|
useEffect(() => {
|
|
472
|
-
if (identityRef.current === null) {
|
|
473
|
-
identityRef.current = identityKey;
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
659
|
if (identityRef.current === identityKey) {
|
|
477
660
|
return;
|
|
478
661
|
}
|
|
479
662
|
identityRef.current = identityKey;
|
|
480
663
|
runRef.current?.abort();
|
|
481
664
|
runRef.current = null;
|
|
482
|
-
clientRef.current.reset();
|
|
483
665
|
clientRef.current = createAgentClient({
|
|
484
666
|
customerId,
|
|
485
667
|
indexId,
|
|
@@ -488,81 +670,81 @@ function useAgentChat({
|
|
|
488
670
|
visitorSessionId: visitorId,
|
|
489
671
|
storageKeyPrefix: resolvedStorageKeyPrefix
|
|
490
672
|
});
|
|
491
|
-
setState(
|
|
673
|
+
setState(
|
|
674
|
+
stateFromConversation(
|
|
675
|
+
loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
|
|
676
|
+
)
|
|
677
|
+
);
|
|
492
678
|
}, [customerId, identityKey, indexId, runtimeOrigin, resolvedStorageKeyPrefix, version, visitorId]);
|
|
679
|
+
useEffect(() => {
|
|
680
|
+
if (!hasVisitorMessages(state.messages)) return;
|
|
681
|
+
savePersistedAgentConversation(resolvedStorageKeyPrefix, visitorId, {
|
|
682
|
+
messages: state.messages,
|
|
683
|
+
pending: isAgentBusy(state.phase),
|
|
684
|
+
streamingText: state.streamingText
|
|
685
|
+
});
|
|
686
|
+
}, [resolvedStorageKeyPrefix, state.messages, state.phase, state.streamingText, visitorId]);
|
|
493
687
|
const reset = useCallback(() => {
|
|
494
688
|
runRef.current?.abort();
|
|
495
689
|
runRef.current = null;
|
|
496
690
|
clientRef.current.reset();
|
|
691
|
+
clearPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId);
|
|
497
692
|
setState(INITIAL_STATE);
|
|
498
|
-
}, []);
|
|
499
|
-
const
|
|
500
|
-
async (
|
|
501
|
-
|
|
502
|
-
clientRef.current.cancelActive();
|
|
503
|
-
const controller = new AbortController();
|
|
504
|
-
runRef.current = controller;
|
|
693
|
+
}, [resolvedStorageKeyPrefix, visitorId]);
|
|
694
|
+
const runTurn = useCallback(
|
|
695
|
+
async (input) => {
|
|
696
|
+
const { controller, initialText = "", resume, visitorText } = input;
|
|
505
697
|
const { signal } = controller;
|
|
506
698
|
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
699
|
try {
|
|
524
|
-
let streamStarted =
|
|
525
|
-
|
|
700
|
+
let streamStarted = Boolean(initialText);
|
|
701
|
+
let streamed = initialText;
|
|
702
|
+
const planningPromise = resume ? Promise.resolve() : runStatusSequence(signal, (step) => {
|
|
526
703
|
if (streamStarted || !isActiveRun()) return;
|
|
527
704
|
setState((prev) => ({ ...prev, phase: "running-tools", toolSteps: [step] }));
|
|
528
705
|
});
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
706
|
+
const handlers = {
|
|
707
|
+
onStep: (label, detail) => {
|
|
708
|
+
if (streamStarted || !isActiveRun()) return;
|
|
709
|
+
setState((prev) => ({
|
|
710
|
+
...prev,
|
|
711
|
+
phase: "running-tools",
|
|
712
|
+
toolSteps: [{ id: `step-${label}`, label, detail, state: "active" }]
|
|
713
|
+
}));
|
|
714
|
+
},
|
|
715
|
+
onDelta: (delta) => {
|
|
716
|
+
if (!isActiveRun()) return;
|
|
717
|
+
void planningPromise.catch(() => {
|
|
718
|
+
});
|
|
719
|
+
if (!streamStarted) {
|
|
720
|
+
streamStarted = true;
|
|
535
721
|
setState((prev) => ({
|
|
536
722
|
...prev,
|
|
537
|
-
phase: "
|
|
538
|
-
toolSteps: [
|
|
723
|
+
phase: "streaming",
|
|
724
|
+
toolSteps: [],
|
|
725
|
+
streamingText: ""
|
|
539
726
|
}));
|
|
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
727
|
}
|
|
728
|
+
streamed += delta;
|
|
729
|
+
setState((prev) => ({ ...prev, phase: "streaming", streamingText: streamed }));
|
|
730
|
+
},
|
|
731
|
+
onComplete: () => {
|
|
732
|
+
if (!isActiveRun()) return;
|
|
733
|
+
streamStarted = true;
|
|
561
734
|
}
|
|
562
|
-
}
|
|
735
|
+
};
|
|
736
|
+
let finalText = resume ? await clientRef.current.resumeTurn({
|
|
737
|
+
handlers,
|
|
738
|
+
initialText,
|
|
739
|
+
message: visitorText,
|
|
740
|
+
signal
|
|
741
|
+
}) : await clientRef.current.sendTurn(visitorText, { handlers, signal });
|
|
742
|
+
if (resume && finalText === null) {
|
|
743
|
+
finalText = await clientRef.current.sendTurn(visitorText, { handlers, signal });
|
|
744
|
+
}
|
|
563
745
|
await planningPromise.catch(() => {
|
|
564
746
|
});
|
|
565
|
-
if (!isActiveRun()) return;
|
|
747
|
+
if (!isActiveRun() || finalText === null) return;
|
|
566
748
|
const agentMessage = {
|
|
567
749
|
id: `agent-${Date.now()}`,
|
|
568
750
|
role: "agent",
|
|
@@ -578,6 +760,7 @@ function useAgentChat({
|
|
|
578
760
|
followUps: [],
|
|
579
761
|
journey: null
|
|
580
762
|
}));
|
|
763
|
+
runRef.current = null;
|
|
581
764
|
} catch (error) {
|
|
582
765
|
if (error instanceof DOMException && error.name === "AbortError") return;
|
|
583
766
|
if (!isActiveRun()) return;
|
|
@@ -590,14 +773,66 @@ function useAgentChat({
|
|
|
590
773
|
streamingText: "",
|
|
591
774
|
error: message
|
|
592
775
|
}));
|
|
776
|
+
runRef.current = null;
|
|
593
777
|
}
|
|
594
778
|
},
|
|
595
|
-
[
|
|
779
|
+
[]
|
|
596
780
|
);
|
|
781
|
+
const submit = useCallback(
|
|
782
|
+
async (visitorText) => {
|
|
783
|
+
if (runRef.current) {
|
|
784
|
+
runRef.current.abort();
|
|
785
|
+
clientRef.current.cancelActive();
|
|
786
|
+
}
|
|
787
|
+
const controller = new AbortController();
|
|
788
|
+
runRef.current = controller;
|
|
789
|
+
const visitorMessage = {
|
|
790
|
+
id: `visitor-${Date.now()}`,
|
|
791
|
+
role: "visitor",
|
|
792
|
+
text: visitorText,
|
|
793
|
+
createdAt: Date.now()
|
|
794
|
+
};
|
|
795
|
+
setState((prev) => ({
|
|
796
|
+
...prev,
|
|
797
|
+
phase: "thinking",
|
|
798
|
+
messages: [...prev.messages, visitorMessage],
|
|
799
|
+
toolSteps: [{ id: "s1", label: "Starting Eve session", state: "active" }],
|
|
800
|
+
journey: null,
|
|
801
|
+
followUps: [],
|
|
802
|
+
streamingText: "",
|
|
803
|
+
error: null
|
|
804
|
+
}));
|
|
805
|
+
await runTurn({ controller, resume: false, visitorText });
|
|
806
|
+
},
|
|
807
|
+
[runTurn]
|
|
808
|
+
);
|
|
809
|
+
useEffect(() => {
|
|
810
|
+
const conversation = loadPersistedAgentConversation(
|
|
811
|
+
resolvedStorageKeyPrefix,
|
|
812
|
+
visitorId
|
|
813
|
+
);
|
|
814
|
+
if (!conversation?.pending) return;
|
|
815
|
+
const visitorMessage = [...conversation.messages].reverse().find((message) => message.role === "visitor");
|
|
816
|
+
if (!visitorMessage) return;
|
|
817
|
+
const controller = new AbortController();
|
|
818
|
+
runRef.current = controller;
|
|
819
|
+
void runTurn({
|
|
820
|
+
controller,
|
|
821
|
+
initialText: conversation.streamingText,
|
|
822
|
+
resume: true,
|
|
823
|
+
visitorText: visitorMessage.text
|
|
824
|
+
});
|
|
825
|
+
return () => {
|
|
826
|
+
if (runRef.current === controller) {
|
|
827
|
+
runRef.current = null;
|
|
828
|
+
}
|
|
829
|
+
controller.abort();
|
|
830
|
+
};
|
|
831
|
+
}, [identityKey, resolvedStorageKeyPrefix, runTurn, visitorId]);
|
|
597
832
|
useEffect(() => {
|
|
598
833
|
return () => {
|
|
599
834
|
runRef.current?.abort();
|
|
600
|
-
|
|
835
|
+
runRef.current = null;
|
|
601
836
|
};
|
|
602
837
|
}, []);
|
|
603
838
|
return {
|
|
@@ -1188,4 +1423,4 @@ export {
|
|
|
1188
1423
|
AssistEdgeTab,
|
|
1189
1424
|
AgentWidget
|
|
1190
1425
|
};
|
|
1191
|
-
//# sourceMappingURL=chunk-
|
|
1426
|
+
//# sourceMappingURL=chunk-K52TJUV6.js.map
|