@meshagent/meshagent-tailwind 0.39.5 → 0.39.7
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.js +14 -4
- package/dist/cjs/ChatBotView.d.ts +3 -1
- package/dist/cjs/ChatBotView.js +4 -4
- package/dist/cjs/ChatInput.js +14 -5
- package/dist/cjs/ChatThread.js +41 -1
- package/dist/cjs/chat-hooks.d.ts +5 -2
- package/dist/cjs/chat-hooks.js +245 -26
- package/dist/cjs/components/pane-example.js +3 -3
- package/dist/cjs/components/ui/sonner.d.ts +1 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/multi-thread-view.js +5 -5
- package/dist/esm/Chat.js +14 -4
- package/dist/esm/ChatBotView.d.ts +3 -1
- package/dist/esm/ChatBotView.js +4 -4
- package/dist/esm/ChatInput.js +14 -5
- package/dist/esm/ChatThread.js +41 -1
- package/dist/esm/chat-hooks.d.ts +5 -2
- package/dist/esm/chat-hooks.js +245 -26
- package/dist/esm/components/pane-example.js +3 -3
- package/dist/esm/components/ui/sonner.d.ts +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/multi-thread-view.js +5 -5
- package/dist/index.css +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## [0.39.7]
|
|
2
|
+
- Updated Meshagent JS/TS package manifests so inter-package dependencies are aligned to the new Meshagent version (`@meshagent/*` packages now depend on the updated `^0.39.6` versions).
|
|
3
|
+
|
|
4
|
+
## [0.39.6]
|
|
5
|
+
- Chat thread message sending now supports an “agent messages” mode: it selects participants that advertise agent-message support and sends `agent-message` payloads using `meshagent.agent.turn.start` / `meshagent.agent.turn.steer` types (including turn/thread scoping), with Promise-based sending and cancellation when recipients never materialize.
|
|
6
|
+
- Chat UI/logic now determines the correct outbound message type (chat vs steer) and turn context from thread status, and passes that into message sending.
|
|
7
|
+
- DatasetsClient now adds strongly typed `importFromStorage` and `exportToStorage` APIs with dataset storage format + import mode options, optional `namespace`/`branch` scoping, and `batch_size` support that is omitted when unset.
|
|
8
|
+
- Unit tests were updated to verify the new import/export request payload shapes and defaults.
|
|
9
|
+
|
|
1
10
|
## [0.39.5]
|
|
2
11
|
- Stability
|
|
3
12
|
|
package/dist/cjs/Chat.js
CHANGED
|
@@ -134,8 +134,8 @@ function EmptyState({
|
|
|
134
134
|
title,
|
|
135
135
|
description
|
|
136
136
|
}) {
|
|
137
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "h-full
|
|
138
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-4xl font-
|
|
137
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "h-full flex flex-col items-center justify-center px-6 py-20 text-center", children: [
|
|
138
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-4xl font-bold tracking-tight text-foreground", children: title }),
|
|
139
139
|
description?.trim() ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mt-3 max-w-xl text-sm leading-6 text-muted-foreground sm:text-base", children: description }) : null
|
|
140
140
|
] });
|
|
141
141
|
}
|
|
@@ -152,6 +152,9 @@ function ResolvedChatView({
|
|
|
152
152
|
showNewThreadButton = false,
|
|
153
153
|
onStartNewThread
|
|
154
154
|
}) {
|
|
155
|
+
const threadStatus = (0, import_chat_hooks.useThreadStatus)({ room, path, agentName });
|
|
156
|
+
const useAgentMessages = threadStatus.supportsAgentMessages;
|
|
157
|
+
const messageType = useAgentMessages && threadStatus.mode === "steerable" && threadStatus.turnId ? "steer" : "chat";
|
|
155
158
|
const {
|
|
156
159
|
document,
|
|
157
160
|
messages,
|
|
@@ -162,9 +165,16 @@ function ResolvedChatView({
|
|
|
162
165
|
onlineParticipants,
|
|
163
166
|
localParticipantName,
|
|
164
167
|
cancelRequest
|
|
165
|
-
} = (0, import_chat_hooks.useChatThread)({
|
|
168
|
+
} = (0, import_chat_hooks.useChatThread)({
|
|
169
|
+
room,
|
|
170
|
+
path,
|
|
171
|
+
participants,
|
|
172
|
+
agentName,
|
|
173
|
+
useAgentMessages,
|
|
174
|
+
messageType,
|
|
175
|
+
turnId: threadStatus.turnId
|
|
176
|
+
});
|
|
166
177
|
const { typing, thinking } = (0, import_meshagent_react.useRoomIndicators)({ room, path });
|
|
167
|
-
const threadStatus = (0, import_chat_hooks.useThreadStatus)({ room, path, agentName });
|
|
168
178
|
const [showCompletedToolCalls, setShowCompletedToolCalls] = (0, import_react.useState)(false);
|
|
169
179
|
const onTextChange = (0, import_react.useCallback)(() => {
|
|
170
180
|
for (const participant of onlineParticipants) {
|
|
@@ -16,6 +16,8 @@ export interface ChatBotViewProps {
|
|
|
16
16
|
centerComposer?: boolean;
|
|
17
17
|
emptyStateTitle?: string;
|
|
18
18
|
emptyStateDescription?: string;
|
|
19
|
+
startNewThreadTitle?: string;
|
|
20
|
+
startNewThreadDescription?: string;
|
|
19
21
|
selectedThreadPath?: string | null;
|
|
20
22
|
selectedThreadDisplayName?: string | null;
|
|
21
23
|
onSelectedThreadPathChanged?: (path: string | null) => void;
|
|
@@ -26,4 +28,4 @@ export interface ChatBotViewProps {
|
|
|
26
28
|
threadListWidth?: number;
|
|
27
29
|
threadListCollapsedHeight?: number;
|
|
28
30
|
}
|
|
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;
|
|
31
|
+
export declare function ChatBotView({ room, path, documentPath, participants, agentName, threadDisplayMode, threadDir, threadListPath, toolkit, tool, centerComposer, emptyStateTitle, emptyStateDescription, startNewThreadTitle, startNewThreadDescription, selectedThreadPath, onSelectedThreadPathChanged, onSelectedThreadResolved, onThreadResolved, newThreadResetVersion, showThreadList, threadListWidth, threadListCollapsedHeight, }: ChatBotViewProps): ReactElement;
|
package/dist/cjs/ChatBotView.js
CHANGED
|
@@ -363,6 +363,8 @@ function ChatBotView({
|
|
|
363
363
|
centerComposer = false,
|
|
364
364
|
emptyStateTitle = "No threads yet",
|
|
365
365
|
emptyStateDescription = "Start a new conversation to see it here.",
|
|
366
|
+
startNewThreadTitle = "Start a new thread",
|
|
367
|
+
startNewThreadDescription = "Connect with this agent and your team.",
|
|
366
368
|
selectedThreadPath,
|
|
367
369
|
onSelectedThreadPathChanged,
|
|
368
370
|
onSelectedThreadResolved,
|
|
@@ -511,8 +513,6 @@ function ChatBotView({
|
|
|
511
513
|
onSelectedThreadResolved: emitResolvedThread,
|
|
512
514
|
newThreadResetVersion,
|
|
513
515
|
centerComposer,
|
|
514
|
-
emptyStateTitle,
|
|
515
|
-
emptyStateDescription,
|
|
516
516
|
builder: (threadPath) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
517
517
|
import_Chat.Chat,
|
|
518
518
|
{
|
|
@@ -523,8 +523,8 @@ function ChatBotView({
|
|
|
523
523
|
toolkit,
|
|
524
524
|
tool,
|
|
525
525
|
centerComposer,
|
|
526
|
-
emptyStateTitle,
|
|
527
|
-
emptyStateDescription
|
|
526
|
+
emptyStateTitle: startNewThreadTitle,
|
|
527
|
+
emptyStateDescription: startNewThreadDescription
|
|
528
528
|
}
|
|
529
529
|
)
|
|
530
530
|
}
|
package/dist/cjs/ChatInput.js
CHANGED
|
@@ -27,11 +27,12 @@ var import_lucide_react = require("lucide-react");
|
|
|
27
27
|
var import_uuid = require("uuid");
|
|
28
28
|
var import_chat_message = require("./chat-message");
|
|
29
29
|
var import_button = require("./components/ui/button");
|
|
30
|
-
var import_textarea = require("./components/ui/textarea");
|
|
31
30
|
var import_FileUploader = require("./FileUploader");
|
|
32
31
|
var import_UploadPill = require("./UploadPill");
|
|
33
32
|
var import_file_attachment = require("./file-attachment");
|
|
34
33
|
var import_utils = require("./lib/utils");
|
|
34
|
+
const MIN_TEXTAREA_HEIGHT = 20;
|
|
35
|
+
const MAX_TEXTAREA_HEIGHT = 160;
|
|
35
36
|
function useAttachmentStatusVersion(attachments) {
|
|
36
37
|
const [version, setVersion] = (0, import_react.useState)(0);
|
|
37
38
|
(0, import_react.useEffect)(() => {
|
|
@@ -56,10 +57,13 @@ function useAutoResizingTextarea(textareaRef, value) {
|
|
|
56
57
|
return;
|
|
57
58
|
}
|
|
58
59
|
if (value === "") {
|
|
59
|
-
element.style.height =
|
|
60
|
+
element.style.height = `${MIN_TEXTAREA_HEIGHT}px`;
|
|
60
61
|
} else {
|
|
61
62
|
element.style.height = "0px";
|
|
62
|
-
element.style.height = `${Math.max(
|
|
63
|
+
element.style.height = `${Math.max(
|
|
64
|
+
MIN_TEXTAREA_HEIGHT,
|
|
65
|
+
Math.min(element.scrollHeight, MAX_TEXTAREA_HEIGHT)
|
|
66
|
+
)}px`;
|
|
63
67
|
}
|
|
64
68
|
}, [textareaRef, value]);
|
|
65
69
|
}
|
|
@@ -185,12 +189,17 @@ function ChatInput({
|
|
|
185
189
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
186
190
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_FileUploader.FileUploader, { onFilesSelected, disabled }),
|
|
187
191
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
188
|
-
|
|
192
|
+
"textarea",
|
|
189
193
|
{
|
|
190
194
|
ref: textareaRef,
|
|
191
195
|
autoFocus,
|
|
192
196
|
placeholder,
|
|
193
|
-
className:
|
|
197
|
+
className: (0, import_utils.cn)(
|
|
198
|
+
"min-h-5 max-h-40",
|
|
199
|
+
"flex-1 resize-none border-0 bg-transparent p-0 leading-5",
|
|
200
|
+
"shadow-none outline-none ring-0 focus:ring-0 focus-visible:ring-0 disabled:cursor-not-allowed disabled:opacity-50",
|
|
201
|
+
"md:text-sm"
|
|
202
|
+
),
|
|
194
203
|
readOnly: disabled,
|
|
195
204
|
value,
|
|
196
205
|
onChange: handleChange,
|
package/dist/cjs/ChatThread.js
CHANGED
|
@@ -259,7 +259,47 @@ function MarkdownBlock({ text }) {
|
|
|
259
259
|
children
|
|
260
260
|
}
|
|
261
261
|
),
|
|
262
|
-
p: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { ...props, className: "mb-2 last:mb-0", children })
|
|
262
|
+
p: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { ...props, className: "mb-2 last:mb-0", children }),
|
|
263
|
+
table: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "my-4 w-full overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
264
|
+
"table",
|
|
265
|
+
{
|
|
266
|
+
...props,
|
|
267
|
+
className: "w-full border-collapse border-spacing-0",
|
|
268
|
+
children
|
|
269
|
+
}
|
|
270
|
+
) }),
|
|
271
|
+
th: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
272
|
+
"th",
|
|
273
|
+
{
|
|
274
|
+
...props,
|
|
275
|
+
className: "border bg-muted/50 px-3 py-2 text-left text-sm font-semibold",
|
|
276
|
+
children
|
|
277
|
+
}
|
|
278
|
+
),
|
|
279
|
+
td: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
280
|
+
"td",
|
|
281
|
+
{
|
|
282
|
+
...props,
|
|
283
|
+
className: "border px-3 py-2 align-top text-sm bg-background",
|
|
284
|
+
children
|
|
285
|
+
}
|
|
286
|
+
),
|
|
287
|
+
ul: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
288
|
+
"ul",
|
|
289
|
+
{
|
|
290
|
+
...props,
|
|
291
|
+
className: "mb-2 ml-6 list-disc last:mb-0",
|
|
292
|
+
children
|
|
293
|
+
}
|
|
294
|
+
),
|
|
295
|
+
ol: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
296
|
+
"ol",
|
|
297
|
+
{
|
|
298
|
+
...props,
|
|
299
|
+
className: "mb-2 ml-6 list-decimal last:mb-0",
|
|
300
|
+
children
|
|
301
|
+
}
|
|
302
|
+
)
|
|
263
303
|
},
|
|
264
304
|
children: text
|
|
265
305
|
}
|
package/dist/cjs/chat-hooks.d.ts
CHANGED
|
@@ -9,11 +9,14 @@ export interface UseChatThreadProps {
|
|
|
9
9
|
includeLocalParticipant?: boolean;
|
|
10
10
|
initialMessage?: ChatMessage;
|
|
11
11
|
agentName?: string;
|
|
12
|
+
useAgentMessages?: boolean;
|
|
13
|
+
messageType?: string;
|
|
14
|
+
turnId?: string;
|
|
12
15
|
}
|
|
13
16
|
export interface UseChatThreadResult {
|
|
14
17
|
document: MeshDocument | null;
|
|
15
18
|
messages: Element[];
|
|
16
|
-
sendMessage: (message: ChatMessage) => void
|
|
19
|
+
sendMessage: (message: ChatMessage) => Promise<void>;
|
|
17
20
|
selectAttachments: (files: File[]) => void;
|
|
18
21
|
attachments: FileUpload[];
|
|
19
22
|
setAttachments: (attachments: FileUpload[]) => void;
|
|
@@ -70,5 +73,5 @@ export interface UseThreadStatusProps {
|
|
|
70
73
|
previous?: ChatThreadStatusState;
|
|
71
74
|
}
|
|
72
75
|
export declare function formatThreadStatusText(text: string, startedAt?: Date | null): string;
|
|
73
|
-
export declare function useChatThread({ room, path, participants, participantNames, initialMessage, includeLocalParticipant, agentName, }: UseChatThreadProps): UseChatThreadResult;
|
|
76
|
+
export declare function useChatThread({ room, path, participants, participantNames, initialMessage, includeLocalParticipant, agentName, useAgentMessages, messageType, turnId, }: UseChatThreadProps): UseChatThreadResult;
|
|
74
77
|
export declare function useThreadStatus({ room, path, agentName }: UseThreadStatusProps): ThreadStatus;
|
package/dist/cjs/chat-hooks.js
CHANGED
|
@@ -29,7 +29,15 @@ var import_react = require("react");
|
|
|
29
29
|
var import_meshagent = require("@meshagent/meshagent");
|
|
30
30
|
var import_meshagent_react = require("@meshagent/meshagent-react");
|
|
31
31
|
var import_file_attachment = require("./file-attachment");
|
|
32
|
+
const agentRoomMessageType = "agent-message";
|
|
33
|
+
const agentTurnStartType = "meshagent.agent.turn.start";
|
|
32
34
|
const agentTurnSteerType = "meshagent.agent.turn.steer";
|
|
35
|
+
class ChatSendCancelledError extends Error {
|
|
36
|
+
constructor() {
|
|
37
|
+
super("chat send cancelled");
|
|
38
|
+
this.name = "ChatSendCancelledError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
33
41
|
class PendingAgentMessage {
|
|
34
42
|
messageId;
|
|
35
43
|
messageType;
|
|
@@ -202,6 +210,175 @@ function getOnlineParticipants(roomParticipants, participantNames) {
|
|
|
202
210
|
function supportsAgentMessages(participant) {
|
|
203
211
|
return participant.getAttribute("supports_agent_messages") === true;
|
|
204
212
|
}
|
|
213
|
+
function uniqueRemoteParticipantsById(participants) {
|
|
214
|
+
const seenParticipantIds = /* @__PURE__ */ new Set();
|
|
215
|
+
const uniqueParticipants = [];
|
|
216
|
+
for (const participant of participants) {
|
|
217
|
+
if (seenParticipantIds.has(participant.id)) {
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
seenParticipantIds.add(participant.id);
|
|
221
|
+
uniqueParticipants.push(participant);
|
|
222
|
+
}
|
|
223
|
+
return uniqueParticipants;
|
|
224
|
+
}
|
|
225
|
+
function getAgentParticipants({
|
|
226
|
+
room,
|
|
227
|
+
document,
|
|
228
|
+
participantName
|
|
229
|
+
}) {
|
|
230
|
+
const normalizedParticipantName = participantName?.trim();
|
|
231
|
+
return uniqueRemoteParticipantsById(
|
|
232
|
+
getOnlineParticipants(room.messaging.remoteParticipants, getDocumentParticipantNames(document)).filter((participant) => {
|
|
233
|
+
if (normalizedParticipantName && getParticipantName(participant) !== normalizedParticipantName) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
return supportsAgentMessages(participant);
|
|
237
|
+
})
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
function matchingRecipients({
|
|
241
|
+
room,
|
|
242
|
+
document,
|
|
243
|
+
useAgentMessages,
|
|
244
|
+
participantName
|
|
245
|
+
}) {
|
|
246
|
+
const normalizedParticipantName = participantName?.trim();
|
|
247
|
+
if (useAgentMessages) {
|
|
248
|
+
return getAgentParticipants({ room, document, participantName: normalizedParticipantName });
|
|
249
|
+
}
|
|
250
|
+
return uniqueRemoteParticipantsById(
|
|
251
|
+
getOnlineParticipants(room.messaging.remoteParticipants, getDocumentParticipantNames(document)).filter((participant) => {
|
|
252
|
+
if (!normalizedParticipantName) {
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
return getParticipantName(participant) === normalizedParticipantName;
|
|
256
|
+
})
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
function normalizeAgentAttachmentUrl(path) {
|
|
260
|
+
const trimmedPath = path.trim();
|
|
261
|
+
if (trimmedPath === "") {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
try {
|
|
265
|
+
const url = new URL(trimmedPath);
|
|
266
|
+
if (url.protocol !== "") {
|
|
267
|
+
return trimmedPath;
|
|
268
|
+
}
|
|
269
|
+
} catch {
|
|
270
|
+
}
|
|
271
|
+
const roomPath = trimmedPath.startsWith("/") ? trimmedPath.slice(1) : trimmedPath;
|
|
272
|
+
return roomPath === "" ? null : `room:///${roomPath}`;
|
|
273
|
+
}
|
|
274
|
+
function agentInputContentFromMessage(message) {
|
|
275
|
+
const content = [];
|
|
276
|
+
if (message.text.trim() !== "") {
|
|
277
|
+
content.push({ type: "text", text: message.text });
|
|
278
|
+
}
|
|
279
|
+
for (const attachmentPath of message.attachments) {
|
|
280
|
+
const normalizedUrl = normalizeAgentAttachmentUrl(attachmentPath);
|
|
281
|
+
if (normalizedUrl !== null) {
|
|
282
|
+
content.push({ type: "file", url: normalizedUrl });
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return content;
|
|
286
|
+
}
|
|
287
|
+
async function sendMessageToParticipant({
|
|
288
|
+
room,
|
|
289
|
+
participant,
|
|
290
|
+
path,
|
|
291
|
+
message,
|
|
292
|
+
messageType = "chat",
|
|
293
|
+
useAgentMessages = false,
|
|
294
|
+
turnId,
|
|
295
|
+
store = false
|
|
296
|
+
}) {
|
|
297
|
+
if (message.text.trim() === "" && message.attachments.length === 0) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
if (useAgentMessages) {
|
|
301
|
+
const isSteer = messageType === "steer";
|
|
302
|
+
const payload = {
|
|
303
|
+
type: isSteer ? agentTurnSteerType : agentTurnStartType,
|
|
304
|
+
thread_id: path,
|
|
305
|
+
message_id: message.id,
|
|
306
|
+
content: agentInputContentFromMessage(message)
|
|
307
|
+
};
|
|
308
|
+
if (isSteer && turnId?.trim()) {
|
|
309
|
+
payload.turn_id = turnId.trim();
|
|
310
|
+
}
|
|
311
|
+
await room.messaging.sendMessage({
|
|
312
|
+
to: participant,
|
|
313
|
+
type: agentRoomMessageType,
|
|
314
|
+
message: { payload }
|
|
315
|
+
});
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
await room.messaging.sendMessage({
|
|
319
|
+
to: participant,
|
|
320
|
+
type: messageType,
|
|
321
|
+
message: {
|
|
322
|
+
path,
|
|
323
|
+
text: message.text,
|
|
324
|
+
attachments: message.attachments.map((attachmentPath) => ({ path: attachmentPath })),
|
|
325
|
+
store
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
function waitForRecipients({
|
|
330
|
+
room,
|
|
331
|
+
document,
|
|
332
|
+
messageId,
|
|
333
|
+
useAgentMessages,
|
|
334
|
+
participantName,
|
|
335
|
+
pendingRecipientWaits
|
|
336
|
+
}) {
|
|
337
|
+
pendingRecipientWaits.get(messageId)?.();
|
|
338
|
+
return new Promise((resolve, reject) => {
|
|
339
|
+
let finished = false;
|
|
340
|
+
const eventNames = [
|
|
341
|
+
"participant_added",
|
|
342
|
+
"participant_removed",
|
|
343
|
+
"participant_attributes_updated",
|
|
344
|
+
"messaging_enabled"
|
|
345
|
+
];
|
|
346
|
+
const finish = () => {
|
|
347
|
+
if (finished) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
finished = true;
|
|
351
|
+
for (const eventName of eventNames) {
|
|
352
|
+
room.messaging.off(eventName, listener);
|
|
353
|
+
}
|
|
354
|
+
if (pendingRecipientWaits.get(messageId) === cancel) {
|
|
355
|
+
pendingRecipientWaits.delete(messageId);
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
const cancel = () => {
|
|
359
|
+
finish();
|
|
360
|
+
reject(new ChatSendCancelledError());
|
|
361
|
+
};
|
|
362
|
+
const listener = () => {
|
|
363
|
+
const recipients = matchingRecipients({
|
|
364
|
+
room,
|
|
365
|
+
document,
|
|
366
|
+
useAgentMessages,
|
|
367
|
+
participantName
|
|
368
|
+
});
|
|
369
|
+
if (recipients.length === 0) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
finish();
|
|
373
|
+
resolve(recipients);
|
|
374
|
+
};
|
|
375
|
+
pendingRecipientWaits.set(messageId, cancel);
|
|
376
|
+
for (const eventName of eventNames) {
|
|
377
|
+
room.messaging.on(eventName, listener);
|
|
378
|
+
}
|
|
379
|
+
listener();
|
|
380
|
+
});
|
|
381
|
+
}
|
|
205
382
|
function threadStatusAttributeCandidates(path, prefix) {
|
|
206
383
|
if (path.startsWith("/")) {
|
|
207
384
|
return [`${prefix}.${path}`, `${prefix}.${path.slice(1)}`];
|
|
@@ -387,13 +564,17 @@ function useChatThread({
|
|
|
387
564
|
participantNames,
|
|
388
565
|
initialMessage,
|
|
389
566
|
includeLocalParticipant,
|
|
390
|
-
agentName
|
|
567
|
+
agentName,
|
|
568
|
+
useAgentMessages = false,
|
|
569
|
+
messageType = "chat",
|
|
570
|
+
turnId
|
|
391
571
|
}) {
|
|
392
572
|
const [document, setDocument] = (0, import_react.useState)(null);
|
|
393
573
|
const [messages, setMessages] = (0, import_react.useState)(() => document ? mapThreadElements(document) : []);
|
|
394
574
|
const [attachments, setAttachments] = (0, import_react.useState)([]);
|
|
395
575
|
const [documentParticipantNames, setDocumentParticipantNames] = (0, import_react.useState)(() => document ? getDocumentParticipantNames(document) : []);
|
|
396
576
|
const initialMessageSentRef = (0, import_react.useRef)(false);
|
|
577
|
+
const pendingRecipientWaitsRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
|
|
397
578
|
const syncDocumentState = (0, import_react.useCallback)((nextDocument) => {
|
|
398
579
|
const nextMessages = mapThreadElements(nextDocument);
|
|
399
580
|
const nextParticipantNames = getDocumentParticipantNames(nextDocument);
|
|
@@ -442,6 +623,14 @@ function useChatThread({
|
|
|
442
623
|
}
|
|
443
624
|
};
|
|
444
625
|
}, [path, room, syncDocumentState]);
|
|
626
|
+
(0, import_react.useEffect)(() => {
|
|
627
|
+
return () => {
|
|
628
|
+
for (const cancel of pendingRecipientWaitsRef.current.values()) {
|
|
629
|
+
cancel();
|
|
630
|
+
}
|
|
631
|
+
pendingRecipientWaitsRef.current.clear();
|
|
632
|
+
};
|
|
633
|
+
}, []);
|
|
445
634
|
(0, import_react.useEffect)(() => {
|
|
446
635
|
if (!document || !room.localParticipant) {
|
|
447
636
|
return;
|
|
@@ -476,38 +665,68 @@ function useChatThread({
|
|
|
476
665
|
() => getOnlineParticipants(roomParticipants, documentParticipantNames),
|
|
477
666
|
[roomParticipants, documentParticipantNames]
|
|
478
667
|
);
|
|
479
|
-
const sendMessage = (0, import_react.useCallback)((message) => {
|
|
668
|
+
const sendMessage = (0, import_react.useCallback)(async (message) => {
|
|
669
|
+
if (message.text.trim() === "" && message.attachments.length === 0) {
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
const normalizedParticipantName = agentName?.trim();
|
|
673
|
+
const storeLocally = !normalizedParticipantName && !useAgentMessages;
|
|
480
674
|
const children = document?.root.getChildren() ?? [];
|
|
481
|
-
const
|
|
482
|
-
if (!
|
|
675
|
+
const messagesElement = children.find((child) => child.tagName === "messages");
|
|
676
|
+
if (!document || !messagesElement) {
|
|
483
677
|
return;
|
|
484
678
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
679
|
+
if (storeLocally) {
|
|
680
|
+
const authorName = getParticipantName(room.localParticipant);
|
|
681
|
+
const messageElement = messagesElement.createChildElement("message", {
|
|
682
|
+
id: message.id,
|
|
683
|
+
text: message.text,
|
|
684
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
685
|
+
author_name: authorName,
|
|
686
|
+
author_ref: null
|
|
687
|
+
});
|
|
688
|
+
for (const attachmentPath of message.attachments) {
|
|
689
|
+
messageElement.createChildElement("file", { path: attachmentPath });
|
|
690
|
+
}
|
|
495
691
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
692
|
+
let recipients = matchingRecipients({
|
|
693
|
+
room,
|
|
694
|
+
document,
|
|
695
|
+
useAgentMessages,
|
|
696
|
+
participantName: normalizedParticipantName
|
|
697
|
+
});
|
|
698
|
+
if (recipients.length === 0) {
|
|
699
|
+
const shouldWaitForRecipient = useAgentMessages || Boolean(normalizedParticipantName);
|
|
700
|
+
if (!shouldWaitForRecipient) {
|
|
701
|
+
throw new Error(`no matching recipients are available for '${path}'`);
|
|
499
702
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
703
|
+
try {
|
|
704
|
+
recipients = await waitForRecipients({
|
|
705
|
+
room,
|
|
706
|
+
document,
|
|
707
|
+
messageId: message.id,
|
|
708
|
+
useAgentMessages,
|
|
709
|
+
participantName: normalizedParticipantName,
|
|
710
|
+
pendingRecipientWaits: pendingRecipientWaitsRef.current
|
|
711
|
+
});
|
|
712
|
+
} catch (error) {
|
|
713
|
+
if (error instanceof ChatSendCancelledError) {
|
|
714
|
+
return;
|
|
507
715
|
}
|
|
508
|
-
|
|
716
|
+
throw error;
|
|
717
|
+
}
|
|
509
718
|
}
|
|
510
|
-
|
|
719
|
+
await Promise.all(recipients.map((participant) => sendMessageToParticipant({
|
|
720
|
+
room,
|
|
721
|
+
participant,
|
|
722
|
+
path,
|
|
723
|
+
message,
|
|
724
|
+
messageType,
|
|
725
|
+
useAgentMessages,
|
|
726
|
+
turnId,
|
|
727
|
+
store: Boolean(normalizedParticipantName) && getParticipantName(participant) === normalizedParticipantName
|
|
728
|
+
})));
|
|
729
|
+
}, [agentName, document, messageType, path, room, turnId, useAgentMessages]);
|
|
511
730
|
(0, import_react.useEffect)(() => {
|
|
512
731
|
if (!document || !initialMessage || initialMessageSentRef.current) {
|
|
513
732
|
return;
|
|
@@ -24,9 +24,9 @@ __export(pane_example_exports, {
|
|
|
24
24
|
module.exports = __toCommonJS(pane_example_exports);
|
|
25
25
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
26
26
|
var import_react = require("react");
|
|
27
|
-
var import_button = require("
|
|
28
|
-
var import_sheet = require("
|
|
29
|
-
var import_pane_service = require("
|
|
27
|
+
var import_button = require("./ui/button");
|
|
28
|
+
var import_sheet = require("./ui/sheet");
|
|
29
|
+
var import_pane_service = require("../lib/pane-service");
|
|
30
30
|
function PaneExample() {
|
|
31
31
|
const [open, setOpen] = (0, import_react.useState)(false);
|
|
32
32
|
(0, import_react.useEffect)(() => {
|
package/dist/cjs/index.d.ts
CHANGED
package/dist/cjs/index.js
CHANGED
|
@@ -25,3 +25,4 @@ __reExport(index_exports, require("./chat-message"), module.exports);
|
|
|
25
25
|
__reExport(index_exports, require("./conversation-descriptor"), module.exports);
|
|
26
26
|
__reExport(index_exports, require("./file-attachment"), module.exports);
|
|
27
27
|
__reExport(index_exports, require("./multi-thread-view"), module.exports);
|
|
28
|
+
__reExport(index_exports, require("./chat-hooks"), module.exports);
|
|
@@ -39,8 +39,8 @@ function MultiThreadView({
|
|
|
39
39
|
onSelectedThreadResolved,
|
|
40
40
|
newThreadResetVersion = 0,
|
|
41
41
|
centerComposer = true,
|
|
42
|
-
emptyStateTitle,
|
|
43
|
-
emptyStateDescription
|
|
42
|
+
emptyStateTitle = "Start a new thread",
|
|
43
|
+
emptyStateDescription = "Connect with this agent and your team"
|
|
44
44
|
}) {
|
|
45
45
|
const controlledSelectedThreadPath = selectedThreadPath !== void 0 ? normalizeSelectedThreadPath(selectedThreadPath) : void 0;
|
|
46
46
|
const [internalSelectedThreadPath, setInternalSelectedThreadPath] = (0, import_react.useState)(() => controlledSelectedThreadPath ?? null);
|
|
@@ -72,8 +72,6 @@ function MultiThreadView({
|
|
|
72
72
|
toolkit,
|
|
73
73
|
tool,
|
|
74
74
|
centerComposer,
|
|
75
|
-
emptyStateTitle,
|
|
76
|
-
emptyStateDescription,
|
|
77
75
|
onThreadResolved: (path, displayName) => {
|
|
78
76
|
const normalizedPath = normalizeSelectedThreadPath(path);
|
|
79
77
|
if (controlledSelectedThreadPath === void 0) {
|
|
@@ -81,7 +79,9 @@ function MultiThreadView({
|
|
|
81
79
|
}
|
|
82
80
|
onSelectedThreadPathChanged?.(normalizedPath);
|
|
83
81
|
onSelectedThreadResolved?.(normalizedPath, displayName);
|
|
84
|
-
}
|
|
82
|
+
},
|
|
83
|
+
emptyStateTitle,
|
|
84
|
+
emptyStateDescription
|
|
85
85
|
},
|
|
86
86
|
composerKey
|
|
87
87
|
);
|
package/dist/esm/Chat.js
CHANGED
|
@@ -111,8 +111,8 @@ function EmptyState({
|
|
|
111
111
|
title,
|
|
112
112
|
description
|
|
113
113
|
}) {
|
|
114
|
-
return /* @__PURE__ */ jsxs("div", { className: "h-full
|
|
115
|
-
/* @__PURE__ */ jsx("h2", { className: "text-4xl font-
|
|
114
|
+
return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col items-center justify-center px-6 py-20 text-center", children: [
|
|
115
|
+
/* @__PURE__ */ jsx("h2", { className: "text-4xl font-bold tracking-tight text-foreground", children: title }),
|
|
116
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
117
|
] });
|
|
118
118
|
}
|
|
@@ -129,6 +129,9 @@ function ResolvedChatView({
|
|
|
129
129
|
showNewThreadButton = false,
|
|
130
130
|
onStartNewThread
|
|
131
131
|
}) {
|
|
132
|
+
const threadStatus = useThreadStatus({ room, path, agentName });
|
|
133
|
+
const useAgentMessages = threadStatus.supportsAgentMessages;
|
|
134
|
+
const messageType = useAgentMessages && threadStatus.mode === "steerable" && threadStatus.turnId ? "steer" : "chat";
|
|
132
135
|
const {
|
|
133
136
|
document,
|
|
134
137
|
messages,
|
|
@@ -139,9 +142,16 @@ function ResolvedChatView({
|
|
|
139
142
|
onlineParticipants,
|
|
140
143
|
localParticipantName,
|
|
141
144
|
cancelRequest
|
|
142
|
-
} = useChatThread({
|
|
145
|
+
} = useChatThread({
|
|
146
|
+
room,
|
|
147
|
+
path,
|
|
148
|
+
participants,
|
|
149
|
+
agentName,
|
|
150
|
+
useAgentMessages,
|
|
151
|
+
messageType,
|
|
152
|
+
turnId: threadStatus.turnId
|
|
153
|
+
});
|
|
143
154
|
const { typing, thinking } = useRoomIndicators({ room, path });
|
|
144
|
-
const threadStatus = useThreadStatus({ room, path, agentName });
|
|
145
155
|
const [showCompletedToolCalls, setShowCompletedToolCalls] = useState(false);
|
|
146
156
|
const onTextChange = useCallback(() => {
|
|
147
157
|
for (const participant of onlineParticipants) {
|
|
@@ -16,6 +16,8 @@ export interface ChatBotViewProps {
|
|
|
16
16
|
centerComposer?: boolean;
|
|
17
17
|
emptyStateTitle?: string;
|
|
18
18
|
emptyStateDescription?: string;
|
|
19
|
+
startNewThreadTitle?: string;
|
|
20
|
+
startNewThreadDescription?: string;
|
|
19
21
|
selectedThreadPath?: string | null;
|
|
20
22
|
selectedThreadDisplayName?: string | null;
|
|
21
23
|
onSelectedThreadPathChanged?: (path: string | null) => void;
|
|
@@ -26,4 +28,4 @@ export interface ChatBotViewProps {
|
|
|
26
28
|
threadListWidth?: number;
|
|
27
29
|
threadListCollapsedHeight?: number;
|
|
28
30
|
}
|
|
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;
|
|
31
|
+
export declare function ChatBotView({ room, path, documentPath, participants, agentName, threadDisplayMode, threadDir, threadListPath, toolkit, tool, centerComposer, emptyStateTitle, emptyStateDescription, startNewThreadTitle, startNewThreadDescription, selectedThreadPath, onSelectedThreadPathChanged, onSelectedThreadResolved, onThreadResolved, newThreadResetVersion, showThreadList, threadListWidth, threadListCollapsedHeight, }: ChatBotViewProps): ReactElement;
|