@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.
- package/CHANGELOG.md +9 -0
- package/dist/cjs/Chat.d.ts +11 -3
- package/dist/cjs/Chat.js +376 -29
- package/dist/cjs/ChatBotView.d.ts +29 -0
- package/dist/cjs/ChatBotView.js +491 -0
- package/dist/cjs/ChatInput.d.ts +12 -3
- package/dist/cjs/ChatInput.js +143 -44
- package/dist/cjs/ChatThread.d.ts +17 -3
- package/dist/cjs/ChatThread.js +646 -90
- package/dist/cjs/ChatTypingIndicator.d.ts +12 -5
- package/dist/cjs/ChatTypingIndicator.js +104 -13
- package/dist/cjs/FileUploader.d.ts +3 -2
- package/dist/cjs/FileUploader.js +35 -11
- package/dist/cjs/UploadPill.d.ts +2 -2
- package/dist/cjs/UploadPill.js +70 -32
- package/dist/cjs/chat-hooks.d.ts +38 -0
- package/dist/cjs/chat-hooks.js +390 -0
- package/dist/cjs/chat-message.d.ts +11 -0
- package/dist/cjs/chat-message.js +33 -0
- package/dist/cjs/components/ui/button.d.ts +1 -1
- package/dist/cjs/conversation-descriptor.d.ts +59 -0
- package/dist/cjs/conversation-descriptor.js +300 -0
- package/dist/cjs/file-attachment.d.ts +45 -0
- package/dist/cjs/file-attachment.js +171 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.js +5 -0
- package/dist/cjs/multi-thread-view.d.ts +18 -0
- package/dist/cjs/multi-thread-view.js +88 -0
- package/dist/cjs/tools/ui-toolkit.d.ts +1 -1
- package/dist/cjs/tools/ui-toolkit.js +2 -1
- package/dist/esm/Chat.d.ts +11 -3
- package/dist/esm/Chat.js +378 -31
- package/dist/esm/ChatBotView.d.ts +29 -0
- package/dist/esm/ChatBotView.js +486 -0
- package/dist/esm/ChatInput.d.ts +12 -3
- package/dist/esm/ChatInput.js +143 -34
- package/dist/esm/ChatThread.d.ts +17 -3
- package/dist/esm/ChatThread.js +648 -92
- package/dist/esm/ChatTypingIndicator.d.ts +12 -5
- package/dist/esm/ChatTypingIndicator.js +94 -13
- package/dist/esm/FileUploader.d.ts +3 -2
- package/dist/esm/FileUploader.js +26 -12
- package/dist/esm/UploadPill.d.ts +2 -2
- package/dist/esm/UploadPill.js +60 -32
- package/dist/esm/chat-hooks.d.ts +38 -0
- package/dist/esm/chat-hooks.js +372 -0
- package/dist/esm/chat-message.d.ts +11 -0
- package/dist/esm/chat-message.js +13 -0
- package/dist/esm/components/ui/button.d.ts +1 -1
- package/dist/esm/conversation-descriptor.d.ts +59 -0
- package/dist/esm/conversation-descriptor.js +280 -0
- package/dist/esm/file-attachment.d.ts +45 -0
- package/dist/esm/file-attachment.js +151 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/multi-thread-view.d.ts +18 -0
- package/dist/esm/multi-thread-view.js +68 -0
- package/dist/esm/tools/ui-toolkit.d.ts +1 -1
- package/dist/esm/tools/ui-toolkit.js +2 -1
- package/dist/index.css +1 -1
- package/package.json +3 -3
package/dist/esm/Chat.js
CHANGED
|
@@ -1,54 +1,192 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo, useCallback } from "react";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { useState, useRef, useMemo, useEffect, useCallback } from "react";
|
|
3
|
+
import { JsonContent } from "@meshagent/meshagent";
|
|
4
|
+
import { useRoomIndicators } from "@meshagent/meshagent-react";
|
|
5
|
+
import { Plus } from "lucide-react";
|
|
5
6
|
import { ChatInput } from "./ChatInput";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
7
|
+
import { ChatThread } from "./ChatThread";
|
|
8
|
+
import { Button } from "./components/ui/button";
|
|
8
9
|
import { Toaster } from "./components/ui/sonner";
|
|
10
|
+
import { MeshagentFileUpload, fileToAsyncIterable } from "./file-attachment";
|
|
11
|
+
import { useChatThread, useThreadStatus } from "./chat-hooks";
|
|
12
|
+
class NewThreadCancelledError extends Error {
|
|
13
|
+
constructor() {
|
|
14
|
+
super("new thread creation cancelled");
|
|
15
|
+
this.name = "NewThreadCancelledError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function normalizeThreadPath(path) {
|
|
19
|
+
const normalizedPath = path?.trim();
|
|
20
|
+
return normalizedPath ? normalizedPath : null;
|
|
21
|
+
}
|
|
9
22
|
function getParticipantName(participant) {
|
|
10
|
-
const name = participant
|
|
11
|
-
return typeof name === "string" ? name : "";
|
|
23
|
+
const name = participant.getAttribute("name");
|
|
24
|
+
return typeof name === "string" ? name.trim() : "";
|
|
25
|
+
}
|
|
26
|
+
function displayParticipantName(name) {
|
|
27
|
+
const normalizedName = name?.trim();
|
|
28
|
+
if (!normalizedName) {
|
|
29
|
+
return "agent";
|
|
30
|
+
}
|
|
31
|
+
return normalizedName.split("@")[0]?.trim() || normalizedName;
|
|
32
|
+
}
|
|
33
|
+
function isAgentParticipant(participant) {
|
|
34
|
+
return participant.role === "agent" || participant.getAttribute("supports_agent_messages") === true;
|
|
35
|
+
}
|
|
36
|
+
function findTargetAgent(room, agentName) {
|
|
37
|
+
const normalizedAgentName = agentName?.trim();
|
|
38
|
+
for (const participant of room.messaging.remoteParticipants) {
|
|
39
|
+
if (!isAgentParticipant(participant)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (normalizedAgentName && getParticipantName(participant) !== normalizedAgentName) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
return participant;
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
function ensureOperationActive(operationId, activeOperationRef) {
|
|
50
|
+
if (activeOperationRef.current !== operationId) {
|
|
51
|
+
throw new NewThreadCancelledError();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function delay(milliseconds) {
|
|
55
|
+
return new Promise((resolve) => {
|
|
56
|
+
window.setTimeout(resolve, milliseconds);
|
|
57
|
+
});
|
|
12
58
|
}
|
|
13
|
-
function
|
|
59
|
+
async function waitForTargetAgent(params) {
|
|
60
|
+
const { room, agentName, operationId, activeOperationRef } = params;
|
|
61
|
+
while (true) {
|
|
62
|
+
ensureOperationActive(operationId, activeOperationRef);
|
|
63
|
+
const targetAgent = findTargetAgent(room, agentName);
|
|
64
|
+
if (targetAgent) {
|
|
65
|
+
return targetAgent;
|
|
66
|
+
}
|
|
67
|
+
await delay(250);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function waitForToolkitAvailable(params) {
|
|
14
71
|
const {
|
|
72
|
+
room,
|
|
73
|
+
participantId,
|
|
74
|
+
toolkit,
|
|
75
|
+
operationId,
|
|
76
|
+
activeOperationRef
|
|
77
|
+
} = params;
|
|
78
|
+
while (true) {
|
|
79
|
+
ensureOperationActive(operationId, activeOperationRef);
|
|
80
|
+
try {
|
|
81
|
+
const toolkits = await room.agents.listToolkits({ participantId, timeout: 1e3 });
|
|
82
|
+
if (toolkits.some((toolkitDescription) => toolkitDescription.name === toolkit)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
} catch {
|
|
86
|
+
}
|
|
87
|
+
await delay(250);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function getStringField(record, key) {
|
|
91
|
+
const value = record[key];
|
|
92
|
+
return typeof value === "string" && value.trim() !== "" ? value.trim() : null;
|
|
93
|
+
}
|
|
94
|
+
function parseThreadToolResult(toolkit, tool, content) {
|
|
95
|
+
const path = getStringField(content.json, "path");
|
|
96
|
+
if (!path) {
|
|
97
|
+
throw new Error(`${toolkit}.${tool} response missing path`);
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
path,
|
|
101
|
+
displayName: getStringField(content.json, "name")
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function describeError(error) {
|
|
105
|
+
if (error instanceof Error && error.message.trim() !== "") {
|
|
106
|
+
return error.message;
|
|
107
|
+
}
|
|
108
|
+
return `${error}`;
|
|
109
|
+
}
|
|
110
|
+
function EmptyState({
|
|
111
|
+
title,
|
|
112
|
+
description
|
|
113
|
+
}) {
|
|
114
|
+
return /* @__PURE__ */ jsxs("div", { className: "mx-auto flex max-w-2xl flex-col items-center justify-center px-6 py-20 text-center", children: [
|
|
115
|
+
/* @__PURE__ */ jsx("h2", { className: "text-4xl font-semibold tracking-tight text-foreground sm:text-5xl", children: title }),
|
|
116
|
+
description?.trim() ? /* @__PURE__ */ jsx("p", { className: "mt-3 max-w-xl text-sm leading-6 text-muted-foreground sm:text-base", children: description }) : null
|
|
117
|
+
] });
|
|
118
|
+
}
|
|
119
|
+
function ErrorBanner({ message }) {
|
|
120
|
+
return /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-[912px] whitespace-pre-wrap rounded-3xl border border-destructive/30 bg-destructive/5 px-6 py-5 text-sm text-destructive", children: message });
|
|
121
|
+
}
|
|
122
|
+
function ResolvedChatView({
|
|
123
|
+
room,
|
|
124
|
+
path,
|
|
125
|
+
participants,
|
|
126
|
+
agentName,
|
|
127
|
+
emptyStateTitle,
|
|
128
|
+
emptyStateDescription,
|
|
129
|
+
showNewThreadButton = false,
|
|
130
|
+
onStartNewThread
|
|
131
|
+
}) {
|
|
132
|
+
const {
|
|
133
|
+
document,
|
|
15
134
|
messages,
|
|
16
135
|
sendMessage,
|
|
17
136
|
selectAttachments,
|
|
18
137
|
attachments,
|
|
19
138
|
setAttachments,
|
|
20
|
-
|
|
139
|
+
onlineParticipants,
|
|
140
|
+
localParticipantName,
|
|
21
141
|
cancelRequest
|
|
22
|
-
} =
|
|
23
|
-
const { thinking } = useRoomIndicators({ room, path });
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const onTextChange = useCallback((_) => {
|
|
29
|
-
const removeParticipant = room.messaging.remoteParticipants;
|
|
30
|
-
for (const part of removeParticipant) {
|
|
142
|
+
} = useChatThread({ room, path, participants, agentName });
|
|
143
|
+
const { typing, thinking } = useRoomIndicators({ room, path });
|
|
144
|
+
const threadStatus = useThreadStatus({ room, path, agentName });
|
|
145
|
+
const [showCompletedToolCalls, setShowCompletedToolCalls] = useState(false);
|
|
146
|
+
const onTextChange = useCallback(() => {
|
|
147
|
+
for (const participant of onlineParticipants) {
|
|
31
148
|
room.messaging.sendMessage({
|
|
32
|
-
to:
|
|
149
|
+
to: participant,
|
|
33
150
|
type: "typing",
|
|
34
151
|
message: { path }
|
|
35
152
|
});
|
|
36
153
|
}
|
|
37
|
-
}, [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
154
|
+
}, [onlineParticipants, path, room]);
|
|
155
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [
|
|
156
|
+
showNewThreadButton && onStartNewThread ? /* @__PURE__ */ jsx("div", { className: "px-4 pt-3", children: /* @__PURE__ */ jsx("div", { className: "mx-auto flex w-full max-w-[912px] justify-end", children: /* @__PURE__ */ jsxs(
|
|
157
|
+
Button,
|
|
158
|
+
{
|
|
159
|
+
type: "button",
|
|
160
|
+
variant: "outline",
|
|
161
|
+
size: "sm",
|
|
162
|
+
className: "rounded-full shadow-xs",
|
|
163
|
+
onClick: onStartNewThread,
|
|
164
|
+
children: [
|
|
165
|
+
/* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4" }),
|
|
166
|
+
"New thread"
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
) }) }) : null,
|
|
43
170
|
/* @__PURE__ */ jsx(
|
|
44
171
|
ChatThread,
|
|
45
172
|
{
|
|
46
173
|
room,
|
|
174
|
+
path,
|
|
47
175
|
messages,
|
|
48
|
-
|
|
176
|
+
isLoading: document === null,
|
|
177
|
+
localParticipantName,
|
|
178
|
+
showCompletedToolCalls,
|
|
179
|
+
onShowCompletedToolCallsChanged: setShowCompletedToolCalls,
|
|
180
|
+
typing,
|
|
181
|
+
thinking,
|
|
182
|
+
threadStatusText: threadStatus.text,
|
|
183
|
+
threadStatusStartedAt: threadStatus.startedAt,
|
|
184
|
+
threadStatusMode: threadStatus.mode,
|
|
185
|
+
onCancelRequest: cancelRequest,
|
|
186
|
+
emptyStateTitle,
|
|
187
|
+
emptyStateDescription
|
|
49
188
|
}
|
|
50
189
|
),
|
|
51
|
-
/* @__PURE__ */ jsx(ChatTypingIndicator, { room, path }),
|
|
52
190
|
/* @__PURE__ */ jsx(
|
|
53
191
|
ChatInput,
|
|
54
192
|
{
|
|
@@ -56,11 +194,220 @@ function Chat({ room, path, participants }) {
|
|
|
56
194
|
attachments,
|
|
57
195
|
onFilesSelected: selectAttachments,
|
|
58
196
|
setAttachments,
|
|
59
|
-
onTextChange
|
|
60
|
-
onCancelRequest: cancelRequest,
|
|
61
|
-
showCancelButton: thinking
|
|
197
|
+
onTextChange
|
|
62
198
|
}
|
|
63
|
-
)
|
|
199
|
+
)
|
|
200
|
+
] });
|
|
201
|
+
}
|
|
202
|
+
function Chat({
|
|
203
|
+
room,
|
|
204
|
+
path,
|
|
205
|
+
participants,
|
|
206
|
+
agentName,
|
|
207
|
+
toolkit = "chat",
|
|
208
|
+
tool = "new_thread",
|
|
209
|
+
centerComposer = true,
|
|
210
|
+
emptyStateTitle,
|
|
211
|
+
emptyStateDescription,
|
|
212
|
+
onThreadResolved
|
|
213
|
+
}) {
|
|
214
|
+
const [internalThreadPath, setInternalThreadPath] = useState(null);
|
|
215
|
+
const [newThreadDraft, setNewThreadDraft] = useState("");
|
|
216
|
+
const [newThreadAttachments, setNewThreadAttachments] = useState([]);
|
|
217
|
+
const [newThreadError, setNewThreadError] = useState(null);
|
|
218
|
+
const [creatingNewThread, setCreatingNewThread] = useState(false);
|
|
219
|
+
const [waitingForAgent, setWaitingForAgent] = useState(false);
|
|
220
|
+
const activeOperationRef = useRef(0);
|
|
221
|
+
const controlledPath = useMemo(() => normalizeThreadPath(path), [path]);
|
|
222
|
+
const managesOwnThread = controlledPath === null;
|
|
223
|
+
const activePath = controlledPath ?? internalThreadPath;
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
return () => {
|
|
226
|
+
activeOperationRef.current += 1;
|
|
227
|
+
};
|
|
228
|
+
}, []);
|
|
229
|
+
useEffect(() => {
|
|
230
|
+
if (controlledPath !== null) {
|
|
231
|
+
setInternalThreadPath(null);
|
|
232
|
+
}
|
|
233
|
+
}, [controlledPath]);
|
|
234
|
+
useEffect(() => {
|
|
235
|
+
activeOperationRef.current += 1;
|
|
236
|
+
setInternalThreadPath(null);
|
|
237
|
+
setNewThreadDraft("");
|
|
238
|
+
setNewThreadAttachments([]);
|
|
239
|
+
setNewThreadError(null);
|
|
240
|
+
setCreatingNewThread(false);
|
|
241
|
+
setWaitingForAgent(false);
|
|
242
|
+
}, [agentName, managesOwnThread, room]);
|
|
243
|
+
const selectNewThreadAttachments = useCallback((files) => {
|
|
244
|
+
const nextAttachments = files.map((file) => new MeshagentFileUpload(
|
|
245
|
+
room,
|
|
246
|
+
`uploaded-files/${file.name}`,
|
|
247
|
+
fileToAsyncIterable(file),
|
|
248
|
+
file.size
|
|
249
|
+
));
|
|
250
|
+
setNewThreadAttachments((currentAttachments) => [...currentAttachments, ...nextAttachments]);
|
|
251
|
+
}, [room]);
|
|
252
|
+
const cancelPendingNewThread = useCallback(() => {
|
|
253
|
+
activeOperationRef.current += 1;
|
|
254
|
+
setCreatingNewThread(false);
|
|
255
|
+
setWaitingForAgent(false);
|
|
256
|
+
setNewThreadError(null);
|
|
257
|
+
}, []);
|
|
258
|
+
const openNewThreadComposer = useCallback(() => {
|
|
259
|
+
activeOperationRef.current += 1;
|
|
260
|
+
setInternalThreadPath(null);
|
|
261
|
+
setNewThreadDraft("");
|
|
262
|
+
setNewThreadAttachments([]);
|
|
263
|
+
setNewThreadError(null);
|
|
264
|
+
setCreatingNewThread(false);
|
|
265
|
+
setWaitingForAgent(false);
|
|
266
|
+
}, []);
|
|
267
|
+
const handleCreateThread = useCallback(async () => {
|
|
268
|
+
const text = newThreadDraft.trim();
|
|
269
|
+
const hasDraft = text !== "" || newThreadAttachments.length > 0;
|
|
270
|
+
if (!hasDraft || creatingNewThread || waitingForAgent) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const operationId = activeOperationRef.current + 1;
|
|
274
|
+
activeOperationRef.current = operationId;
|
|
275
|
+
const initialTargetAgent = findTargetAgent(room, agentName);
|
|
276
|
+
setWaitingForAgent(initialTargetAgent === null);
|
|
277
|
+
setCreatingNewThread(initialTargetAgent !== null);
|
|
278
|
+
setNewThreadError(null);
|
|
279
|
+
try {
|
|
280
|
+
const targetAgent = initialTargetAgent ?? await waitForTargetAgent({
|
|
281
|
+
room,
|
|
282
|
+
agentName,
|
|
283
|
+
operationId,
|
|
284
|
+
activeOperationRef
|
|
285
|
+
});
|
|
286
|
+
ensureOperationActive(operationId, activeOperationRef);
|
|
287
|
+
if (initialTargetAgent === null) {
|
|
288
|
+
setWaitingForAgent(false);
|
|
289
|
+
setCreatingNewThread(true);
|
|
290
|
+
}
|
|
291
|
+
await waitForToolkitAvailable({
|
|
292
|
+
room,
|
|
293
|
+
participantId: targetAgent.id,
|
|
294
|
+
toolkit,
|
|
295
|
+
operationId,
|
|
296
|
+
activeOperationRef
|
|
297
|
+
});
|
|
298
|
+
ensureOperationActive(operationId, activeOperationRef);
|
|
299
|
+
const response = await room.agents.invokeTool({
|
|
300
|
+
toolkit,
|
|
301
|
+
tool,
|
|
302
|
+
arguments: {
|
|
303
|
+
message: {
|
|
304
|
+
text,
|
|
305
|
+
attachments: newThreadAttachments.map((attachment) => ({ path: attachment.path }))
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
ensureOperationActive(operationId, activeOperationRef);
|
|
310
|
+
if (!(response instanceof JsonContent)) {
|
|
311
|
+
throw new Error(`${toolkit}.${tool} returned non-JSON content`);
|
|
312
|
+
}
|
|
313
|
+
const result = parseThreadToolResult(toolkit, tool, response);
|
|
314
|
+
if (controlledPath === null) {
|
|
315
|
+
setInternalThreadPath(result.path);
|
|
316
|
+
}
|
|
317
|
+
setNewThreadDraft("");
|
|
318
|
+
setNewThreadAttachments([]);
|
|
319
|
+
setNewThreadError(null);
|
|
320
|
+
setCreatingNewThread(false);
|
|
321
|
+
setWaitingForAgent(false);
|
|
322
|
+
onThreadResolved?.(result.path, result.displayName);
|
|
323
|
+
} catch (error) {
|
|
324
|
+
if (error instanceof NewThreadCancelledError) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
setCreatingNewThread(false);
|
|
328
|
+
setWaitingForAgent(false);
|
|
329
|
+
setNewThreadError(describeError(error));
|
|
330
|
+
}
|
|
331
|
+
}, [
|
|
332
|
+
agentName,
|
|
333
|
+
controlledPath,
|
|
334
|
+
creatingNewThread,
|
|
335
|
+
newThreadAttachments,
|
|
336
|
+
newThreadDraft,
|
|
337
|
+
onThreadResolved,
|
|
338
|
+
room,
|
|
339
|
+
toolkit,
|
|
340
|
+
tool,
|
|
341
|
+
waitingForAgent
|
|
342
|
+
]);
|
|
343
|
+
useEffect(() => {
|
|
344
|
+
if (!managesOwnThread) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
const handleKeyDown = (event) => {
|
|
348
|
+
if (!(event.ctrlKey || event.metaKey) || event.key.toLowerCase() !== "n") {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
event.preventDefault();
|
|
352
|
+
openNewThreadComposer();
|
|
353
|
+
};
|
|
354
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
355
|
+
return () => {
|
|
356
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
357
|
+
};
|
|
358
|
+
}, [managesOwnThread, openNewThreadComposer]);
|
|
359
|
+
const targetAgentLabel = useMemo(() => {
|
|
360
|
+
const knownAgentName = agentName?.trim();
|
|
361
|
+
if (knownAgentName) {
|
|
362
|
+
return displayParticipantName(knownAgentName);
|
|
363
|
+
}
|
|
364
|
+
const targetAgent = findTargetAgent(room);
|
|
365
|
+
return displayParticipantName(targetAgent ? getParticipantName(targetAgent) : null);
|
|
366
|
+
}, [agentName, room]);
|
|
367
|
+
const pendingStatusText = waitingForAgent ? `Waiting for ${targetAgentLabel} to be ready.` : creatingNewThread ? `Starting a thread with ${targetAgentLabel}.` : null;
|
|
368
|
+
const composer = /* @__PURE__ */ jsx(
|
|
369
|
+
ChatInput,
|
|
370
|
+
{
|
|
371
|
+
onSubmit: handleCreateThread,
|
|
372
|
+
attachments: newThreadAttachments,
|
|
373
|
+
onFilesSelected: selectNewThreadAttachments,
|
|
374
|
+
setAttachments: setNewThreadAttachments,
|
|
375
|
+
value: newThreadDraft,
|
|
376
|
+
onValueChange: setNewThreadDraft,
|
|
377
|
+
clearOnSubmit: false,
|
|
378
|
+
showCancelButton: creatingNewThread || waitingForAgent,
|
|
379
|
+
onCancelRequest: cancelPendingNewThread,
|
|
380
|
+
disabled: creatingNewThread || waitingForAgent,
|
|
381
|
+
placeholder: agentName?.trim() ? `Type a message or @${displayParticipantName(agentName)}` : "Type a message"
|
|
382
|
+
}
|
|
383
|
+
);
|
|
384
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [
|
|
385
|
+
activePath ? /* @__PURE__ */ jsx(
|
|
386
|
+
ResolvedChatView,
|
|
387
|
+
{
|
|
388
|
+
room,
|
|
389
|
+
path: activePath,
|
|
390
|
+
participants,
|
|
391
|
+
agentName,
|
|
392
|
+
emptyStateTitle,
|
|
393
|
+
emptyStateDescription,
|
|
394
|
+
showNewThreadButton: managesOwnThread,
|
|
395
|
+
onStartNewThread: openNewThreadComposer
|
|
396
|
+
},
|
|
397
|
+
activePath
|
|
398
|
+
) : centerComposer ? /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 items-center justify-center px-4 py-6", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-[912px] space-y-5", children: [
|
|
399
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2 text-center", children: [
|
|
400
|
+
/* @__PURE__ */ jsx("h2", { className: "text-4xl font-semibold tracking-tight text-foreground sm:text-5xl", children: "Start a new thread" }),
|
|
401
|
+
pendingStatusText ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground sm:text-base", children: pendingStatusText }) : null
|
|
402
|
+
] }),
|
|
403
|
+
composer,
|
|
404
|
+
newThreadError ? /* @__PURE__ */ jsx(ErrorBanner, { message: newThreadError }) : null
|
|
405
|
+
] }) }) : /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [
|
|
406
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1", children: emptyStateTitle ? /* @__PURE__ */ jsx(EmptyState, { title: emptyStateTitle, description: emptyStateDescription }) : null }),
|
|
407
|
+
pendingStatusText ? /* @__PURE__ */ jsx("div", { className: "px-4 pb-2", children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-[912px] text-sm text-muted-foreground", children: pendingStatusText }) }) : null,
|
|
408
|
+
newThreadError ? /* @__PURE__ */ jsx("div", { className: "px-4 pb-2", children: /* @__PURE__ */ jsx(ErrorBanner, { message: newThreadError }) }) : null,
|
|
409
|
+
composer
|
|
410
|
+
] }),
|
|
64
411
|
/* @__PURE__ */ jsx(Toaster, {})
|
|
65
412
|
] });
|
|
66
413
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import { Participant, RoomClient } from "@meshagent/meshagent";
|
|
3
|
+
import { ChatThreadDisplayMode } from "./conversation-descriptor";
|
|
4
|
+
export { ChatThreadDisplayMode, chatDocumentPath, resolvedThreadListPath, } from "./conversation-descriptor";
|
|
5
|
+
export interface ChatBotViewProps {
|
|
6
|
+
room: RoomClient;
|
|
7
|
+
path?: string;
|
|
8
|
+
documentPath?: string;
|
|
9
|
+
participants?: Participant[];
|
|
10
|
+
agentName?: string;
|
|
11
|
+
threadDisplayMode?: ChatThreadDisplayMode;
|
|
12
|
+
threadDir?: string;
|
|
13
|
+
threadListPath?: string;
|
|
14
|
+
toolkit?: string;
|
|
15
|
+
tool?: string;
|
|
16
|
+
centerComposer?: boolean;
|
|
17
|
+
emptyStateTitle?: string;
|
|
18
|
+
emptyStateDescription?: string;
|
|
19
|
+
selectedThreadPath?: string | null;
|
|
20
|
+
selectedThreadDisplayName?: string | null;
|
|
21
|
+
onSelectedThreadPathChanged?: (path: string | null) => void;
|
|
22
|
+
onSelectedThreadResolved?: (path: string | null, displayName: string | null) => void;
|
|
23
|
+
onThreadResolved?: (path: string | null, displayName: string | null) => void;
|
|
24
|
+
newThreadResetVersion?: number;
|
|
25
|
+
showThreadList?: boolean;
|
|
26
|
+
threadListWidth?: number;
|
|
27
|
+
threadListCollapsedHeight?: number;
|
|
28
|
+
}
|
|
29
|
+
export declare function ChatBotView({ room, path, documentPath, participants, agentName, threadDisplayMode, threadDir, threadListPath, toolkit, tool, centerComposer, emptyStateTitle, emptyStateDescription, selectedThreadPath, onSelectedThreadPathChanged, onSelectedThreadResolved, onThreadResolved, newThreadResetVersion, showThreadList, threadListWidth, threadListCollapsedHeight, }: ChatBotViewProps): ReactElement;
|