@meshagent/meshagent-tailwind 0.39.8 → 0.40.0

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 (111) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cjs/{ChatBotView.js → chat/chat-bot-view.js} +37 -22
  3. package/dist/cjs/{chat-hooks.d.ts → chat/chat-hooks.d.ts} +5 -1
  4. package/dist/cjs/{chat-hooks.js → chat/chat-hooks.js} +12 -2
  5. package/dist/cjs/{ChatInput.js → chat/chat-input.js} +9 -9
  6. package/dist/cjs/chat/chat-thread.d.ts +12 -0
  7. package/dist/cjs/{ChatThread.js → chat/chat-thread.js} +75 -28
  8. package/dist/cjs/{ChatTypingIndicator.js → chat/chat-typing-indicator.js} +4 -4
  9. package/dist/{esm → cjs/chat}/conversation-descriptor.d.ts +7 -1
  10. package/dist/cjs/{conversation-descriptor.js → chat/conversation-descriptor.js} +41 -7
  11. package/dist/cjs/chat/dataset-chat-thread.d.ts +13 -0
  12. package/dist/cjs/chat/dataset-chat-thread.js +1840 -0
  13. package/dist/cjs/{FileUploader.js → chat/file-uploader.js} +4 -4
  14. package/dist/cjs/{multi-thread-view.js → chat/multi-thread-view.js} +8 -3
  15. package/dist/cjs/chat/new-chat-thread.d.ts +17 -0
  16. package/dist/cjs/{Chat.js → chat/new-chat-thread.js} +43 -168
  17. package/dist/cjs/{UploadPill.js → chat/upload-pill.js} +5 -5
  18. package/dist/cjs/file-preview/file-preview.d.ts +34 -0
  19. package/dist/cjs/file-preview/file-preview.js +329 -0
  20. package/dist/cjs/forms/email-address.d.ts +10 -0
  21. package/dist/cjs/forms/email-address.js +105 -0
  22. package/dist/cjs/forms/form.d.ts +27 -0
  23. package/dist/cjs/forms/form.js +200 -0
  24. package/dist/cjs/forms/multi-select-autocomplete.d.ts +35 -0
  25. package/dist/cjs/forms/multi-select-autocomplete.js +294 -0
  26. package/dist/cjs/forms/select-users-dialog.d.ts +20 -0
  27. package/dist/cjs/forms/select-users-dialog.js +145 -0
  28. package/dist/cjs/forms/select-users.d.ts +16 -0
  29. package/dist/cjs/forms/select-users.js +117 -0
  30. package/dist/cjs/index.d.ts +19 -11
  31. package/dist/cjs/index.js +19 -11
  32. package/dist/cjs/meetings/audio-visualization.d.ts +7 -0
  33. package/dist/cjs/meetings/audio-visualization.js +74 -0
  34. package/dist/cjs/meetings/controls.d.ts +19 -0
  35. package/dist/cjs/meetings/controls.js +300 -0
  36. package/dist/cjs/meetings/meeting-scope.d.ts +83 -0
  37. package/dist/cjs/meetings/meeting-scope.js +309 -0
  38. package/dist/cjs/meetings/meetings.d.ts +5 -0
  39. package/dist/cjs/meetings/meetings.js +22 -0
  40. package/dist/cjs/meetings/participants.d.ts +13 -0
  41. package/dist/cjs/meetings/participants.js +154 -0
  42. package/dist/cjs/meetings/wake-lock.d.ts +4 -0
  43. package/dist/cjs/meetings/wake-lock.js +55 -0
  44. package/dist/esm/{ChatBotView.js → chat/chat-bot-view.js} +34 -19
  45. package/dist/esm/{chat-hooks.d.ts → chat/chat-hooks.d.ts} +5 -1
  46. package/dist/esm/{chat-hooks.js → chat/chat-hooks.js} +12 -2
  47. package/dist/esm/{ChatInput.js → chat/chat-input.js} +4 -4
  48. package/dist/esm/chat/chat-thread.d.ts +12 -0
  49. package/dist/esm/{ChatThread.js → chat/chat-thread.js} +70 -23
  50. package/dist/esm/{ChatTypingIndicator.js → chat/chat-typing-indicator.js} +1 -1
  51. package/dist/{cjs → esm/chat}/conversation-descriptor.d.ts +7 -1
  52. package/dist/esm/{conversation-descriptor.js → chat/conversation-descriptor.js} +41 -7
  53. package/dist/esm/chat/dataset-chat-thread.d.ts +13 -0
  54. package/dist/esm/chat/dataset-chat-thread.js +1815 -0
  55. package/dist/esm/{FileUploader.js → chat/file-uploader.js} +1 -1
  56. package/dist/esm/{multi-thread-view.js → chat/multi-thread-view.js} +8 -3
  57. package/dist/esm/chat/new-chat-thread.d.ts +17 -0
  58. package/dist/esm/{Chat.js → chat/new-chat-thread.js} +40 -165
  59. package/dist/esm/{UploadPill.js → chat/upload-pill.js} +2 -2
  60. package/dist/esm/file-preview/file-preview.d.ts +34 -0
  61. package/dist/esm/file-preview/file-preview.js +316 -0
  62. package/dist/esm/forms/email-address.d.ts +10 -0
  63. package/dist/esm/forms/email-address.js +85 -0
  64. package/dist/esm/forms/form.d.ts +27 -0
  65. package/dist/esm/forms/form.js +193 -0
  66. package/dist/esm/forms/multi-select-autocomplete.d.ts +35 -0
  67. package/dist/esm/forms/multi-select-autocomplete.js +274 -0
  68. package/dist/esm/forms/select-users-dialog.d.ts +20 -0
  69. package/dist/esm/forms/select-users-dialog.js +132 -0
  70. package/dist/esm/forms/select-users.d.ts +16 -0
  71. package/dist/esm/forms/select-users.js +97 -0
  72. package/dist/esm/index.d.ts +19 -11
  73. package/dist/esm/index.js +19 -11
  74. package/dist/esm/meetings/audio-visualization.d.ts +7 -0
  75. package/dist/esm/meetings/audio-visualization.js +54 -0
  76. package/dist/esm/meetings/controls.d.ts +19 -0
  77. package/dist/esm/meetings/controls.js +294 -0
  78. package/dist/esm/meetings/meeting-scope.d.ts +83 -0
  79. package/dist/esm/meetings/meeting-scope.js +294 -0
  80. package/dist/esm/meetings/meetings.d.ts +5 -0
  81. package/dist/esm/meetings/meetings.js +5 -0
  82. package/dist/esm/meetings/participants.d.ts +13 -0
  83. package/dist/esm/meetings/participants.js +137 -0
  84. package/dist/esm/meetings/wake-lock.d.ts +4 -0
  85. package/dist/esm/meetings/wake-lock.js +35 -0
  86. package/dist/index.css +2 -2
  87. package/package.json +7 -4
  88. package/dist/cjs/Chat.d.ts +0 -15
  89. package/dist/cjs/ChatThread.d.ts +0 -21
  90. package/dist/esm/Chat.d.ts +0 -15
  91. package/dist/esm/ChatThread.d.ts +0 -21
  92. /package/dist/cjs/{ChatBotView.d.ts → chat/chat-bot-view.d.ts} +0 -0
  93. /package/dist/cjs/{ChatInput.d.ts → chat/chat-input.d.ts} +0 -0
  94. /package/dist/cjs/{chat-message.d.ts → chat/chat-message.d.ts} +0 -0
  95. /package/dist/cjs/{chat-message.js → chat/chat-message.js} +0 -0
  96. /package/dist/cjs/{ChatTypingIndicator.d.ts → chat/chat-typing-indicator.d.ts} +0 -0
  97. /package/dist/cjs/{file-attachment.d.ts → chat/file-attachment.d.ts} +0 -0
  98. /package/dist/cjs/{file-attachment.js → chat/file-attachment.js} +0 -0
  99. /package/dist/cjs/{FileUploader.d.ts → chat/file-uploader.d.ts} +0 -0
  100. /package/dist/cjs/{multi-thread-view.d.ts → chat/multi-thread-view.d.ts} +0 -0
  101. /package/dist/cjs/{UploadPill.d.ts → chat/upload-pill.d.ts} +0 -0
  102. /package/dist/esm/{ChatBotView.d.ts → chat/chat-bot-view.d.ts} +0 -0
  103. /package/dist/esm/{ChatInput.d.ts → chat/chat-input.d.ts} +0 -0
  104. /package/dist/esm/{chat-message.d.ts → chat/chat-message.d.ts} +0 -0
  105. /package/dist/esm/{chat-message.js → chat/chat-message.js} +0 -0
  106. /package/dist/esm/{ChatTypingIndicator.d.ts → chat/chat-typing-indicator.d.ts} +0 -0
  107. /package/dist/esm/{file-attachment.d.ts → chat/file-attachment.d.ts} +0 -0
  108. /package/dist/esm/{file-attachment.js → chat/file-attachment.js} +0 -0
  109. /package/dist/esm/{FileUploader.d.ts → chat/file-uploader.d.ts} +0 -0
  110. /package/dist/esm/{multi-thread-view.d.ts → chat/multi-thread-view.d.ts} +0 -0
  111. /package/dist/esm/{UploadPill.d.ts → chat/upload-pill.d.ts} +0 -0
@@ -32,15 +32,19 @@ export declare class PendingAgentMessage {
32
32
  readonly text: string;
33
33
  readonly attachments: string[];
34
34
  readonly senderName?: string;
35
+ readonly createdAt?: Date;
36
+ readonly matchByContentOnly: boolean;
35
37
  readonly awaitingAcceptance: boolean;
36
38
  readonly awaitingOnline: boolean;
37
- constructor({ messageId, messageType, threadPath, text, attachments, senderName, awaitingAcceptance, awaitingOnline, }: {
39
+ constructor({ messageId, messageType, threadPath, text, attachments, senderName, createdAt, matchByContentOnly, awaitingAcceptance, awaitingOnline, }: {
38
40
  messageId: string;
39
41
  messageType: string;
40
42
  threadPath: string;
41
43
  text: string;
42
44
  attachments: string[];
43
45
  senderName?: string;
46
+ createdAt?: Date;
47
+ matchByContentOnly?: boolean;
44
48
  awaitingAcceptance?: boolean;
45
49
  awaitingOnline?: boolean;
46
50
  });
@@ -20,6 +20,8 @@ class PendingAgentMessage {
20
20
  text;
21
21
  attachments;
22
22
  senderName;
23
+ createdAt;
24
+ matchByContentOnly;
23
25
  awaitingAcceptance;
24
26
  awaitingOnline;
25
27
  constructor({
@@ -29,6 +31,8 @@ class PendingAgentMessage {
29
31
  text,
30
32
  attachments,
31
33
  senderName,
34
+ createdAt,
35
+ matchByContentOnly = false,
32
36
  awaitingAcceptance = false,
33
37
  awaitingOnline = false
34
38
  }) {
@@ -38,6 +42,8 @@ class PendingAgentMessage {
38
42
  this.text = text;
39
43
  this.attachments = attachments;
40
44
  this.senderName = senderName;
45
+ this.createdAt = createdAt;
46
+ this.matchByContentOnly = matchByContentOnly;
41
47
  this.awaitingAcceptance = awaitingAcceptance;
42
48
  this.awaitingOnline = awaitingOnline;
43
49
  }
@@ -69,6 +75,8 @@ class PendingAgentMessage {
69
75
  const messageType = json["message_type"];
70
76
  const messageId = json["message_id"];
71
77
  const threadPath = json["thread_id"];
78
+ const createdAt = json["created_at"];
79
+ const parsedCreatedAt = typeof createdAt === "string" ? new Date(createdAt) : void 0;
72
80
  return new PendingAgentMessage({
73
81
  messageId: typeof messageId === "string" ? messageId : crypto.randomUUID(),
74
82
  messageType: typeof messageType === "string" ? messageType : agentTurnSteerType,
@@ -76,6 +84,8 @@ class PendingAgentMessage {
76
84
  text: textParts.join("\n\n"),
77
85
  attachments,
78
86
  senderName: typeof senderName === "string" && senderName.trim().length > 0 ? senderName.trim() : void 0,
87
+ createdAt: parsedCreatedAt instanceof Date && !Number.isNaN(parsedCreatedAt.getTime()) ? parsedCreatedAt : void 0,
88
+ matchByContentOnly: false,
79
89
  awaitingOnline: false
80
90
  });
81
91
  }
@@ -286,7 +296,7 @@ async function sendMessageToParticipant({
286
296
  await room.messaging.sendMessage({
287
297
  to: participant,
288
298
  type: agentRoomMessageType,
289
- message: { payload }
299
+ message: payload
290
300
  });
291
301
  return;
292
302
  }
@@ -510,7 +520,7 @@ function resolveThreadStatus({
510
520
  function pendingMessagesEqual(left, right) {
511
521
  return left.length === right.length && left.every((message, index) => {
512
522
  const other = right[index];
513
- return message.messageId === other.messageId && message.messageType === other.messageType && message.text === other.text && stringArraysEqual(message.attachments, other.attachments) && message.senderName === other.senderName;
523
+ return message.messageId === other.messageId && message.messageType === other.messageType && message.text === other.text && stringArraysEqual(message.attachments, other.attachments) && message.senderName === other.senderName && message.createdAt?.getTime() === other.createdAt?.getTime() && message.matchByContentOnly === other.matchByContentOnly && message.awaitingAcceptance === other.awaitingAcceptance && message.awaitingOnline === other.awaitingOnline;
514
524
  });
515
525
  }
516
526
  function threadStatusEquals(left, right) {
@@ -3,11 +3,11 @@ import { useRef, useState, useEffect, useMemo, useCallback } from "react";
3
3
  import { ArrowUp, LoaderCircle, X } from "lucide-react";
4
4
  import { v4 as uuidV4 } from "uuid";
5
5
  import { ChatMessage } from "./chat-message";
6
- import { Button } from "./components/ui/button";
7
- import { FileUploader } from "./FileUploader";
8
- import { UploadPill } from "./UploadPill";
6
+ import { Button } from "../components/ui/button";
7
+ import { FileUploader } from "./file-uploader";
8
+ import { UploadPill } from "./upload-pill";
9
9
  import { UploadStatus } from "./file-attachment";
10
- import { cn } from "./lib/utils";
10
+ import { cn } from "../lib/utils";
11
11
  const MIN_TEXTAREA_HEIGHT = 20;
12
12
  const MAX_TEXTAREA_HEIGHT = 160;
13
13
  function useAttachmentStatusVersion(attachments) {
@@ -0,0 +1,12 @@
1
+ import type { ReactElement } from "react";
2
+ import { Participant, RoomClient } from "@meshagent/meshagent";
3
+ export interface ChatThreadProps {
4
+ room: RoomClient;
5
+ path: string;
6
+ participants?: Participant[];
7
+ agentName?: string;
8
+ emptyStateTitle?: string;
9
+ emptyStateDescription?: string;
10
+ }
11
+ export declare function timeAgo(iso: string): string;
12
+ export declare function ChatThread({ room, path, participants, agentName, emptyStateTitle, emptyStateDescription, }: ChatThreadProps): ReactElement;
@@ -1,14 +1,17 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useMemo, useState, useEffect, useRef, useCallback } from "react";
3
- import { Download, FileText } from "lucide-react";
3
+ import { FileText } from "lucide-react";
4
4
  import ReactMarkdown from "react-markdown";
5
5
  import rehypeHighlight from "rehype-highlight";
6
6
  import rehypeSanitize from "rehype-sanitize";
7
7
  import remarkGfm from "remark-gfm";
8
- import { Button } from "./components/ui/button";
9
- import { Spinner } from "./components/ui/spinner";
10
- import { ChatTypingIndicator } from "./ChatTypingIndicator";
11
- import { cn } from "./lib/utils";
8
+ import { Button } from "../components/ui/button";
9
+ import { Spinner } from "../components/ui/spinner";
10
+ import { ChatTypingIndicator } from "./chat-typing-indicator";
11
+ import { ChatInput } from "./chat-input";
12
+ import { useChatThread, useThreadStatus } from "./chat-hooks";
13
+ import { FilePreviewDialog, isImagePath } from "../file-preview/file-preview";
14
+ import { cn } from "../lib/utils";
12
15
  const supportedEventKinds = /* @__PURE__ */ new Set([
13
16
  "exec",
14
17
  "tool",
@@ -74,9 +77,6 @@ function timeAgo(iso) {
74
77
  function displayParticipantName(name) {
75
78
  return name.split("@")[0]?.trim() ?? name.trim();
76
79
  }
77
- function isImagePath(path) {
78
- return /\.(avif|bmp|gif|jpe?g|png|svg|webp)$/i.test(path);
79
- }
80
80
  function isThreadAttachmentElement(element) {
81
81
  return element.tagName === "file" || element.tagName === "image";
82
82
  }
@@ -301,14 +301,11 @@ function ChatImage({
301
301
  if (!url) {
302
302
  return null;
303
303
  }
304
- return /* @__PURE__ */ jsx(
304
+ return /* @__PURE__ */ jsx(FilePreviewDialog, { room, path, children: /* @__PURE__ */ jsx(
305
305
  "button",
306
306
  {
307
307
  type: "button",
308
308
  className: "block overflow-hidden rounded-md bg-muted/20 shadow-xs transition-opacity hover:opacity-95",
309
- onClick: () => {
310
- window.open(url, "_blank", "noopener,noreferrer");
311
- },
312
309
  children: /* @__PURE__ */ jsx(
313
310
  "img",
314
311
  {
@@ -325,28 +322,21 @@ function ChatImage({
325
322
  }
326
323
  )
327
324
  }
328
- );
325
+ ) });
329
326
  }
330
327
  function FileAttachment({ room, path }) {
331
- const url = useDownloadUrl(room, path);
332
328
  const filename = path.split("/").pop() ?? path;
333
- return /* @__PURE__ */ jsxs(
329
+ return /* @__PURE__ */ jsx(FilePreviewDialog, { room, path, children: /* @__PURE__ */ jsxs(
334
330
  "button",
335
331
  {
336
332
  type: "button",
337
333
  className: "inline-flex max-w-full items-center gap-2 rounded-md bg-muted/60 px-3 py-2 text-left shadow-xs transition-colors hover:bg-muted/80",
338
- onClick: () => {
339
- if (url) {
340
- window.open(url, "_blank", "noopener,noreferrer");
341
- }
342
- },
343
334
  children: [
344
335
  /* @__PURE__ */ jsx(FileText, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
345
- /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium", children: filename }),
346
- /* @__PURE__ */ jsx(Download, { className: "h-4 w-4 shrink-0 text-muted-foreground" })
336
+ /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium", children: filename })
347
337
  ]
348
338
  }
349
- );
339
+ ) });
350
340
  }
351
341
  function ThreadAttachment({ room, attachment, onImageSettled }) {
352
342
  const path = getTrimmedStringAttribute(attachment, "path");
@@ -551,6 +541,63 @@ function EmptyState({
551
541
  ] });
552
542
  }
553
543
  function ChatThread({
544
+ room,
545
+ path,
546
+ participants,
547
+ agentName,
548
+ emptyStateTitle,
549
+ emptyStateDescription
550
+ }) {
551
+ const status = useThreadStatus({ room, path, agentName });
552
+ const {
553
+ document,
554
+ messages,
555
+ sendMessage,
556
+ selectAttachments,
557
+ attachments,
558
+ setAttachments,
559
+ localParticipantName,
560
+ cancelRequest
561
+ } = useChatThread({
562
+ room,
563
+ path,
564
+ participants,
565
+ agentName,
566
+ useAgentMessages: agentName?.trim() !== "",
567
+ messageType: status.mode === "steerable" && status.turnId != null ? "steer" : "chat",
568
+ turnId: status.turnId
569
+ });
570
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [
571
+ /* @__PURE__ */ jsx(
572
+ ChatThreadView,
573
+ {
574
+ room,
575
+ messages,
576
+ isLoading: document === null,
577
+ localParticipantName,
578
+ path,
579
+ threadStatusText: status.text,
580
+ threadStatusStartedAt: status.startedAt,
581
+ threadStatusMode: status.mode,
582
+ onCancelRequest: cancelRequest,
583
+ emptyStateTitle,
584
+ emptyStateDescription
585
+ }
586
+ ),
587
+ /* @__PURE__ */ jsx(
588
+ ChatInput,
589
+ {
590
+ onSubmit: sendMessage,
591
+ attachments,
592
+ onFilesSelected: selectAttachments,
593
+ setAttachments,
594
+ disabled: document === null,
595
+ placeholder: agentName?.trim() ? `Type a message or @${displayParticipantName(agentName)}` : "Type a message"
596
+ }
597
+ )
598
+ ] });
599
+ }
600
+ function ChatThreadView({
554
601
  room,
555
602
  messages,
556
603
  isLoading = false,
@@ -3,7 +3,7 @@ import * as React from "react";
3
3
  import { useRoomIndicators } from "@meshagent/meshagent-react";
4
4
  import { LoaderCircle, X } from "lucide-react";
5
5
  import { formatThreadStatusText } from "./chat-hooks";
6
- import { cn } from "./lib/utils";
6
+ import { cn } from "../lib/utils";
7
7
  function useStatusLabel(text, startedAt) {
8
8
  const normalizedText = text?.trim() ?? "";
9
9
  const [tick, setTick] = React.useState(0);
@@ -11,10 +11,11 @@ export declare enum ChatThreadDisplayMode {
11
11
  }
12
12
  export declare class ChatAgentConversationDescriptor {
13
13
  private constructor();
14
- static chat({ chatThreadDisplayMode, threadDir, threadListPath, }?: {
14
+ static chat({ chatThreadDisplayMode, threadDir, threadListPath, threadPath, }?: {
15
15
  chatThreadDisplayMode?: ChatThreadDisplayMode;
16
16
  threadDir?: string | null;
17
17
  threadListPath?: string | null;
18
+ threadPath?: string | null;
18
19
  }): ChatAgentConversationDescriptor;
19
20
  static voiceOnly(): ChatAgentConversationDescriptor;
20
21
  static meeting(): ChatAgentConversationDescriptor;
@@ -22,6 +23,7 @@ export declare class ChatAgentConversationDescriptor {
22
23
  readonly chatThreadDisplayMode: ChatThreadDisplayMode;
23
24
  readonly threadDir: string | null;
24
25
  readonly threadListPath: string | null;
26
+ readonly threadPath: string | null;
25
27
  get isChat(): boolean;
26
28
  get isVoiceOnly(): boolean;
27
29
  get isMeeting(): boolean;
@@ -36,11 +38,15 @@ export declare function chatThreadDisplayModeFromAnnotation(value: unknown): Cha
36
38
  export declare function normalizedThreadDir(threadDir?: string | null): string | null;
37
39
  export declare function participantThreadDir(participant: RemoteParticipant): string | null;
38
40
  export declare function participantThreadListPath(participant: RemoteParticipant): string | null;
41
+ export declare function participantThreadPath(participant: RemoteParticipant): string | null;
39
42
  export declare function participantConversationDescriptor(participant: RemoteParticipant): ChatAgentConversationDescriptor | null;
40
43
  export declare function serviceThreadDir(service: ServiceSpec): string | null;
41
44
  export declare function serviceThreadListPath(service: ServiceSpec, { remoteParticipants }?: {
42
45
  remoteParticipants?: Iterable<RemoteParticipant>;
43
46
  }): string | null;
47
+ export declare function serviceThreadPath(service: ServiceSpec, { remoteParticipants }?: {
48
+ remoteParticipants?: Iterable<RemoteParticipant>;
49
+ }): string | null;
44
50
  export declare function serviceConversationDescriptor(service: ServiceSpec, { remoteParticipants }?: {
45
51
  remoteParticipants?: Iterable<RemoteParticipant>;
46
52
  }): ChatAgentConversationDescriptor | null;
@@ -17,23 +17,27 @@ class ChatAgentConversationDescriptor {
17
17
  kind,
18
18
  chatThreadDisplayMode = 0 /* SingleThread */,
19
19
  threadDir = null,
20
- threadListPath = null
20
+ threadListPath = null,
21
+ threadPath = null
21
22
  }) {
22
23
  this.kind = kind;
23
24
  this.chatThreadDisplayMode = chatThreadDisplayMode;
24
25
  this.threadDir = threadDir;
25
26
  this.threadListPath = threadListPath;
27
+ this.threadPath = threadPath;
26
28
  }
27
29
  static chat({
28
30
  chatThreadDisplayMode = 0 /* SingleThread */,
29
31
  threadDir = null,
30
- threadListPath = null
32
+ threadListPath = null,
33
+ threadPath = null
31
34
  } = {}) {
32
35
  return new ChatAgentConversationDescriptor({
33
36
  kind: 0 /* Chat */,
34
37
  chatThreadDisplayMode,
35
38
  threadDir,
36
- threadListPath
39
+ threadListPath,
40
+ threadPath
37
41
  });
38
42
  }
39
43
  static voiceOnly() {
@@ -50,6 +54,7 @@ class ChatAgentConversationDescriptor {
50
54
  chatThreadDisplayMode;
51
55
  threadDir;
52
56
  threadListPath;
57
+ threadPath;
53
58
  get isChat() {
54
59
  return this.kind === 0 /* Chat */;
55
60
  }
@@ -121,12 +126,16 @@ function participantThreadListPath(participant) {
121
126
  const threadListPath = normalizedAnnotationString(participant.getAttribute("meshagent.chatbot.thread-list"));
122
127
  return threadListPath ?? threadListPathFromThreadDir(participantThreadDir(participant));
123
128
  }
129
+ function participantThreadPath(participant) {
130
+ return normalizedAnnotationString(participant.getAttribute("meshagent.chatbot.thread-path"));
131
+ }
124
132
  function participantConversationDescriptor(participant) {
125
133
  const supportsVoice = participantSupportsVoice(participant);
126
134
  const supportsChat = participantSupportsChatOverride(participant);
127
135
  const threadDir = participantThreadDir(participant);
128
136
  const threadListPath = participantThreadListPath(participant);
129
- const hasThreadAnnotations = normalizedAnnotationString(participant.getAttribute("meshagent.chatbot.threading")) !== null || threadDir !== null || threadListPath !== null;
137
+ const threadPath = participantThreadPath(participant);
138
+ const hasThreadAnnotations = normalizedAnnotationString(participant.getAttribute("meshagent.chatbot.threading")) !== null || threadDir !== null || threadListPath !== null || threadPath !== null;
130
139
  if (supportsChat === false) {
131
140
  return supportsVoice ? ChatAgentConversationDescriptor.voiceOnly() : null;
132
141
  }
@@ -139,7 +148,8 @@ function participantConversationDescriptor(participant) {
139
148
  participant.getAttribute("meshagent.chatbot.threading")
140
149
  ),
141
150
  threadDir,
142
- threadListPath
151
+ threadListPath,
152
+ threadPath
143
153
  });
144
154
  }
145
155
  if (supportsVoice) {
@@ -173,6 +183,24 @@ function serviceThreadListPath(service, { remoteParticipants = [] } = {}) {
173
183
  }
174
184
  return null;
175
185
  }
186
+ function serviceThreadPath(service, { remoteParticipants = [] } = {}) {
187
+ const annotationPath = normalizedAnnotationString(
188
+ firstAgent(service)?.annotations?.["meshagent.chatbot.thread-path"]
189
+ );
190
+ if (annotationPath !== null) {
191
+ return annotationPath;
192
+ }
193
+ const agentName = firstAgent(service)?.name;
194
+ if (!agentName || agentName.trim() === "") {
195
+ return null;
196
+ }
197
+ for (const participant of remoteParticipants) {
198
+ if (participant.getAttribute("name") === agentName) {
199
+ return participantThreadPath(participant);
200
+ }
201
+ }
202
+ return null;
203
+ }
176
204
  function serviceConversationDescriptor(service, { remoteParticipants = [] } = {}) {
177
205
  const type = firstAgent(service)?.annotations?.["meshagent.agent.type"];
178
206
  if (type === "VoiceBot") {
@@ -189,7 +217,8 @@ function serviceConversationDescriptor(service, { remoteParticipants = [] } = {}
189
217
  firstAgent(service)?.annotations?.["meshagent.chatbot.threading"]
190
218
  ),
191
219
  threadDir: serviceThreadDir(service),
192
- threadListPath: serviceThreadListPath(service, { remoteParticipants })
220
+ threadListPath: serviceThreadListPath(service, { remoteParticipants }),
221
+ threadPath: serviceThreadPath(service, { remoteParticipants })
193
222
  });
194
223
  }
195
224
  function conversationDescriptorForParticipant(participant, {
@@ -234,6 +263,9 @@ function chatDocumentPath(agentName, {
234
263
  } = {}) {
235
264
  const normalizedDir = normalizedThreadDir(threadDir);
236
265
  if (normalizedDir !== null) {
266
+ if (normalizedDir.startsWith("dataset://") || normalizedDir.startsWith("tmp://")) {
267
+ return `${normalizedDir}/main`;
268
+ }
237
269
  return `${normalizedDir}/main.thread`;
238
270
  }
239
271
  const defaultThreadDir = defaultThreadDocumentDir(agentName);
@@ -273,8 +305,10 @@ export {
273
305
  participantSupportsVoice,
274
306
  participantThreadDir,
275
307
  participantThreadListPath,
308
+ participantThreadPath,
276
309
  resolvedThreadListPath,
277
310
  serviceConversationDescriptor,
278
311
  serviceThreadDir,
279
- serviceThreadListPath
312
+ serviceThreadListPath,
313
+ serviceThreadPath
280
314
  };
@@ -0,0 +1,13 @@
1
+ import type { ReactElement } from "react";
2
+ import type { RoomClient } from "@meshagent/meshagent";
3
+ export interface DatasetChatThreadProps {
4
+ room: RoomClient;
5
+ path: string;
6
+ agentName?: string;
7
+ emptyStateTitle?: string;
8
+ emptyStateDescription?: string;
9
+ inputPlaceholder?: string;
10
+ initialShowCompletedToolCalls?: boolean;
11
+ openFile?: (path: string) => void | Promise<void>;
12
+ }
13
+ export declare function DatasetChatThread({ room, path, agentName, emptyStateTitle, emptyStateDescription, inputPlaceholder, initialShowCompletedToolCalls, openFile, }: DatasetChatThreadProps): ReactElement;