@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 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 max-w-2xl 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-semibold tracking-tight text-foreground sm:text-5xl", children: title }),
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)({ room, path, participants, agentName });
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;
@@ -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
  }
@@ -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 = "20px";
60
+ element.style.height = `${MIN_TEXTAREA_HEIGHT}px`;
60
61
  } else {
61
62
  element.style.height = "0px";
62
- element.style.height = `${Math.max(20, Math.min(element.scrollHeight, 160))}px`;
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
- import_textarea.Textarea,
192
+ "textarea",
189
193
  {
190
194
  ref: textareaRef,
191
195
  autoFocus,
192
196
  placeholder,
193
- className: "min-h-5 max-h-40 flex-1 resize-none border-0 bg-transparent p-0 leading-5 shadow-none focus-visible:border-transparent focus-visible:ring-0",
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,
@@ -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
  }
@@ -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;
@@ -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 thread = children.find((child) => child.tagName === "messages");
482
- if (!thread) {
675
+ const messagesElement = children.find((child) => child.tagName === "messages");
676
+ if (!document || !messagesElement) {
483
677
  return;
484
678
  }
485
- const authorName = getParticipantName(room.localParticipant);
486
- const messageElement = thread.createChildElement("message", {
487
- id: message.id,
488
- text: message.text,
489
- created_at: (/* @__PURE__ */ new Date()).toISOString(),
490
- author_name: authorName,
491
- author_ref: null
492
- });
493
- for (const attachmentPath of message.attachments) {
494
- messageElement.createChildElement("file", { path: attachmentPath });
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
- for (const participant of onlineParticipants) {
497
- if (!matchesParticipantName(participant, agentName)) {
498
- continue;
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
- room.messaging.sendMessage({
501
- to: participant,
502
- type: "chat",
503
- message: {
504
- path,
505
- text: message.text,
506
- attachments: message.attachments.map((attachmentPath) => ({ path: attachmentPath }))
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
- }, [agentName, document, onlineParticipants, path, room]);
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("@/components/ui/button");
28
- var import_sheet = require("@/components/ui/sheet");
29
- var import_pane_service = require("@/lib/pane-service");
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)(() => {
@@ -1,3 +1,3 @@
1
- import { ToasterProps } from "sonner";
1
+ import type { ToasterProps } from "sonner";
2
2
  declare const Toaster: ({ ...props }: ToasterProps) => import("react/jsx-runtime").JSX.Element;
3
3
  export { Toaster };
@@ -8,3 +8,4 @@ export * from './chat-message';
8
8
  export * from './conversation-descriptor';
9
9
  export * from './file-attachment';
10
10
  export * from './multi-thread-view';
11
+ export * from './chat-hooks';
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 max-w-2xl flex 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 }),
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({ room, path, participants, agentName });
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;