@meshagent/meshagent-tailwind 0.41.4 → 0.41.6

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +33 -0
  3. package/dist/cjs/chat/chat-thread.js +15 -10
  4. package/dist/cjs/chat/dataset-chat-thread.d.ts +4 -1
  5. package/dist/cjs/chat/dataset-chat-thread.js +130 -157
  6. package/dist/cjs/chat/multi-thread-view.d.ts +4 -1
  7. package/dist/cjs/chat/multi-thread-view.js +4 -0
  8. package/dist/cjs/chat/new-chat-thread.d.ts +4 -1
  9. package/dist/cjs/chat/new-chat-thread.js +43 -87
  10. package/dist/cjs/file-preview/file-preview.d.ts +6 -0
  11. package/dist/cjs/file-preview/file-preview.js +220 -0
  12. package/dist/cjs/meetings/camera-grid.d.ts +46 -0
  13. package/dist/cjs/meetings/camera-grid.js +435 -0
  14. package/dist/cjs/meetings/controls.d.ts +4 -2
  15. package/dist/cjs/meetings/controls.js +9 -3
  16. package/dist/cjs/meetings/lobby.d.ts +17 -0
  17. package/dist/cjs/meetings/lobby.js +595 -0
  18. package/dist/cjs/meetings/meeting-scope.d.ts +7 -6
  19. package/dist/cjs/meetings/meeting-scope.js +64 -15
  20. package/dist/cjs/meetings/meeting-view.d.ts +6 -0
  21. package/dist/cjs/meetings/meeting-view.js +635 -0
  22. package/dist/cjs/meetings/meetings.d.ts +3 -0
  23. package/dist/cjs/meetings/meetings.js +3 -0
  24. package/dist/cjs/meetings/wake-lock.js +2 -2
  25. package/dist/esm/chat/chat-thread.js +15 -10
  26. package/dist/esm/chat/dataset-chat-thread.d.ts +4 -1
  27. package/dist/esm/chat/dataset-chat-thread.js +129 -133
  28. package/dist/esm/chat/multi-thread-view.d.ts +4 -1
  29. package/dist/esm/chat/multi-thread-view.js +4 -0
  30. package/dist/esm/chat/new-chat-thread.d.ts +4 -1
  31. package/dist/esm/chat/new-chat-thread.js +43 -87
  32. package/dist/esm/file-preview/file-preview.d.ts +6 -0
  33. package/dist/esm/file-preview/file-preview.js +220 -0
  34. package/dist/esm/meetings/camera-grid.d.ts +46 -0
  35. package/dist/esm/meetings/camera-grid.js +405 -0
  36. package/dist/esm/meetings/controls.d.ts +4 -2
  37. package/dist/esm/meetings/controls.js +9 -3
  38. package/dist/esm/meetings/lobby.d.ts +17 -0
  39. package/dist/esm/meetings/lobby.js +595 -0
  40. package/dist/esm/meetings/meeting-scope.d.ts +7 -6
  41. package/dist/esm/meetings/meeting-scope.js +71 -16
  42. package/dist/esm/meetings/meeting-view.d.ts +6 -0
  43. package/dist/esm/meetings/meeting-view.js +630 -0
  44. package/dist/esm/meetings/meetings.d.ts +3 -0
  45. package/dist/esm/meetings/meetings.js +3 -0
  46. package/dist/esm/meetings/wake-lock.js +2 -2
  47. package/dist/index.css +1 -1
  48. package/package.json +9 -5
@@ -225,7 +225,7 @@ function MarkdownBlock({ text }) {
225
225
  children
226
226
  }
227
227
  ),
228
- p: ({ children, ...props }) => /* @__PURE__ */ jsx("p", { ...props, className: "mb-2 last:mb-0", children }),
228
+ p: ({ children, ...props }) => /* @__PURE__ */ jsx("p", { ...props, className: "mb-2 last:mb-0 overflow-hidden max-w-full", children }),
229
229
  table: ({ children, ...props }) => /* @__PURE__ */ jsx("div", { className: "my-4 w-full overflow-x-auto", children: /* @__PURE__ */ jsx(
230
230
  "table",
231
231
  {
@@ -265,6 +265,17 @@ function MarkdownBlock({ text }) {
265
265
  className: "mb-2 ml-6 list-decimal last:mb-0",
266
266
  children
267
267
  }
268
+ ),
269
+ a: ({ children, href, ...props }) => /* @__PURE__ */ jsx(
270
+ "a",
271
+ {
272
+ ...props,
273
+ href,
274
+ target: "_blank",
275
+ rel: "noopener noreferrer",
276
+ className: "text-primary underline overflow-ellipsis inline-block max-w-full overflow-x-hidden",
277
+ children
278
+ }
268
279
  )
269
280
  },
270
281
  children: text
@@ -360,10 +371,7 @@ function ThreadAttachment({ room, attachment, onImageSettled }) {
360
371
  }
361
372
  return /* @__PURE__ */ jsx(FileAttachment, { room, path });
362
373
  }
363
- function ChatBubble({
364
- text,
365
- mine
366
- }) {
374
+ function ChatBubble({ text, mine }) {
367
375
  if (text.trim() === "") {
368
376
  return null;
369
377
  }
@@ -371,7 +379,7 @@ function ChatBubble({
371
379
  "div",
372
380
  {
373
381
  className: cn(
374
- "w-fit max-w-[85%] rounded-md px-4 py-3 text-sm leading-6 shadow-xs sm:max-w-2xl",
382
+ "w-fit max-w-[85%] rounded-md px-4 py-3 text-sm leading-6 shadow-xs sm:w-2xl",
375
383
  mine ? "bg-secondary/85 text-foreground" : "bg-muted/70 text-foreground"
376
384
  ),
377
385
  children: /* @__PURE__ */ jsx(MarkdownBlock, { text })
@@ -440,10 +448,7 @@ function defaultEventHeadline(kind, state, eventName) {
440
448
  }
441
449
  return eventName.replace(/[._]/gu, " ");
442
450
  }
443
- function EventRow({
444
- room,
445
- message
446
- }) {
451
+ function EventRow({ room, message }) {
447
452
  const method = getTrimmedStringAttribute(message, "method") || "agent/event";
448
453
  const eventName = getTrimmedStringAttribute(message, "name") || getTrimmedStringAttribute(message, "event_type") || method.replace(/\//gu, ".");
449
454
  const kind = getTrimmedStringAttribute(message, "kind").toLowerCase();
@@ -1,8 +1,11 @@
1
1
  import type { ReactElement } from "react";
2
2
  import type { RoomClient } from "@meshagent/meshagent";
3
+ import type { BaseChatClient } from "@meshagent/meshagent-agents";
3
4
  export interface DatasetChatThreadProps {
4
5
  room: RoomClient;
5
6
  path: string;
7
+ chatClient?: BaseChatClient;
8
+ disposeChatClient?: boolean;
6
9
  agentName?: string;
7
10
  emptyStateTitle?: string;
8
11
  emptyStateDescription?: string;
@@ -10,4 +13,4 @@ export interface DatasetChatThreadProps {
10
13
  initialShowCompletedToolCalls?: boolean;
11
14
  openFile?: (path: string) => void | Promise<void>;
12
15
  }
13
- export declare function DatasetChatThread({ room, path, agentName, emptyStateTitle, emptyStateDescription, inputPlaceholder, initialShowCompletedToolCalls, openFile, }: DatasetChatThreadProps): ReactElement;
16
+ export declare function DatasetChatThread({ room, path, chatClient, disposeChatClient, agentName, emptyStateTitle, emptyStateDescription, inputPlaceholder, initialShowCompletedToolCalls, openFile, }: DatasetChatThreadProps): ReactElement;
@@ -3,10 +3,33 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
3
  import {
4
4
  DatasetJson,
5
5
  DatasetStruct,
6
- RoomMessageEvent,
7
6
  RoomServerException
8
7
  } from "@meshagent/meshagent";
9
- import { subscribe } from "@meshagent/meshagent-react";
8
+ import {
9
+ MessagingChatClient,
10
+ agentFileContentDeltaType,
11
+ agentFileContentEndedType,
12
+ agentFileContentStartedType,
13
+ agentImageGenerationCompletedType,
14
+ agentImageGenerationFailedType,
15
+ agentImageGenerationPartialType,
16
+ agentImageGenerationStartedType,
17
+ agentReasoningContentDeltaType,
18
+ agentReasoningContentEndedType,
19
+ agentReasoningContentStartedType,
20
+ agentTextContentDeltaType,
21
+ agentTextContentEndedType,
22
+ agentToolCallEndedType,
23
+ agentToolCallInProgressType,
24
+ agentToolCallPendingType,
25
+ agentToolCallStartedType,
26
+ agentTurnStartAcceptedType,
27
+ agentTurnStartRejectedType,
28
+ agentTurnStartedType,
29
+ agentTurnSteerAcceptedType,
30
+ agentTurnSteerRejectedType,
31
+ agentTurnSteeredType
32
+ } from "@meshagent/meshagent-agents";
10
33
  import { Download, FileText, ImageOff } from "lucide-react";
11
34
  import ReactMarkdown from "react-markdown";
12
35
  import rehypeHighlight from "rehype-highlight";
@@ -17,37 +40,9 @@ import { ChatTypingIndicator } from "./chat-typing-indicator";
17
40
  import { Button } from "../components/ui/button";
18
41
  import { Spinner } from "../components/ui/spinner";
19
42
  import { MeshagentFileUpload, fileToAsyncIterable } from "./file-attachment";
20
- import { useThreadStatus } from "./chat-hooks";
43
+ import { PendingAgentMessage, useThreadStatus } from "./chat-hooks";
21
44
  import { cn } from "../lib/utils";
22
45
  import { timeAgo } from "./chat-thread";
23
- const agentRoomMessageType = "agent-message";
24
- const agentTurnStartType = "meshagent.agent.turn.start";
25
- const agentTurnSteerType = "meshagent.agent.turn.steer";
26
- const agentTurnInterruptType = "meshagent.agent.turn.interrupt";
27
- const agentThreadOpenType = "meshagent.agent.thread.open";
28
- const agentThreadCloseType = "meshagent.agent.thread.close";
29
- const agentTurnStartAcceptedType = "meshagent.agent.turn.start.accepted";
30
- const agentTurnStartRejectedType = "meshagent.agent.turn.start.rejected";
31
- const agentTurnSteerAcceptedType = "meshagent.agent.turn.steer.accepted";
32
- const agentTurnSteerRejectedType = "meshagent.agent.turn.steer.rejected";
33
- const agentTurnStartedType = "meshagent.agent.turn.started";
34
- const agentTurnSteeredType = "meshagent.agent.turn.steered";
35
- const agentTextContentDeltaType = "meshagent.agent.text_content.delta";
36
- const agentTextContentEndedType = "meshagent.agent.text_content.ended";
37
- const agentReasoningContentStartedType = "meshagent.agent.reasoning_content.started";
38
- const agentReasoningContentDeltaType = "meshagent.agent.reasoning_content.delta";
39
- const agentReasoningContentEndedType = "meshagent.agent.reasoning_content.ended";
40
- const agentFileContentStartedType = "meshagent.agent.file_content.started";
41
- const agentFileContentDeltaType = "meshagent.agent.file_content.delta";
42
- const agentFileContentEndedType = "meshagent.agent.file_content.ended";
43
- const agentToolCallPendingType = "meshagent.agent.tool_call.pending";
44
- const agentToolCallInProgressType = "meshagent.agent.tool_call.in_progress";
45
- const agentToolCallStartedType = "meshagent.agent.tool_call.started";
46
- const agentToolCallEndedType = "meshagent.agent.tool_call.ended";
47
- const agentImageGenerationStartedType = "meshagent.agent.image_generation.started";
48
- const agentImageGenerationPartialType = "meshagent.agent.image_generation.partial";
49
- const agentImageGenerationCompletedType = "meshagent.agent.image_generation.completed";
50
- const agentImageGenerationFailedType = "meshagent.agent.image_generation.failed";
51
46
  const stickyBottomThresholdPx = 24;
52
47
  const maxPreviewEdgePx = 312.5;
53
48
  function createDatasetThreadModel() {
@@ -991,6 +986,26 @@ function describeError(error) {
991
986
  }
992
987
  return String(error);
993
988
  }
989
+ function pendingAgentMessageFromInput(pending) {
990
+ const payload = pending.payload.toJson();
991
+ const parsed = PendingAgentMessage.fromQueueJson({
992
+ ...payload,
993
+ message_type: pending.messageType,
994
+ created_at: pending.createdAt.toISOString()
995
+ });
996
+ return new PendingAgentMessage({
997
+ messageId: parsed.messageId,
998
+ messageType: parsed.messageType,
999
+ threadPath: parsed.threadPath,
1000
+ text: parsed.text,
1001
+ attachments: parsed.attachments,
1002
+ senderName: parsed.senderName,
1003
+ createdAt: parsed.createdAt,
1004
+ matchByContentOnly: parsed.matchByContentOnly,
1005
+ awaitingAcceptance: pending.awaitingAcceptance,
1006
+ awaitingOnline: pending.awaitingOnline
1007
+ });
1008
+ }
994
1009
  function MarkdownBlock({ text }) {
995
1010
  return /* @__PURE__ */ jsx(
996
1011
  ReactMarkdown,
@@ -1407,24 +1422,11 @@ function EmptyState({
1407
1422
  function ErrorBanner({ message }) {
1408
1423
  return /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-[912px] whitespace-pre-wrap rounded-md border border-destructive/30 bg-destructive/5 px-4 py-3 text-sm text-destructive", children: message });
1409
1424
  }
1410
- function sendThreadSubscriptionMessage({
1411
- room,
1412
- agent,
1413
- messageType,
1414
- path
1415
- }) {
1416
- void room.messaging.sendMessage({
1417
- to: agent,
1418
- type: agentRoomMessageType,
1419
- ignoreOffline: true,
1420
- message: {
1421
- payload: { type: messageType, thread_id: path }
1422
- }
1423
- }).catch(() => void 0);
1424
- }
1425
1425
  function DatasetChatThread({
1426
1426
  room,
1427
1427
  path,
1428
+ chatClient,
1429
+ disposeChatClient = false,
1428
1430
  agentName,
1429
1431
  emptyStateTitle,
1430
1432
  emptyStateDescription,
@@ -1438,14 +1440,35 @@ function DatasetChatThread({
1438
1440
  const [sendError, setSendError] = useState(null);
1439
1441
  const [showCompletedToolCalls, setShowCompletedToolCalls] = useState(initialShowCompletedToolCalls);
1440
1442
  const status = useThreadStatus({ room, path, agentName });
1441
- const agentParticipant = findAgentParticipant(room, agentName);
1442
1443
  const localParticipantName = getParticipantName(room.localParticipant);
1443
1444
  const scrollContainerRef = useRef(null);
1444
1445
  const contentRef = useRef(null);
1445
1446
  const stickToBottomRef = useRef(true);
1447
+ const threadSessionRef = useRef(null);
1448
+ const threadSessionCursorRef = useRef(0);
1449
+ const [threadSessionVersion, setThreadSessionVersion] = useState(0);
1450
+ const ownsChatClient = chatClient == null;
1451
+ const activeChatClient = useMemo(
1452
+ () => chatClient ?? new MessagingChatClient({ room, agentName }),
1453
+ [agentName, chatClient, room]
1454
+ );
1455
+ const agentParticipant = activeChatClient.agentParticipant() ?? findAgentParticipant(room, agentName);
1446
1456
  const bumpModelVersion = useCallback(() => {
1447
1457
  setModelVersion((current) => current + 1);
1448
1458
  }, []);
1459
+ useEffect(() => {
1460
+ void activeChatClient.start();
1461
+ const handleChange = () => {
1462
+ setThreadSessionVersion((current) => current + 1);
1463
+ };
1464
+ activeChatClient.addListener(handleChange);
1465
+ return () => {
1466
+ activeChatClient.removeListener(handleChange);
1467
+ if (ownsChatClient || disposeChatClient) {
1468
+ void activeChatClient.stop();
1469
+ }
1470
+ };
1471
+ }, [activeChatClient, disposeChatClient, ownsChatClient]);
1449
1472
  useEffect(() => {
1450
1473
  const model2 = createDatasetThreadModel();
1451
1474
  modelRef.current = model2;
@@ -1523,46 +1546,41 @@ function DatasetChatThread({
1523
1546
  };
1524
1547
  }, [bumpModelVersion, path, room]);
1525
1548
  useEffect(() => {
1526
- const subscription = subscribe(room.listen(), {
1527
- next: (event) => {
1528
- if (!(event instanceof RoomMessageEvent)) {
1529
- return;
1530
- }
1531
- if (event.message.type !== agentRoomMessageType) {
1532
- return;
1533
- }
1534
- const payload = event.message.message.payload;
1535
- if (!isRecord(payload)) {
1536
- return;
1537
- }
1538
- if (applyAgentMessagePayload(modelRef.current, payload, path)) {
1539
- bumpModelVersion();
1549
+ if (isTmpThreadPath(path)) {
1550
+ threadSessionRef.current = null;
1551
+ threadSessionCursorRef.current = 0;
1552
+ setThreadSessionVersion((current) => current + 1);
1553
+ return;
1554
+ }
1555
+ const session = activeChatClient.openThread(path);
1556
+ threadSessionRef.current = session;
1557
+ threadSessionCursorRef.current = 0;
1558
+ const drainSessionMessages = () => {
1559
+ let changed = false;
1560
+ const messages = session.messages;
1561
+ while (threadSessionCursorRef.current < messages.length) {
1562
+ const event = messages[threadSessionCursorRef.current];
1563
+ threadSessionCursorRef.current += 1;
1564
+ if (applyAgentMessagePayload(modelRef.current, event.payload, path)) {
1565
+ changed = true;
1540
1566
  }
1541
1567
  }
1542
- });
1543
- return () => {
1544
- subscription.unsubscribe();
1568
+ if (changed) {
1569
+ bumpModelVersion();
1570
+ }
1571
+ setThreadSessionVersion((current) => current + 1);
1545
1572
  };
1546
- }, [bumpModelVersion, path, room]);
1547
- useEffect(() => {
1548
- if (!agentParticipant) {
1549
- return;
1550
- }
1551
- sendThreadSubscriptionMessage({
1552
- room,
1553
- agent: agentParticipant,
1554
- messageType: agentThreadOpenType,
1555
- path
1556
- });
1573
+ session.addListener(drainSessionMessages);
1574
+ drainSessionMessages();
1557
1575
  return () => {
1558
- sendThreadSubscriptionMessage({
1559
- room,
1560
- agent: agentParticipant,
1561
- messageType: agentThreadCloseType,
1562
- path
1563
- });
1576
+ session.removeListener(drainSessionMessages);
1577
+ if (threadSessionRef.current === session) {
1578
+ threadSessionRef.current = null;
1579
+ threadSessionCursorRef.current = 0;
1580
+ }
1581
+ void session.close().catch(() => void 0);
1564
1582
  };
1565
- }, [agentParticipant, path, room]);
1583
+ }, [activeChatClient, bumpModelVersion, path]);
1566
1584
  const allMessages = useMemo(() => {
1567
1585
  const model2 = modelRef.current;
1568
1586
  const mergedRowsByItemId = /* @__PURE__ */ new Map();
@@ -1587,29 +1605,24 @@ function DatasetChatThread({
1587
1605
  for (const pending of status.pendingMessages) {
1588
1606
  combined.set(pending.messageId, pending);
1589
1607
  }
1608
+ for (const pending of threadSessionRef.current?.pendingInputs ?? []) {
1609
+ combined.set(pending.messageId, pendingAgentMessageFromInput(pending));
1610
+ }
1590
1611
  const values = Array.from(combined.values()).filter((pending) => !allMessages.some((message) => datasetThreadMessageMatchesPendingAgentMessage(message, pending)));
1591
1612
  return [
1592
1613
  ...values.filter((message) => !message.awaitingAcceptance),
1593
1614
  ...values.filter((message) => message.awaitingAcceptance)
1594
1615
  ];
1595
- }, [allMessages, status.pendingMessages]);
1596
- const canInterruptActiveTurn = status.supportsAgentMessages && status.turnId != null;
1616
+ }, [allMessages, status.pendingMessages, threadSessionVersion]);
1617
+ const canInterruptActiveTurn = status.turnId != null && (status.supportsAgentMessages || agentParticipant != null || chatClient != null);
1597
1618
  const cancelTurn = useCallback(async () => {
1598
- if (!status.turnId?.trim() || !agentParticipant) {
1619
+ const turnId = status.turnId?.trim();
1620
+ const session = threadSessionRef.current;
1621
+ if (!turnId || session == null) {
1599
1622
  return;
1600
1623
  }
1601
- await room.messaging.sendMessage({
1602
- to: agentParticipant,
1603
- type: agentRoomMessageType,
1604
- message: {
1605
- payload: {
1606
- type: agentTurnInterruptType,
1607
- thread_id: path,
1608
- turn_id: status.turnId
1609
- }
1610
- }
1611
- });
1612
- }, [agentParticipant, path, room, status.turnId]);
1624
+ await session.interruptTurn(turnId);
1625
+ }, [status.turnId, threadSessionVersion]);
1613
1626
  const selectAttachments = useCallback((files) => {
1614
1627
  const nextAttachments = files.map((file) => new MeshagentFileUpload(
1615
1628
  room,
@@ -1623,56 +1636,39 @@ function DatasetChatThread({
1623
1636
  if (message.text.trim() === "" && message.attachments.length === 0) {
1624
1637
  return;
1625
1638
  }
1626
- if (!agentParticipant) {
1639
+ if (!agentParticipant && chatClient == null) {
1627
1640
  setSendError("This thread requires an online agent that supports agent messages.");
1628
1641
  return;
1629
1642
  }
1643
+ const session = threadSessionRef.current;
1644
+ if (session == null) {
1645
+ setSendError("No thread session is open.");
1646
+ return;
1647
+ }
1630
1648
  const isSteer = status.mode === "steerable" && status.turnId != null;
1631
1649
  const normalizedAttachments = message.attachments.map(normalizeAgentAttachmentUrl).filter((attachment) => attachment !== null);
1632
1650
  const senderName = localParticipantName.trim() || void 0;
1633
- upsertAgentRow({
1634
- model: modelRef.current,
1635
- itemId: message.id,
1636
- turnId: null,
1637
- timestamp: /* @__PURE__ */ new Date(),
1638
- data: {
1639
- kind: "message",
1640
- role: "user",
1641
- text: message.text,
1642
- sender_name: senderName,
1643
- attachments: normalizedAttachments
1644
- }
1645
- });
1646
- bumpModelVersion();
1647
1651
  try {
1648
- const payload = {
1649
- type: isSteer ? agentTurnSteerType : agentTurnStartType,
1650
- thread_id: path,
1651
- message_id: message.id,
1652
- content: agentInputContent(message.text, message.attachments)
1653
- };
1654
- if (isSteer && status.turnId) {
1655
- payload.turn_id = status.turnId;
1656
- }
1657
- await room.messaging.sendMessage({
1658
- to: agentParticipant,
1659
- type: agentRoomMessageType,
1660
- message: { payload }
1652
+ await session.sendText({
1653
+ messageId: message.id,
1654
+ text: message.text,
1655
+ attachments: normalizedAttachments,
1656
+ steer: isSteer,
1657
+ turnId: status.turnId,
1658
+ senderName
1661
1659
  });
1662
1660
  setSendError(null);
1661
+ setThreadSessionVersion((current) => current + 1);
1663
1662
  } catch (error) {
1664
- modelRef.current.agentRowsByItemId.delete(message.id);
1665
- bumpModelVersion();
1666
1663
  setSendError(describeError(error));
1667
1664
  }
1668
1665
  }, [
1669
1666
  agentParticipant,
1670
- bumpModelVersion,
1667
+ chatClient,
1671
1668
  localParticipantName,
1672
- path,
1673
- room,
1674
1669
  status.mode,
1675
- status.turnId
1670
+ status.turnId,
1671
+ threadSessionVersion
1676
1672
  ]);
1677
1673
  const hasWireBackedContent = modelRef.current.agentRowsByItemId.size > 0 || status.pendingMessages.length > 0 || pendingMessages.length > 0;
1678
1674
  const model = modelRef.current;
@@ -1804,8 +1800,8 @@ function DatasetChatThread({
1804
1800
  attachments,
1805
1801
  onFilesSelected: selectAttachments,
1806
1802
  setAttachments,
1807
- disabled: agentParticipant == null,
1808
- placeholder: inputPlaceholder ?? (agentParticipant ? "Type a message" : `Waiting for ${displayParticipantName(agentName ?? "agent")}`)
1803
+ disabled: agentParticipant == null && chatClient == null,
1804
+ placeholder: inputPlaceholder ?? (agentParticipant || chatClient ? "Type a message" : `Waiting for ${displayParticipantName(agentName ?? "agent")}`)
1809
1805
  }
1810
1806
  )
1811
1807
  ] });
@@ -1,8 +1,11 @@
1
1
  import type { ReactElement } from "react";
2
2
  import { RoomClient } from "@meshagent/meshagent";
3
+ import type { BaseChatClient } from "@meshagent/meshagent-agents";
3
4
  export type MultiThreadContentBuilder = (threadPath: string) => ReactElement;
4
5
  export interface MultiThreadViewProps {
5
6
  room: RoomClient;
7
+ chatClient?: BaseChatClient;
8
+ disposeChatClient?: boolean;
6
9
  agentName: string;
7
10
  builder: MultiThreadContentBuilder;
8
11
  toolkit?: string;
@@ -15,4 +18,4 @@ export interface MultiThreadViewProps {
15
18
  emptyStateTitle?: string;
16
19
  emptyStateDescription?: string;
17
20
  }
18
- export declare function MultiThreadView({ room, agentName, builder, toolkit, tool, selectedThreadPath, onSelectedThreadPathChanged, onSelectedThreadResolved, newThreadResetVersion, centerComposer, emptyStateTitle, emptyStateDescription, }: MultiThreadViewProps): ReactElement;
21
+ export declare function MultiThreadView({ room, chatClient, disposeChatClient, agentName, builder, toolkit, tool, selectedThreadPath, onSelectedThreadPathChanged, onSelectedThreadResolved, newThreadResetVersion, centerComposer, emptyStateTitle, emptyStateDescription, }: MultiThreadViewProps): ReactElement;
@@ -7,6 +7,8 @@ function normalizeSelectedThreadPath(path) {
7
7
  }
8
8
  function MultiThreadView({
9
9
  room,
10
+ chatClient,
11
+ disposeChatClient = false,
10
12
  agentName,
11
13
  builder,
12
14
  toolkit = "chat",
@@ -45,6 +47,8 @@ function MultiThreadView({
45
47
  NewChatThread,
46
48
  {
47
49
  room,
50
+ chatClient,
51
+ disposeChatClient,
48
52
  agentName,
49
53
  builder,
50
54
  toolkit,
@@ -1,8 +1,11 @@
1
1
  import type { ReactElement } from "react";
2
2
  import { RoomClient } from "@meshagent/meshagent";
3
+ import type { BaseChatClient } from "@meshagent/meshagent-agents";
3
4
  export type NewChatThreadBuilder = (threadPath: string) => ReactElement;
4
5
  export interface NewChatThreadProps {
5
6
  room: RoomClient;
7
+ chatClient?: BaseChatClient;
8
+ disposeChatClient?: boolean;
6
9
  agentName: string;
7
10
  builder: NewChatThreadBuilder;
8
11
  toolkit?: string;
@@ -14,4 +17,4 @@ export interface NewChatThreadProps {
14
17
  emptyStateTitle?: string;
15
18
  emptyStateDescription?: string;
16
19
  }
17
- export declare function NewChatThread({ room, agentName, builder, toolkit, tool, selectedThreadPath, onThreadPathChanged, onThreadResolved, centerComposer, emptyStateTitle, emptyStateDescription, }: NewChatThreadProps): ReactElement;
20
+ export declare function NewChatThread({ room, chatClient, disposeChatClient, agentName, builder, selectedThreadPath, onThreadPathChanged, onThreadResolved, centerComposer, emptyStateTitle, emptyStateDescription, }: NewChatThreadProps): ReactElement;