@meshagent/meshagent-tailwind 0.38.2 → 0.38.3

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 (61) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/cjs/Chat.d.ts +11 -3
  3. package/dist/cjs/Chat.js +376 -29
  4. package/dist/cjs/ChatBotView.d.ts +29 -0
  5. package/dist/cjs/ChatBotView.js +491 -0
  6. package/dist/cjs/ChatInput.d.ts +12 -3
  7. package/dist/cjs/ChatInput.js +143 -44
  8. package/dist/cjs/ChatThread.d.ts +17 -3
  9. package/dist/cjs/ChatThread.js +646 -90
  10. package/dist/cjs/ChatTypingIndicator.d.ts +12 -5
  11. package/dist/cjs/ChatTypingIndicator.js +104 -13
  12. package/dist/cjs/FileUploader.d.ts +3 -2
  13. package/dist/cjs/FileUploader.js +35 -11
  14. package/dist/cjs/UploadPill.d.ts +2 -2
  15. package/dist/cjs/UploadPill.js +70 -32
  16. package/dist/cjs/chat-hooks.d.ts +38 -0
  17. package/dist/cjs/chat-hooks.js +390 -0
  18. package/dist/cjs/chat-message.d.ts +11 -0
  19. package/dist/cjs/chat-message.js +33 -0
  20. package/dist/cjs/components/ui/button.d.ts +1 -1
  21. package/dist/cjs/conversation-descriptor.d.ts +59 -0
  22. package/dist/cjs/conversation-descriptor.js +300 -0
  23. package/dist/cjs/file-attachment.d.ts +45 -0
  24. package/dist/cjs/file-attachment.js +171 -0
  25. package/dist/cjs/index.d.ts +5 -0
  26. package/dist/cjs/index.js +5 -0
  27. package/dist/cjs/multi-thread-view.d.ts +18 -0
  28. package/dist/cjs/multi-thread-view.js +88 -0
  29. package/dist/cjs/tools/ui-toolkit.d.ts +1 -1
  30. package/dist/cjs/tools/ui-toolkit.js +2 -1
  31. package/dist/esm/Chat.d.ts +11 -3
  32. package/dist/esm/Chat.js +378 -31
  33. package/dist/esm/ChatBotView.d.ts +29 -0
  34. package/dist/esm/ChatBotView.js +486 -0
  35. package/dist/esm/ChatInput.d.ts +12 -3
  36. package/dist/esm/ChatInput.js +143 -34
  37. package/dist/esm/ChatThread.d.ts +17 -3
  38. package/dist/esm/ChatThread.js +648 -92
  39. package/dist/esm/ChatTypingIndicator.d.ts +12 -5
  40. package/dist/esm/ChatTypingIndicator.js +94 -13
  41. package/dist/esm/FileUploader.d.ts +3 -2
  42. package/dist/esm/FileUploader.js +26 -12
  43. package/dist/esm/UploadPill.d.ts +2 -2
  44. package/dist/esm/UploadPill.js +60 -32
  45. package/dist/esm/chat-hooks.d.ts +38 -0
  46. package/dist/esm/chat-hooks.js +372 -0
  47. package/dist/esm/chat-message.d.ts +11 -0
  48. package/dist/esm/chat-message.js +13 -0
  49. package/dist/esm/components/ui/button.d.ts +1 -1
  50. package/dist/esm/conversation-descriptor.d.ts +59 -0
  51. package/dist/esm/conversation-descriptor.js +280 -0
  52. package/dist/esm/file-attachment.d.ts +45 -0
  53. package/dist/esm/file-attachment.js +151 -0
  54. package/dist/esm/index.d.ts +5 -0
  55. package/dist/esm/index.js +5 -0
  56. package/dist/esm/multi-thread-view.d.ts +18 -0
  57. package/dist/esm/multi-thread-view.js +68 -0
  58. package/dist/esm/tools/ui-toolkit.d.ts +1 -1
  59. package/dist/esm/tools/ui-toolkit.js +2 -1
  60. package/dist/index.css +1 -1
  61. package/package.json +3 -3
@@ -0,0 +1,280 @@
1
+ import { RemoteParticipant as MeshagentRemoteParticipant } from "@meshagent/meshagent";
2
+ const defaultUntitledThreadName = "New Chat";
3
+ const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
4
+ var ChatAgentConversationKind = /* @__PURE__ */ ((ChatAgentConversationKind2) => {
5
+ ChatAgentConversationKind2[ChatAgentConversationKind2["Chat"] = 0] = "Chat";
6
+ ChatAgentConversationKind2[ChatAgentConversationKind2["VoiceOnly"] = 1] = "VoiceOnly";
7
+ ChatAgentConversationKind2[ChatAgentConversationKind2["Meeting"] = 2] = "Meeting";
8
+ return ChatAgentConversationKind2;
9
+ })(ChatAgentConversationKind || {});
10
+ var ChatThreadDisplayMode = /* @__PURE__ */ ((ChatThreadDisplayMode2) => {
11
+ ChatThreadDisplayMode2[ChatThreadDisplayMode2["SingleThread"] = 0] = "SingleThread";
12
+ ChatThreadDisplayMode2[ChatThreadDisplayMode2["MultiThreadComposer"] = 1] = "MultiThreadComposer";
13
+ return ChatThreadDisplayMode2;
14
+ })(ChatThreadDisplayMode || {});
15
+ class ChatAgentConversationDescriptor {
16
+ constructor({
17
+ kind,
18
+ chatThreadDisplayMode = 0 /* SingleThread */,
19
+ threadDir = null,
20
+ threadListPath = null
21
+ }) {
22
+ this.kind = kind;
23
+ this.chatThreadDisplayMode = chatThreadDisplayMode;
24
+ this.threadDir = threadDir;
25
+ this.threadListPath = threadListPath;
26
+ }
27
+ static chat({
28
+ chatThreadDisplayMode = 0 /* SingleThread */,
29
+ threadDir = null,
30
+ threadListPath = null
31
+ } = {}) {
32
+ return new ChatAgentConversationDescriptor({
33
+ kind: 0 /* Chat */,
34
+ chatThreadDisplayMode,
35
+ threadDir,
36
+ threadListPath
37
+ });
38
+ }
39
+ static voiceOnly() {
40
+ return new ChatAgentConversationDescriptor({
41
+ kind: 1 /* VoiceOnly */
42
+ });
43
+ }
44
+ static meeting() {
45
+ return new ChatAgentConversationDescriptor({
46
+ kind: 2 /* Meeting */
47
+ });
48
+ }
49
+ kind;
50
+ chatThreadDisplayMode;
51
+ threadDir;
52
+ threadListPath;
53
+ get isChat() {
54
+ return this.kind === 0 /* Chat */;
55
+ }
56
+ get isVoiceOnly() {
57
+ return this.kind === 1 /* VoiceOnly */;
58
+ }
59
+ get isMeeting() {
60
+ return this.kind === 2 /* Meeting */;
61
+ }
62
+ get isMultiThreadChat() {
63
+ return this.isChat && this.chatThreadDisplayMode === 1 /* MultiThreadComposer */;
64
+ }
65
+ }
66
+ function firstAgent(service) {
67
+ return service.agents?.[0] ?? null;
68
+ }
69
+ function defaultThreadDocumentDir(agentName) {
70
+ const trimmed = agentName?.trim();
71
+ if (!trimmed) {
72
+ return null;
73
+ }
74
+ return `.threads/${trimmed}`;
75
+ }
76
+ function threadListPathFromThreadDir(threadDir) {
77
+ const normalized = normalizedThreadDir(threadDir);
78
+ if (normalized === null) {
79
+ return null;
80
+ }
81
+ return `${normalized}/index.threadl`;
82
+ }
83
+ function basename(path) {
84
+ const segments = path.split("/");
85
+ return segments[segments.length - 1] ?? path;
86
+ }
87
+ function participantDisplayName(participant) {
88
+ return normalizedAnnotationString(participant.getAttribute("name"));
89
+ }
90
+ function participantSupportsVoice(participant) {
91
+ return participant.getAttribute("supports_voice") === true;
92
+ }
93
+ function participantSupportsChatOverride(participant) {
94
+ const value = participant.getAttribute("supports_chat");
95
+ return typeof value === "boolean" ? value : null;
96
+ }
97
+ function participantSupportsChat(participant) {
98
+ return participantSupportsChatOverride(participant) ?? true;
99
+ }
100
+ function normalizedAnnotationString(value) {
101
+ if (typeof value !== "string") {
102
+ return null;
103
+ }
104
+ const normalized = value.trim();
105
+ return normalized === "" ? null : normalized;
106
+ }
107
+ function chatThreadDisplayModeFromAnnotation(value) {
108
+ return normalizedAnnotationString(value) === "default-new" ? 1 /* MultiThreadComposer */ : 0 /* SingleThread */;
109
+ }
110
+ function normalizedThreadDir(threadDir) {
111
+ const trimmed = threadDir?.trim();
112
+ if (!trimmed) {
113
+ return null;
114
+ }
115
+ return trimmed.replace(/\/+$/u, "");
116
+ }
117
+ function participantThreadDir(participant) {
118
+ return normalizedThreadDir(normalizedAnnotationString(participant.getAttribute("meshagent.chatbot.thread-dir")));
119
+ }
120
+ function participantThreadListPath(participant) {
121
+ const threadListPath = normalizedAnnotationString(participant.getAttribute("meshagent.chatbot.thread-list"));
122
+ return threadListPath ?? threadListPathFromThreadDir(participantThreadDir(participant));
123
+ }
124
+ function participantConversationDescriptor(participant) {
125
+ const supportsVoice = participantSupportsVoice(participant);
126
+ const supportsChat = participantSupportsChatOverride(participant);
127
+ const threadDir = participantThreadDir(participant);
128
+ const threadListPath = participantThreadListPath(participant);
129
+ const hasThreadAnnotations = normalizedAnnotationString(participant.getAttribute("meshagent.chatbot.threading")) !== null || threadDir !== null || threadListPath !== null;
130
+ if (supportsChat === false) {
131
+ return supportsVoice ? ChatAgentConversationDescriptor.voiceOnly() : null;
132
+ }
133
+ if (supportsVoice && supportsChat !== true && !hasThreadAnnotations) {
134
+ return ChatAgentConversationDescriptor.voiceOnly();
135
+ }
136
+ if (hasThreadAnnotations || participantSupportsChat(participant)) {
137
+ return ChatAgentConversationDescriptor.chat({
138
+ chatThreadDisplayMode: chatThreadDisplayModeFromAnnotation(
139
+ participant.getAttribute("meshagent.chatbot.threading")
140
+ ),
141
+ threadDir,
142
+ threadListPath
143
+ });
144
+ }
145
+ if (supportsVoice) {
146
+ return ChatAgentConversationDescriptor.voiceOnly();
147
+ }
148
+ return null;
149
+ }
150
+ function serviceThreadDir(service) {
151
+ return normalizedThreadDir(firstAgent(service)?.annotations?.["meshagent.chatbot.thread-dir"]);
152
+ }
153
+ function serviceThreadListPath(service, { remoteParticipants = [] } = {}) {
154
+ const annotationPath = normalizedAnnotationString(
155
+ firstAgent(service)?.annotations?.["meshagent.chatbot.thread-list"]
156
+ );
157
+ if (annotationPath !== null) {
158
+ return annotationPath;
159
+ }
160
+ const threadDir = serviceThreadDir(service);
161
+ const threadListPath = threadListPathFromThreadDir(threadDir);
162
+ if (threadListPath !== null) {
163
+ return threadListPath;
164
+ }
165
+ const agentName = firstAgent(service)?.name;
166
+ if (!agentName || agentName.trim() === "") {
167
+ return null;
168
+ }
169
+ for (const participant of remoteParticipants) {
170
+ if (participant.getAttribute("name") === agentName) {
171
+ return participantThreadListPath(participant);
172
+ }
173
+ }
174
+ return null;
175
+ }
176
+ function serviceConversationDescriptor(service, { remoteParticipants = [] } = {}) {
177
+ const type = firstAgent(service)?.annotations?.["meshagent.agent.type"];
178
+ if (type === "VoiceBot") {
179
+ return ChatAgentConversationDescriptor.voiceOnly();
180
+ }
181
+ if (type === "MeetingTranscriber") {
182
+ return ChatAgentConversationDescriptor.meeting();
183
+ }
184
+ if (type !== "ChatBot") {
185
+ return null;
186
+ }
187
+ return ChatAgentConversationDescriptor.chat({
188
+ chatThreadDisplayMode: chatThreadDisplayModeFromAnnotation(
189
+ firstAgent(service)?.annotations?.["meshagent.chatbot.threading"]
190
+ ),
191
+ threadDir: serviceThreadDir(service),
192
+ threadListPath: serviceThreadListPath(service, { remoteParticipants })
193
+ });
194
+ }
195
+ function conversationDescriptorForParticipant(participant, {
196
+ services,
197
+ remoteParticipants
198
+ }) {
199
+ if (!(participant instanceof MeshagentRemoteParticipant)) {
200
+ return null;
201
+ }
202
+ const displayName = participantDisplayName(participant);
203
+ if (displayName !== null) {
204
+ for (const service of services) {
205
+ if (firstAgent(service)?.name !== displayName) {
206
+ continue;
207
+ }
208
+ const descriptor = serviceConversationDescriptor(service, { remoteParticipants });
209
+ if (descriptor !== null) {
210
+ return descriptor;
211
+ }
212
+ }
213
+ }
214
+ return participantConversationDescriptor(participant);
215
+ }
216
+ function resolvedThreadListPath(threadListPath, {
217
+ threadDir,
218
+ agentName
219
+ } = {}) {
220
+ const normalizedPath = normalizedAnnotationString(threadListPath);
221
+ if (normalizedPath !== null) {
222
+ return normalizedPath;
223
+ }
224
+ const normalizedDir = normalizedThreadDir(threadDir);
225
+ if (normalizedDir !== null) {
226
+ return `${normalizedDir}/index.threadl`;
227
+ }
228
+ const defaultThreadDir = defaultThreadDocumentDir(agentName);
229
+ return defaultThreadDir === null ? null : `${defaultThreadDir}/index.threadl`;
230
+ }
231
+ function chatDocumentPath(agentName, {
232
+ threadDir,
233
+ fallbackPath = ".threads/main.thread"
234
+ } = {}) {
235
+ const normalizedDir = normalizedThreadDir(threadDir);
236
+ if (normalizedDir !== null) {
237
+ return `${normalizedDir}/main.thread`;
238
+ }
239
+ const defaultThreadDir = defaultThreadDocumentDir(agentName);
240
+ if (defaultThreadDir !== null) {
241
+ return `${defaultThreadDir}/main.thread`;
242
+ }
243
+ return fallbackPath;
244
+ }
245
+ function defaultThreadDisplayNameFromPath(path) {
246
+ const basenamePath = basename(path);
247
+ const rawName = basenamePath.endsWith(".thread") ? basenamePath.slice(0, -".thread".length) : basenamePath;
248
+ const trimmed = rawName.trim();
249
+ if (!trimmed || uuidPattern.test(trimmed)) {
250
+ return defaultUntitledThreadName;
251
+ }
252
+ const normalized = trimmed.replace(/[_-]+/gu, " ").replace(/\s+/gu, " ").trim();
253
+ if (!normalized) {
254
+ return defaultUntitledThreadName;
255
+ }
256
+ return normalized.split(" ").filter((segment) => segment !== "").map((segment) => segment.length === 1 ? segment.toUpperCase() : `${segment[0]?.toUpperCase() ?? ""}${segment.slice(1)}`).join(" ");
257
+ }
258
+ export {
259
+ ChatAgentConversationDescriptor,
260
+ ChatAgentConversationKind,
261
+ ChatThreadDisplayMode,
262
+ chatDocumentPath,
263
+ chatThreadDisplayModeFromAnnotation,
264
+ conversationDescriptorForParticipant,
265
+ defaultThreadDisplayNameFromPath,
266
+ defaultUntitledThreadName,
267
+ normalizedAnnotationString,
268
+ normalizedThreadDir,
269
+ participantConversationDescriptor,
270
+ participantDisplayName,
271
+ participantSupportsChat,
272
+ participantSupportsChatOverride,
273
+ participantSupportsVoice,
274
+ participantThreadDir,
275
+ participantThreadListPath,
276
+ resolvedThreadListPath,
277
+ serviceConversationDescriptor,
278
+ serviceThreadDir,
279
+ serviceThreadListPath
280
+ };
@@ -0,0 +1,45 @@
1
+ import { EventEmitter, RoomClient } from "@meshagent/meshagent";
2
+ export declare enum UploadStatus {
3
+ Initial = "initial",
4
+ Uploading = "uploading",
5
+ Completed = "completed",
6
+ Failed = "failed"
7
+ }
8
+ export declare abstract class FileAttachment extends EventEmitter<void> {
9
+ protected _status: UploadStatus;
10
+ path: string;
11
+ protected constructor({ path, initialStatus, }: {
12
+ path: string;
13
+ initialStatus?: UploadStatus;
14
+ });
15
+ get status(): UploadStatus;
16
+ protected set status(value: UploadStatus);
17
+ protected notifyChange(): void;
18
+ get filename(): string;
19
+ get size(): number;
20
+ get bytesUploaded(): number;
21
+ }
22
+ export type FileUpload = FileAttachment;
23
+ export declare class MeshagentFileUpload extends FileAttachment {
24
+ readonly room: RoomClient;
25
+ readonly dataStream: AsyncIterable<Uint8Array>;
26
+ private readonly _done;
27
+ private readonly _downloadUrl;
28
+ private _resolveDone;
29
+ private _rejectDone;
30
+ private _resolveDownloadUrl;
31
+ private _rejectDownloadUrl;
32
+ private _bytesUploaded;
33
+ private _size;
34
+ constructor(room: RoomClient, path: string, dataStream: AsyncIterable<Uint8Array>, size?: number, autoStart?: boolean);
35
+ static deferred(room: RoomClient, path: string, dataStream: AsyncIterable<Uint8Array>, size?: number): MeshagentFileUpload;
36
+ get bytesUploaded(): number;
37
+ get size(): number;
38
+ set size(value: number);
39
+ get done(): Promise<void>;
40
+ get downloadUrl(): Promise<URL>;
41
+ startUpload(): void;
42
+ private _upload;
43
+ private _trackedStream;
44
+ }
45
+ export declare function fileToAsyncIterable(file: Blob): AsyncIterable<Uint8Array>;
@@ -0,0 +1,151 @@
1
+ import { EventEmitter } from "@meshagent/meshagent";
2
+ var UploadStatus = /* @__PURE__ */ ((UploadStatus2) => {
3
+ UploadStatus2["Initial"] = "initial";
4
+ UploadStatus2["Uploading"] = "uploading";
5
+ UploadStatus2["Completed"] = "completed";
6
+ UploadStatus2["Failed"] = "failed";
7
+ return UploadStatus2;
8
+ })(UploadStatus || {});
9
+ class FileAttachment extends EventEmitter {
10
+ _status;
11
+ path;
12
+ constructor({
13
+ path,
14
+ initialStatus = "initial" /* Initial */
15
+ }) {
16
+ super();
17
+ this.path = path;
18
+ this._status = initialStatus;
19
+ }
20
+ get status() {
21
+ return this._status;
22
+ }
23
+ set status(value) {
24
+ if (this._status !== value) {
25
+ this._status = value;
26
+ this.notifyChange();
27
+ }
28
+ }
29
+ notifyChange() {
30
+ this.emit("change", void 0);
31
+ }
32
+ get filename() {
33
+ return this.path.split("/").pop() ?? "";
34
+ }
35
+ get size() {
36
+ return 0;
37
+ }
38
+ get bytesUploaded() {
39
+ return 0;
40
+ }
41
+ }
42
+ class MeshagentFileUpload extends FileAttachment {
43
+ room;
44
+ dataStream;
45
+ _done;
46
+ _downloadUrl;
47
+ _resolveDone;
48
+ _rejectDone;
49
+ _resolveDownloadUrl;
50
+ _rejectDownloadUrl;
51
+ _bytesUploaded = 0;
52
+ _size;
53
+ constructor(room, path, dataStream, size = 0, autoStart = true) {
54
+ super({ path });
55
+ this.room = room;
56
+ this.dataStream = dataStream;
57
+ this._size = size;
58
+ this._done = new Promise((resolve, reject) => {
59
+ this._resolveDone = resolve;
60
+ this._rejectDone = reject;
61
+ });
62
+ this._downloadUrl = new Promise((resolve, reject) => {
63
+ this._resolveDownloadUrl = resolve;
64
+ this._rejectDownloadUrl = reject;
65
+ });
66
+ if (autoStart) {
67
+ this.startUpload();
68
+ }
69
+ }
70
+ static deferred(room, path, dataStream, size = 0) {
71
+ return new MeshagentFileUpload(room, path, dataStream, size, false);
72
+ }
73
+ get bytesUploaded() {
74
+ return this._bytesUploaded;
75
+ }
76
+ get size() {
77
+ return this._size;
78
+ }
79
+ set size(value) {
80
+ this._size = value;
81
+ }
82
+ get done() {
83
+ return this._done;
84
+ }
85
+ get downloadUrl() {
86
+ return this._downloadUrl;
87
+ }
88
+ startUpload() {
89
+ if (this.status !== "initial" /* Initial */) {
90
+ throw new Error("upload already started or completed");
91
+ }
92
+ void this._upload();
93
+ }
94
+ async _upload() {
95
+ try {
96
+ this.status = "uploading" /* Uploading */;
97
+ const trackedStream = this._trackedStream();
98
+ await this.room.storage.uploadStream(this.path, trackedStream, {
99
+ overwrite: true,
100
+ size: this.size > 0 ? this.size : null
101
+ });
102
+ this._resolveDone();
103
+ this.status = "completed" /* Completed */;
104
+ const url = await this.room.storage.downloadUrl(this.path);
105
+ this._resolveDownloadUrl(new URL(url));
106
+ } catch (error) {
107
+ this.status = "failed" /* Failed */;
108
+ this._rejectDone(error);
109
+ this._rejectDownloadUrl(error);
110
+ }
111
+ }
112
+ async *_trackedStream() {
113
+ for await (const chunk of this.dataStream) {
114
+ yield chunk;
115
+ this._bytesUploaded += chunk.length;
116
+ this.notifyChange();
117
+ }
118
+ }
119
+ }
120
+ async function* fileToAsyncIterable(file) {
121
+ const chunkSize = 64 * 1024;
122
+ if (typeof file.stream === "function") {
123
+ const reader = file.stream().getReader();
124
+ try {
125
+ while (true) {
126
+ const { done, value } = await reader.read();
127
+ if (done) {
128
+ return;
129
+ }
130
+ if (value != null) {
131
+ yield value;
132
+ }
133
+ }
134
+ } finally {
135
+ reader.releaseLock();
136
+ }
137
+ }
138
+ let offset = 0;
139
+ while (offset < file.size) {
140
+ const chunk = file.slice(offset, offset + chunkSize);
141
+ const buffer = await chunk.arrayBuffer();
142
+ yield new Uint8Array(buffer);
143
+ offset += chunkSize;
144
+ }
145
+ }
146
+ export {
147
+ FileAttachment,
148
+ MeshagentFileUpload,
149
+ UploadStatus,
150
+ fileToAsyncIterable
151
+ };
@@ -1,5 +1,10 @@
1
1
  export * from './Chat';
2
+ export * from './ChatBotView';
2
3
  export * from './ChatInput';
3
4
  export * from './ChatThread';
4
5
  export * from './ChatTypingIndicator';
5
6
  export * from './FileUploader';
7
+ export * from './chat-message';
8
+ export * from './conversation-descriptor';
9
+ export * from './file-attachment';
10
+ export * from './multi-thread-view';
package/dist/esm/index.js CHANGED
@@ -1,5 +1,10 @@
1
1
  export * from "./Chat";
2
+ export * from "./ChatBotView";
2
3
  export * from "./ChatInput";
3
4
  export * from "./ChatThread";
4
5
  export * from "./ChatTypingIndicator";
5
6
  export * from "./FileUploader";
7
+ export * from "./chat-message";
8
+ export * from "./conversation-descriptor";
9
+ export * from "./file-attachment";
10
+ export * from "./multi-thread-view";
@@ -0,0 +1,18 @@
1
+ import type { ReactElement } from "react";
2
+ import { RoomClient } from "@meshagent/meshagent";
3
+ export type MultiThreadContentBuilder = (threadPath: string) => ReactElement;
4
+ export interface MultiThreadViewProps {
5
+ room: RoomClient;
6
+ agentName: string;
7
+ builder: MultiThreadContentBuilder;
8
+ toolkit?: string;
9
+ tool?: string;
10
+ selectedThreadPath?: string | null;
11
+ onSelectedThreadPathChanged?: (path: string | null) => void;
12
+ onSelectedThreadResolved?: (path: string | null, displayName: string | null) => void;
13
+ newThreadResetVersion?: number;
14
+ centerComposer?: boolean;
15
+ emptyStateTitle?: string;
16
+ emptyStateDescription?: string;
17
+ }
18
+ export declare function MultiThreadView({ room, agentName, builder, toolkit, tool, selectedThreadPath, onSelectedThreadPathChanged, onSelectedThreadResolved, newThreadResetVersion, centerComposer, emptyStateTitle, emptyStateDescription, }: MultiThreadViewProps): ReactElement;
@@ -0,0 +1,68 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useState } from "react";
3
+ import { Chat } from "./Chat";
4
+ function normalizeSelectedThreadPath(path) {
5
+ const normalized = path?.trim();
6
+ return normalized ? normalized : null;
7
+ }
8
+ function MultiThreadView({
9
+ room,
10
+ agentName,
11
+ builder,
12
+ toolkit = "chat",
13
+ tool = "new_thread",
14
+ selectedThreadPath,
15
+ onSelectedThreadPathChanged,
16
+ onSelectedThreadResolved,
17
+ newThreadResetVersion = 0,
18
+ centerComposer = true,
19
+ emptyStateTitle,
20
+ emptyStateDescription
21
+ }) {
22
+ const controlledSelectedThreadPath = selectedThreadPath !== void 0 ? normalizeSelectedThreadPath(selectedThreadPath) : void 0;
23
+ const [internalSelectedThreadPath, setInternalSelectedThreadPath] = useState(() => controlledSelectedThreadPath ?? null);
24
+ useEffect(() => {
25
+ if (controlledSelectedThreadPath === void 0) {
26
+ return;
27
+ }
28
+ setInternalSelectedThreadPath(controlledSelectedThreadPath);
29
+ }, [controlledSelectedThreadPath]);
30
+ useEffect(() => {
31
+ if (controlledSelectedThreadPath !== void 0) {
32
+ return;
33
+ }
34
+ setInternalSelectedThreadPath(null);
35
+ }, [agentName, controlledSelectedThreadPath, room]);
36
+ const activeSelectedThreadPath = controlledSelectedThreadPath ?? internalSelectedThreadPath;
37
+ const composerKey = useMemo(
38
+ () => `new-thread-${agentName.trim()}-${newThreadResetVersion}`,
39
+ [agentName, newThreadResetVersion]
40
+ );
41
+ if (activeSelectedThreadPath !== null) {
42
+ return builder(activeSelectedThreadPath);
43
+ }
44
+ return /* @__PURE__ */ jsx(
45
+ Chat,
46
+ {
47
+ room,
48
+ agentName,
49
+ toolkit,
50
+ tool,
51
+ centerComposer,
52
+ emptyStateTitle,
53
+ emptyStateDescription,
54
+ onThreadResolved: (path, displayName) => {
55
+ const normalizedPath = normalizeSelectedThreadPath(path);
56
+ if (controlledSelectedThreadPath === void 0) {
57
+ setInternalSelectedThreadPath(normalizedPath);
58
+ }
59
+ onSelectedThreadPathChanged?.(normalizedPath);
60
+ onSelectedThreadResolved?.(normalizedPath, displayName);
61
+ }
62
+ },
63
+ composerKey
64
+ );
65
+ }
66
+ export {
67
+ MultiThreadView
68
+ };
@@ -1,4 +1,4 @@
1
- import { Toolkit } from '@meshagent/meshagent';
1
+ import { Toolkit } from "@meshagent/meshagent";
2
2
  export declare class UIToolkit extends Toolkit {
3
3
  constructor();
4
4
  }
@@ -14,7 +14,8 @@ class UIToolkit extends Toolkit {
14
14
  new AskUserForFile(),
15
15
  new Toast(),
16
16
  new DisplayDocument()
17
- ]
17
+ ],
18
+ rules: []
18
19
  });
19
20
  }
20
21
  }