@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/react.cjs CHANGED
@@ -221,6 +221,54 @@ function clearPersistedAgentSession(visitorSessionId, options) {
221
221
  }
222
222
 
223
223
  // src/runtime/client.ts
224
+ function isTurnBoundary(event) {
225
+ return event.type === "session.waiting" || event.type === "session.completed" || event.type === "session.failed";
226
+ }
227
+ function applyMessageEvent(event, rendered, handlers) {
228
+ const step = mapStepLabel(event);
229
+ if (step) handlers.onStep?.(step.label, step.detail);
230
+ if (event.type === "session.failed") {
231
+ throw new Error(event.data.message || event.data.code);
232
+ }
233
+ if (event.type === "message.completed") {
234
+ handlers.onComplete?.();
235
+ }
236
+ if (event.type !== "message.appended") return rendered;
237
+ const { messageDelta, messageSoFar } = event.data;
238
+ let delta = messageDelta;
239
+ let next = rendered;
240
+ if (messageSoFar.startsWith(rendered)) {
241
+ delta = messageSoFar.slice(rendered.length);
242
+ next = messageSoFar;
243
+ } else if (messageDelta) {
244
+ next += messageDelta;
245
+ }
246
+ if (delta) handlers.onDelta(delta);
247
+ return next;
248
+ }
249
+ function latestTurnEvents(events) {
250
+ let startIndex = -1;
251
+ for (let index = events.length - 1; index >= 0; index -= 1) {
252
+ if (events[index]?.type === "message.received") {
253
+ startIndex = index;
254
+ break;
255
+ }
256
+ }
257
+ return startIndex >= 0 ? events.slice(startIndex) : [];
258
+ }
259
+ function renderTurn(events) {
260
+ let rendered = "";
261
+ for (const event of events) {
262
+ if (event.type !== "message.appended") continue;
263
+ const { messageDelta, messageSoFar } = event.data;
264
+ if (messageSoFar.startsWith(rendered)) {
265
+ rendered = messageSoFar;
266
+ } else if (messageDelta) {
267
+ rendered += messageDelta;
268
+ }
269
+ }
270
+ return rendered;
271
+ }
224
272
  function mapStepLabel(event) {
225
273
  if (event.type !== "step.started") return null;
226
274
  const stepIndex = event.data.stepIndex;
@@ -256,8 +304,13 @@ var AgentSession = class {
256
304
  return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
257
305
  }
258
306
  reset() {
259
- void this.activeResponse?.cancel().catch(() => {
260
- });
307
+ if (this.activeResponse) {
308
+ void this.activeResponse.cancel().catch(() => {
309
+ });
310
+ } else {
311
+ void this.session?.cancel().catch(() => {
312
+ });
313
+ }
261
314
  this.activeResponse = void 0;
262
315
  this.session = void 0;
263
316
  clearPersistedAgentSession(this.visitorSessionId, this.storeOptions);
@@ -282,7 +335,8 @@ var AgentSession = class {
282
335
  if (this.client && this.clientHost === config.host) {
283
336
  return this.client;
284
337
  }
285
- this.reset();
338
+ this.activeResponse = void 0;
339
+ this.session = void 0;
286
340
  this.client = new import_client2.Client({
287
341
  auth: { bearer: () => this.capability.getAccessToken() },
288
342
  host: config.host,
@@ -331,28 +385,20 @@ var AgentSession = class {
331
385
  this.persistSessionCursor(session);
332
386
  }
333
387
  this.activeResponse = response;
388
+ let streamIndex = session?.state.streamIndex ?? 0;
334
389
  let rendered = "";
335
390
  try {
336
391
  for await (const event of response) {
337
392
  if (signal.aborted) break;
338
- const step = mapStepLabel(event);
339
- if (step) handlers.onStep?.(step.label, step.detail);
340
- if (event.type === "message.appended") {
341
- const { messageDelta, messageSoFar } = event.data;
342
- let delta = messageDelta;
343
- if (messageSoFar.startsWith(rendered)) {
344
- delta = messageSoFar.slice(rendered.length);
345
- rendered = messageSoFar;
346
- } else if (messageDelta) {
347
- rendered += messageDelta;
348
- }
349
- if (delta) handlers.onDelta(delta);
350
- }
351
- if (event.type === "message.completed") {
352
- handlers.onComplete?.();
353
- }
354
- if (event.type === "session.failed") {
355
- throw new Error(event.data.message || event.data.code);
393
+ rendered = applyMessageEvent(event, rendered, handlers);
394
+ streamIndex += 1;
395
+ if (session) {
396
+ savePersistedAgentSession(
397
+ this.visitorSessionId,
398
+ session.state.sessionId,
399
+ streamIndex,
400
+ this.storeOptions
401
+ );
356
402
  }
357
403
  }
358
404
  } finally {
@@ -364,15 +410,83 @@ var AgentSession = class {
364
410
  if (!rendered.trim() && !signal.aborted) {
365
411
  throw new Error("Empty response from runtime");
366
412
  }
367
- if (signal.aborted) {
368
- await response.cancel().catch(() => {
369
- });
413
+ return rendered.trim();
414
+ }
415
+ async resumeTurn(message, signal, handlers, initialText = "") {
416
+ const persisted = loadPersistedAgentSession(this.visitorSessionId, this.storeOptions);
417
+ if (!persisted) return null;
418
+ const client = this.ensureClient();
419
+ const attached = client.sessions.attach(persisted.sessionId, {
420
+ streamIndex: persisted.streamIndex
421
+ });
422
+ const snapshot = await withCapabilityRefresh(
423
+ this.capability,
424
+ () => attached.snapshot({ signal })
425
+ );
426
+ const turnEvents = latestTurnEvents(snapshot.events);
427
+ const received = turnEvents[0];
428
+ if (received?.type !== "message.received" || received.data.message !== message) {
429
+ return null;
430
+ }
431
+ let rendered = renderTurn(turnEvents);
432
+ if (rendered.startsWith(initialText)) {
433
+ const missedText = rendered.slice(initialText.length);
434
+ if (missedText) handlers.onDelta(missedText);
435
+ } else if (initialText.startsWith(rendered)) {
436
+ rendered = initialText;
437
+ } else if (!initialText.startsWith(rendered)) {
438
+ rendered = initialText + rendered;
439
+ }
440
+ let session = client.sessions.attach(snapshot.session.sessionId, {
441
+ streamIndex: snapshot.session.streamIndex
442
+ });
443
+ this.session = session;
444
+ this.persistSessionCursor(session);
445
+ let snapshotBoundary;
446
+ for (let index = turnEvents.length - 1; index >= 0; index -= 1) {
447
+ const event = turnEvents[index];
448
+ if (event && isTurnBoundary(event)) {
449
+ snapshotBoundary = event;
450
+ break;
451
+ }
452
+ }
453
+ if (snapshotBoundary) {
454
+ if (snapshotBoundary.type === "session.failed") {
455
+ throw new Error(snapshotBoundary.data.message || snapshotBoundary.data.code);
456
+ }
457
+ handlers.onComplete?.();
458
+ if (!rendered.trim()) throw new Error("Empty response from runtime");
459
+ return rendered.trim();
460
+ }
461
+ let streamIndex = snapshot.session.streamIndex;
462
+ for await (const event of session.stream({ signal })) {
463
+ if (signal.aborted) break;
464
+ rendered = applyMessageEvent(event, rendered, handlers);
465
+ streamIndex += 1;
466
+ savePersistedAgentSession(
467
+ this.visitorSessionId,
468
+ session.state.sessionId,
469
+ streamIndex,
470
+ this.storeOptions
471
+ );
472
+ if (isTurnBoundary(event)) break;
473
+ }
474
+ session = client.sessions.attach(session.state.sessionId, { streamIndex });
475
+ this.session = session;
476
+ this.persistSessionCursor(session);
477
+ if (!rendered.trim() && !signal.aborted) {
478
+ throw new Error("Empty response from runtime");
370
479
  }
371
480
  return rendered.trim();
372
481
  }
373
482
  cancelActive() {
374
- this.activeResponse?.cancel().catch(() => {
375
- });
483
+ if (this.activeResponse) {
484
+ this.activeResponse.cancel().catch(() => {
485
+ });
486
+ } else {
487
+ this.session?.cancel().catch(() => {
488
+ });
489
+ }
376
490
  }
377
491
  };
378
492
  function createAgentClient(options) {
@@ -406,6 +520,12 @@ function createAgentClient(options) {
406
520
  sendOptions.signal ?? new AbortController().signal,
407
521
  sendOptions.handlers
408
522
  ),
523
+ resumeTurn: (resumeOptions) => session.resumeTurn(
524
+ resumeOptions.message,
525
+ resumeOptions.signal ?? new AbortController().signal,
526
+ resumeOptions.handlers,
527
+ resumeOptions.initialText
528
+ ),
409
529
  reset: () => session.reset(),
410
530
  cancelActive: () => session.cancelActive(),
411
531
  getActiveSessionId: () => session.getActiveSessionId()
@@ -434,6 +554,58 @@ function formatAgentError(error) {
434
554
  return "Runtime request failed";
435
555
  }
436
556
 
557
+ // src/react/persisted-conversation.ts
558
+ var CONVERSATION_VERSION = 1;
559
+ function conversationKey(storageKeyPrefix, visitorSessionId) {
560
+ return `${storageKeyPrefix}:conversation:${visitorSessionId}`;
561
+ }
562
+ function parseMessage(value) {
563
+ if (typeof value !== "object" || value === null) return null;
564
+ const record = value;
565
+ if (typeof record.id !== "string" || record.role !== "agent" && record.role !== "visitor" || typeof record.text !== "string" || typeof record.createdAt !== "number" || !Number.isFinite(record.createdAt)) {
566
+ return null;
567
+ }
568
+ return {
569
+ id: record.id,
570
+ role: record.role,
571
+ text: record.text,
572
+ createdAt: record.createdAt
573
+ };
574
+ }
575
+ function loadPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
576
+ if (typeof sessionStorage === "undefined") return null;
577
+ const raw = sessionStorage.getItem(conversationKey(storageKeyPrefix, visitorSessionId));
578
+ if (!raw) return null;
579
+ try {
580
+ const value = JSON.parse(raw);
581
+ if (typeof value !== "object" || value === null) return null;
582
+ const record = value;
583
+ if (record.version !== CONVERSATION_VERSION || !Array.isArray(record.messages) || typeof record.pending !== "boolean" || typeof record.streamingText !== "string") {
584
+ return null;
585
+ }
586
+ const messages = record.messages.map(parseMessage);
587
+ if (messages.some((message) => message === null)) return null;
588
+ return {
589
+ messages: messages.filter((message) => message !== null),
590
+ pending: record.pending,
591
+ streamingText: record.streamingText
592
+ };
593
+ } catch {
594
+ return null;
595
+ }
596
+ }
597
+ function savePersistedAgentConversation(storageKeyPrefix, visitorSessionId, conversation) {
598
+ if (typeof sessionStorage === "undefined") return;
599
+ sessionStorage.setItem(
600
+ conversationKey(storageKeyPrefix, visitorSessionId),
601
+ JSON.stringify({ version: CONVERSATION_VERSION, ...conversation })
602
+ );
603
+ }
604
+ function clearPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
605
+ if (typeof sessionStorage === "undefined") return;
606
+ sessionStorage.removeItem(conversationKey(storageKeyPrefix, visitorSessionId));
607
+ }
608
+
437
609
  // src/react/hooks/useAgentChat.ts
438
610
  var GREETING_MESSAGE = {
439
611
  id: "greeting",
@@ -450,6 +622,15 @@ var INITIAL_STATE = {
450
622
  streamingText: "",
451
623
  error: null
452
624
  };
625
+ function stateFromConversation(conversation) {
626
+ if (!conversation || conversation.messages.length === 0) return INITIAL_STATE;
627
+ return {
628
+ ...INITIAL_STATE,
629
+ messages: conversation.messages,
630
+ phase: conversation.pending ? conversation.streamingText ? "streaming" : "thinking" : "complete",
631
+ streamingText: conversation.streamingText
632
+ };
633
+ }
453
634
  var STATUS_SEQUENCE = [
454
635
  { id: "s1", label: "Starting Eve session", ms: 400 },
455
636
  { id: "s2", label: "Connecting to runtime", ms: 500 }
@@ -481,8 +662,6 @@ function useAgentChat({
481
662
  visitorSessionId,
482
663
  storageKeyPrefix
483
664
  }) {
484
- const [state, setState] = (0, import_react.useState)(INITIAL_STATE);
485
- const runRef = (0, import_react.useRef)(null);
486
665
  const resolvedStorageKeyPrefix = (0, import_react.useMemo)(
487
666
  () => storageKeyPrefix?.trim() || buildAgentStorageKeyPrefix({ customerId, indexId, version, runtimeOrigin }),
488
667
  [customerId, indexId, runtimeOrigin, storageKeyPrefix, version]
@@ -491,6 +670,12 @@ function useAgentChat({
491
670
  () => visitorSessionId?.trim() || getOrCreateVisitorSessionId({ storageKeyPrefix: resolvedStorageKeyPrefix }),
492
671
  [resolvedStorageKeyPrefix, visitorSessionId]
493
672
  );
673
+ const [state, setState] = (0, import_react.useState)(
674
+ () => stateFromConversation(
675
+ loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
676
+ )
677
+ );
678
+ const runRef = (0, import_react.useRef)(null);
494
679
  const clientRef = (0, import_react.useRef)(
495
680
  createAgentClient({
496
681
  customerId,
@@ -501,20 +686,15 @@ function useAgentChat({
501
686
  storageKeyPrefix: resolvedStorageKeyPrefix
502
687
  })
503
688
  );
504
- const identityRef = (0, import_react.useRef)(null);
505
689
  const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}`;
690
+ const identityRef = (0, import_react.useRef)(identityKey);
506
691
  (0, import_react.useEffect)(() => {
507
- if (identityRef.current === null) {
508
- identityRef.current = identityKey;
509
- return;
510
- }
511
692
  if (identityRef.current === identityKey) {
512
693
  return;
513
694
  }
514
695
  identityRef.current = identityKey;
515
696
  runRef.current?.abort();
516
697
  runRef.current = null;
517
- clientRef.current.reset();
518
698
  clientRef.current = createAgentClient({
519
699
  customerId,
520
700
  indexId,
@@ -523,81 +703,81 @@ function useAgentChat({
523
703
  visitorSessionId: visitorId,
524
704
  storageKeyPrefix: resolvedStorageKeyPrefix
525
705
  });
526
- setState(INITIAL_STATE);
706
+ setState(
707
+ stateFromConversation(
708
+ loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
709
+ )
710
+ );
527
711
  }, [customerId, identityKey, indexId, runtimeOrigin, resolvedStorageKeyPrefix, version, visitorId]);
712
+ (0, import_react.useEffect)(() => {
713
+ if (!hasVisitorMessages(state.messages)) return;
714
+ savePersistedAgentConversation(resolvedStorageKeyPrefix, visitorId, {
715
+ messages: state.messages,
716
+ pending: isAgentBusy(state.phase),
717
+ streamingText: state.streamingText
718
+ });
719
+ }, [resolvedStorageKeyPrefix, state.messages, state.phase, state.streamingText, visitorId]);
528
720
  const reset = (0, import_react.useCallback)(() => {
529
721
  runRef.current?.abort();
530
722
  runRef.current = null;
531
723
  clientRef.current.reset();
724
+ clearPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId);
532
725
  setState(INITIAL_STATE);
533
- }, []);
534
- const submit = (0, import_react.useCallback)(
535
- async (visitorText) => {
536
- runRef.current?.abort();
537
- clientRef.current.cancelActive();
538
- const controller = new AbortController();
539
- runRef.current = controller;
726
+ }, [resolvedStorageKeyPrefix, visitorId]);
727
+ const runTurn = (0, import_react.useCallback)(
728
+ async (input) => {
729
+ const { controller, initialText = "", resume, visitorText } = input;
540
730
  const { signal } = controller;
541
731
  const isActiveRun = () => runRef.current === controller && !signal.aborted;
542
- const visitorMessage = {
543
- id: `visitor-${Date.now()}`,
544
- role: "visitor",
545
- text: visitorText,
546
- createdAt: Date.now()
547
- };
548
- setState((prev) => ({
549
- ...prev,
550
- phase: "thinking",
551
- messages: [...prev.messages, visitorMessage],
552
- toolSteps: [{ id: "s1", label: "Starting Eve session", state: "active" }],
553
- journey: null,
554
- followUps: [],
555
- streamingText: "",
556
- error: null
557
- }));
558
732
  try {
559
- let streamStarted = false;
560
- const planningPromise = runStatusSequence(signal, (step) => {
733
+ let streamStarted = Boolean(initialText);
734
+ let streamed = initialText;
735
+ const planningPromise = resume ? Promise.resolve() : runStatusSequence(signal, (step) => {
561
736
  if (streamStarted || !isActiveRun()) return;
562
737
  setState((prev) => ({ ...prev, phase: "running-tools", toolSteps: [step] }));
563
738
  });
564
- let streamed = "";
565
- const finalText = await clientRef.current.sendTurn(visitorText, {
566
- signal,
567
- handlers: {
568
- onStep: (label, detail) => {
569
- if (streamStarted || !isActiveRun()) return;
739
+ const handlers = {
740
+ onStep: (label, detail) => {
741
+ if (streamStarted || !isActiveRun()) return;
742
+ setState((prev) => ({
743
+ ...prev,
744
+ phase: "running-tools",
745
+ toolSteps: [{ id: `step-${label}`, label, detail, state: "active" }]
746
+ }));
747
+ },
748
+ onDelta: (delta) => {
749
+ if (!isActiveRun()) return;
750
+ void planningPromise.catch(() => {
751
+ });
752
+ if (!streamStarted) {
753
+ streamStarted = true;
570
754
  setState((prev) => ({
571
755
  ...prev,
572
- phase: "running-tools",
573
- toolSteps: [{ id: `step-${label}`, label, detail, state: "active" }]
756
+ phase: "streaming",
757
+ toolSteps: [],
758
+ streamingText: ""
574
759
  }));
575
- },
576
- onDelta: (delta) => {
577
- if (!isActiveRun()) return;
578
- void planningPromise.catch(() => {
579
- });
580
- if (!streamStarted) {
581
- streamStarted = true;
582
- setState((prev) => ({
583
- ...prev,
584
- phase: "streaming",
585
- toolSteps: [],
586
- streamingText: ""
587
- }));
588
- }
589
- streamed += delta;
590
- setState((prev) => ({ ...prev, phase: "streaming", streamingText: streamed }));
591
- },
592
- onComplete: () => {
593
- if (!isActiveRun()) return;
594
- streamStarted = true;
595
760
  }
761
+ streamed += delta;
762
+ setState((prev) => ({ ...prev, phase: "streaming", streamingText: streamed }));
763
+ },
764
+ onComplete: () => {
765
+ if (!isActiveRun()) return;
766
+ streamStarted = true;
596
767
  }
597
- });
768
+ };
769
+ let finalText = resume ? await clientRef.current.resumeTurn({
770
+ handlers,
771
+ initialText,
772
+ message: visitorText,
773
+ signal
774
+ }) : await clientRef.current.sendTurn(visitorText, { handlers, signal });
775
+ if (resume && finalText === null) {
776
+ finalText = await clientRef.current.sendTurn(visitorText, { handlers, signal });
777
+ }
598
778
  await planningPromise.catch(() => {
599
779
  });
600
- if (!isActiveRun()) return;
780
+ if (!isActiveRun() || finalText === null) return;
601
781
  const agentMessage = {
602
782
  id: `agent-${Date.now()}`,
603
783
  role: "agent",
@@ -613,6 +793,7 @@ function useAgentChat({
613
793
  followUps: [],
614
794
  journey: null
615
795
  }));
796
+ runRef.current = null;
616
797
  } catch (error) {
617
798
  if (error instanceof DOMException && error.name === "AbortError") return;
618
799
  if (!isActiveRun()) return;
@@ -625,14 +806,66 @@ function useAgentChat({
625
806
  streamingText: "",
626
807
  error: message
627
808
  }));
809
+ runRef.current = null;
628
810
  }
629
811
  },
630
- [customerId, indexId, runtimeOrigin, resolvedStorageKeyPrefix, version, visitorId]
812
+ []
813
+ );
814
+ const submit = (0, import_react.useCallback)(
815
+ async (visitorText) => {
816
+ if (runRef.current) {
817
+ runRef.current.abort();
818
+ clientRef.current.cancelActive();
819
+ }
820
+ const controller = new AbortController();
821
+ runRef.current = controller;
822
+ const visitorMessage = {
823
+ id: `visitor-${Date.now()}`,
824
+ role: "visitor",
825
+ text: visitorText,
826
+ createdAt: Date.now()
827
+ };
828
+ setState((prev) => ({
829
+ ...prev,
830
+ phase: "thinking",
831
+ messages: [...prev.messages, visitorMessage],
832
+ toolSteps: [{ id: "s1", label: "Starting Eve session", state: "active" }],
833
+ journey: null,
834
+ followUps: [],
835
+ streamingText: "",
836
+ error: null
837
+ }));
838
+ await runTurn({ controller, resume: false, visitorText });
839
+ },
840
+ [runTurn]
631
841
  );
842
+ (0, import_react.useEffect)(() => {
843
+ const conversation = loadPersistedAgentConversation(
844
+ resolvedStorageKeyPrefix,
845
+ visitorId
846
+ );
847
+ if (!conversation?.pending) return;
848
+ const visitorMessage = [...conversation.messages].reverse().find((message) => message.role === "visitor");
849
+ if (!visitorMessage) return;
850
+ const controller = new AbortController();
851
+ runRef.current = controller;
852
+ void runTurn({
853
+ controller,
854
+ initialText: conversation.streamingText,
855
+ resume: true,
856
+ visitorText: visitorMessage.text
857
+ });
858
+ return () => {
859
+ if (runRef.current === controller) {
860
+ runRef.current = null;
861
+ }
862
+ controller.abort();
863
+ };
864
+ }, [identityKey, resolvedStorageKeyPrefix, runTurn, visitorId]);
632
865
  (0, import_react.useEffect)(() => {
633
866
  return () => {
634
867
  runRef.current?.abort();
635
- clientRef.current.cancelActive();
868
+ runRef.current = null;
636
869
  };
637
870
  }, []);
638
871
  return {
@@ -869,15 +1102,27 @@ function FollowUpChips({
869
1102
  }
870
1103
 
871
1104
  // src/react/components/MessageBubble/MessageBubble.tsx
1105
+ var import_streamdown = require("streamdown");
1106
+ var import_styles = require("streamdown/styles.css");
872
1107
  var import_jsx_runtime5 = require("react/jsx-runtime");
873
1108
  function MessageBubble({ message }) {
874
1109
  if (message.role === "visitor") {
875
1110
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "message-bubble__text", children: message.text }) });
876
1111
  }
877
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("article", { className: "message-bubble message-bubble--agent", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "message-bubble__text", children: [
878
- message.text,
879
- message.streaming ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "tool-timeline__cursor", "aria-hidden": "true" }) : null
880
- ] }) });
1112
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("article", { className: "message-bubble message-bubble--agent", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "message-bubble__text", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1113
+ import_streamdown.Streamdown,
1114
+ {
1115
+ animated: true,
1116
+ caret: "circle",
1117
+ className: "message-bubble__markdown",
1118
+ controls: false,
1119
+ isAnimating: message.streaming,
1120
+ linkSafety: { enabled: false },
1121
+ mode: message.streaming ? "streaming" : "static",
1122
+ skipHtml: true,
1123
+ children: message.text
1124
+ }
1125
+ ) }) });
881
1126
  }
882
1127
 
883
1128
  // src/react/components/AgentRail/AgentRail.tsx