@meshagent/meshagent-tailwind 0.38.4 → 0.39.1
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 +12 -0
- package/dist/cjs/Chat.js +3 -3
- package/dist/cjs/ChatBotView.js +132 -40
- package/dist/cjs/ChatThread.js +1 -1
- package/dist/cjs/chat-hooks.d.ts +41 -5
- package/dist/cjs/chat-hooks.js +246 -55
- package/dist/esm/Chat.js +3 -3
- package/dist/esm/ChatBotView.js +142 -42
- package/dist/esm/ChatThread.js +1 -1
- package/dist/esm/chat-hooks.d.ts +41 -5
- package/dist/esm/chat-hooks.js +246 -55
- package/dist/index.css +1 -1
- package/package.json +5 -5
package/dist/esm/chat-hooks.d.ts
CHANGED
|
@@ -22,16 +22,52 @@ export interface UseChatThreadResult {
|
|
|
22
22
|
localParticipantName: string;
|
|
23
23
|
cancelRequest?: () => void;
|
|
24
24
|
}
|
|
25
|
-
export
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
export declare class PendingAgentMessage {
|
|
26
|
+
readonly messageId: string;
|
|
27
|
+
readonly messageType: string;
|
|
28
|
+
readonly threadPath: string;
|
|
29
|
+
readonly text: string;
|
|
30
|
+
readonly attachments: string[];
|
|
31
|
+
readonly senderName?: string;
|
|
32
|
+
readonly awaitingAcceptance: boolean;
|
|
33
|
+
readonly awaitingOnline: boolean;
|
|
34
|
+
constructor({ messageId, messageType, threadPath, text, attachments, senderName, awaitingAcceptance, awaitingOnline, }: {
|
|
35
|
+
messageId: string;
|
|
36
|
+
messageType: string;
|
|
37
|
+
threadPath: string;
|
|
38
|
+
text: string;
|
|
39
|
+
attachments: string[];
|
|
40
|
+
senderName?: string;
|
|
41
|
+
awaitingAcceptance?: boolean;
|
|
42
|
+
awaitingOnline?: boolean;
|
|
43
|
+
});
|
|
44
|
+
static fromQueueJson(json: Record<string, unknown>): PendingAgentMessage;
|
|
30
45
|
}
|
|
46
|
+
export declare class ChatThreadStatusState {
|
|
47
|
+
readonly text?: string;
|
|
48
|
+
readonly startedAt?: Date;
|
|
49
|
+
readonly mode?: string;
|
|
50
|
+
readonly turnId?: string;
|
|
51
|
+
readonly pendingMessages: PendingAgentMessage[];
|
|
52
|
+
readonly pendingItemId?: string;
|
|
53
|
+
readonly supportsAgentMessages: boolean;
|
|
54
|
+
constructor({ text, startedAt, mode, turnId, pendingMessages, pendingItemId, supportsAgentMessages, }: {
|
|
55
|
+
text?: string;
|
|
56
|
+
startedAt?: Date;
|
|
57
|
+
mode?: string;
|
|
58
|
+
turnId?: string;
|
|
59
|
+
pendingMessages?: PendingAgentMessage[];
|
|
60
|
+
pendingItemId?: string;
|
|
61
|
+
supportsAgentMessages?: boolean;
|
|
62
|
+
});
|
|
63
|
+
get hasStatus(): boolean;
|
|
64
|
+
}
|
|
65
|
+
export type ThreadStatus = ChatThreadStatusState;
|
|
31
66
|
export interface UseThreadStatusProps {
|
|
32
67
|
room: RoomClient;
|
|
33
68
|
path: string;
|
|
34
69
|
agentName?: string;
|
|
70
|
+
previous?: ChatThreadStatusState;
|
|
35
71
|
}
|
|
36
72
|
export declare function formatThreadStatusText(text: string, startedAt?: Date | null): string;
|
|
37
73
|
export declare function useChatThread({ room, path, participants, participantNames, initialMessage, includeLocalParticipant, agentName, }: UseChatThreadProps): UseChatThreadResult;
|
package/dist/esm/chat-hooks.js
CHANGED
|
@@ -4,6 +4,103 @@ import {
|
|
|
4
4
|
} from "@meshagent/meshagent";
|
|
5
5
|
import { subscribe, useDocumentChanged, useRoomParticipants } from "@meshagent/meshagent-react";
|
|
6
6
|
import { MeshagentFileUpload, fileToAsyncIterable } from "./file-attachment";
|
|
7
|
+
const agentTurnSteerType = "meshagent.agent.turn.steer";
|
|
8
|
+
class PendingAgentMessage {
|
|
9
|
+
messageId;
|
|
10
|
+
messageType;
|
|
11
|
+
threadPath;
|
|
12
|
+
text;
|
|
13
|
+
attachments;
|
|
14
|
+
senderName;
|
|
15
|
+
awaitingAcceptance;
|
|
16
|
+
awaitingOnline;
|
|
17
|
+
constructor({
|
|
18
|
+
messageId,
|
|
19
|
+
messageType,
|
|
20
|
+
threadPath,
|
|
21
|
+
text,
|
|
22
|
+
attachments,
|
|
23
|
+
senderName,
|
|
24
|
+
awaitingAcceptance = false,
|
|
25
|
+
awaitingOnline = false
|
|
26
|
+
}) {
|
|
27
|
+
this.messageId = messageId;
|
|
28
|
+
this.messageType = messageType;
|
|
29
|
+
this.threadPath = threadPath;
|
|
30
|
+
this.text = text;
|
|
31
|
+
this.attachments = attachments;
|
|
32
|
+
this.senderName = senderName;
|
|
33
|
+
this.awaitingAcceptance = awaitingAcceptance;
|
|
34
|
+
this.awaitingOnline = awaitingOnline;
|
|
35
|
+
}
|
|
36
|
+
static fromQueueJson(json) {
|
|
37
|
+
const content = json["content"];
|
|
38
|
+
const textParts = [];
|
|
39
|
+
const attachments = [];
|
|
40
|
+
if (Array.isArray(content)) {
|
|
41
|
+
for (const item of content) {
|
|
42
|
+
if (item == null || typeof item !== "object") {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const obj = item;
|
|
46
|
+
const type = obj["type"];
|
|
47
|
+
if (type === "text") {
|
|
48
|
+
const text = obj["text"];
|
|
49
|
+
if (typeof text === "string" && text.trim().length > 0) {
|
|
50
|
+
textParts.push(text);
|
|
51
|
+
}
|
|
52
|
+
} else if (type === "file") {
|
|
53
|
+
const url = obj["url"];
|
|
54
|
+
if (typeof url === "string" && url.trim().length > 0) {
|
|
55
|
+
attachments.push(url);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const senderName = json["sender_name"];
|
|
61
|
+
const messageType = json["message_type"];
|
|
62
|
+
const messageId = json["message_id"];
|
|
63
|
+
const threadPath = json["thread_id"];
|
|
64
|
+
return new PendingAgentMessage({
|
|
65
|
+
messageId: typeof messageId === "string" ? messageId : crypto.randomUUID(),
|
|
66
|
+
messageType: typeof messageType === "string" ? messageType : agentTurnSteerType,
|
|
67
|
+
threadPath: typeof threadPath === "string" ? threadPath : "",
|
|
68
|
+
text: textParts.join("\n\n"),
|
|
69
|
+
attachments,
|
|
70
|
+
senderName: typeof senderName === "string" && senderName.trim().length > 0 ? senderName.trim() : void 0,
|
|
71
|
+
awaitingOnline: false
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
class ChatThreadStatusState {
|
|
76
|
+
text;
|
|
77
|
+
startedAt;
|
|
78
|
+
mode;
|
|
79
|
+
turnId;
|
|
80
|
+
pendingMessages;
|
|
81
|
+
pendingItemId;
|
|
82
|
+
supportsAgentMessages;
|
|
83
|
+
constructor({
|
|
84
|
+
text,
|
|
85
|
+
startedAt,
|
|
86
|
+
mode,
|
|
87
|
+
turnId,
|
|
88
|
+
pendingMessages = [],
|
|
89
|
+
pendingItemId,
|
|
90
|
+
supportsAgentMessages: supportsAgentMessages2 = false
|
|
91
|
+
}) {
|
|
92
|
+
this.text = text;
|
|
93
|
+
this.startedAt = startedAt;
|
|
94
|
+
this.mode = mode;
|
|
95
|
+
this.turnId = turnId;
|
|
96
|
+
this.pendingMessages = pendingMessages;
|
|
97
|
+
this.pendingItemId = pendingItemId;
|
|
98
|
+
this.supportsAgentMessages = supportsAgentMessages2;
|
|
99
|
+
}
|
|
100
|
+
get hasStatus() {
|
|
101
|
+
return this.text != null && this.text.trim().length > 0;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
7
104
|
function getParticipantName(participant) {
|
|
8
105
|
const name = participant.getAttribute("name");
|
|
9
106
|
return typeof name === "string" ? name.trim() : "";
|
|
@@ -86,73 +183,161 @@ function threadStatusAttributeCandidates(path, prefix) {
|
|
|
86
183
|
}
|
|
87
184
|
return [`${prefix}.${path}`, `${prefix}./${path}`];
|
|
88
185
|
}
|
|
89
|
-
function
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
186
|
+
function parsePendingMessagesStatus(participant, path) {
|
|
187
|
+
for (const key of threadStatusAttributeCandidates(
|
|
188
|
+
path,
|
|
189
|
+
"thread.status.pending_messages"
|
|
190
|
+
)) {
|
|
191
|
+
const value = participant.getAttribute(key);
|
|
192
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
const decoded = JSON.parse(value.trim());
|
|
197
|
+
if (decoded != null && typeof decoded === "object" && !Array.isArray(decoded)) {
|
|
198
|
+
return decoded;
|
|
199
|
+
}
|
|
200
|
+
} catch (_) {
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return void 0;
|
|
204
|
+
}
|
|
205
|
+
function resolveThreadStatus({
|
|
206
|
+
room,
|
|
207
|
+
path,
|
|
208
|
+
agentName,
|
|
209
|
+
previous
|
|
210
|
+
}) {
|
|
211
|
+
const keyCandidates = threadStatusAttributeCandidates(path, "thread.status");
|
|
212
|
+
const textKeyCandidates = threadStatusAttributeCandidates(path, "thread.status.text");
|
|
213
|
+
const modeKeyCandidates = threadStatusAttributeCandidates(path, "thread.status.mode");
|
|
214
|
+
const startedAtKeyCandidates = threadStatusAttributeCandidates(path, "thread.status.started_at");
|
|
215
|
+
const pendingItemIdKeyCandidates = threadStatusAttributeCandidates(path, "thread.status.pending_item_id");
|
|
216
|
+
const candidates = agentName != null ? room.messaging.remoteParticipants.filter(
|
|
217
|
+
(participant) => participant.getAttribute("name") === agentName
|
|
218
|
+
) : room.messaging.remoteParticipants.filter(
|
|
219
|
+
(participant) => participant.role === "agent" || supportsAgentMessages(participant)
|
|
220
|
+
);
|
|
221
|
+
let nextStatus;
|
|
222
|
+
let nextMode;
|
|
223
|
+
let nextStartedAt;
|
|
224
|
+
let nextTurnId;
|
|
225
|
+
let nextPendingMessages = [];
|
|
226
|
+
let nextPendingItemId;
|
|
227
|
+
let nextSupportsAgentMessages = false;
|
|
101
228
|
for (const participant of candidates) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
229
|
+
if (supportsAgentMessages(participant)) {
|
|
230
|
+
nextSupportsAgentMessages = true;
|
|
231
|
+
}
|
|
232
|
+
if (nextStatus == null) {
|
|
233
|
+
for (const key of textKeyCandidates) {
|
|
105
234
|
const value = participant.getAttribute(key);
|
|
106
|
-
if (typeof value === "string" && value.trim()
|
|
107
|
-
|
|
235
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
236
|
+
nextStatus = value.trim();
|
|
108
237
|
break;
|
|
109
238
|
}
|
|
110
239
|
}
|
|
111
240
|
}
|
|
112
|
-
if (
|
|
113
|
-
for (const key of
|
|
241
|
+
if (nextStatus == null) {
|
|
242
|
+
for (const key of keyCandidates) {
|
|
114
243
|
const value = participant.getAttribute(key);
|
|
115
|
-
if (typeof value
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
const normalized = value.trim().toLowerCase();
|
|
119
|
-
if (normalized === "busy" || normalized === "steerable") {
|
|
120
|
-
mode = normalized;
|
|
244
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
245
|
+
nextStatus = value.trim();
|
|
121
246
|
break;
|
|
122
247
|
}
|
|
123
248
|
}
|
|
124
249
|
}
|
|
125
|
-
|
|
126
|
-
|
|
250
|
+
const pendingStatus = parsePendingMessagesStatus(participant, path);
|
|
251
|
+
if (pendingStatus != null && typeof pendingStatus === "object") {
|
|
252
|
+
if (nextTurnId == null) {
|
|
253
|
+
const turnId = pendingStatus["turn_id"];
|
|
254
|
+
if (typeof turnId === "string" && turnId.trim().length > 0) {
|
|
255
|
+
nextTurnId = turnId.trim();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (nextPendingMessages.length === 0) {
|
|
259
|
+
const messages = pendingStatus["messages"];
|
|
260
|
+
if (Array.isArray(messages)) {
|
|
261
|
+
nextPendingMessages = messages.flatMap((item) => {
|
|
262
|
+
if (item != null && typeof item === "object") {
|
|
263
|
+
return [
|
|
264
|
+
PendingAgentMessage.fromQueueJson(
|
|
265
|
+
item
|
|
266
|
+
)
|
|
267
|
+
];
|
|
268
|
+
}
|
|
269
|
+
return [];
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (nextMode == null) {
|
|
275
|
+
for (const key of modeKeyCandidates) {
|
|
276
|
+
const value = participant.getAttribute(key);
|
|
277
|
+
if (typeof value === "string") {
|
|
278
|
+
const normalized = value.trim().toLowerCase();
|
|
279
|
+
if (normalized === "busy" || normalized === "steerable") {
|
|
280
|
+
nextMode = normalized;
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (nextStartedAt == null) {
|
|
287
|
+
for (const key of startedAtKeyCandidates) {
|
|
127
288
|
const value = participant.getAttribute(key);
|
|
128
|
-
if (typeof value !== "string"
|
|
289
|
+
if (typeof value !== "string") {
|
|
129
290
|
continue;
|
|
130
291
|
}
|
|
131
|
-
const
|
|
292
|
+
const normalized = value.trim();
|
|
293
|
+
if (normalized.length === 0) {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
const parsed = new Date(normalized);
|
|
132
297
|
if (!Number.isNaN(parsed.getTime())) {
|
|
133
|
-
|
|
298
|
+
nextStartedAt = parsed;
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (nextPendingItemId == null) {
|
|
304
|
+
for (const key of pendingItemIdKeyCandidates) {
|
|
305
|
+
const value = participant.getAttribute(key);
|
|
306
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
307
|
+
nextPendingItemId = value.trim();
|
|
134
308
|
break;
|
|
135
309
|
}
|
|
136
310
|
}
|
|
137
311
|
}
|
|
312
|
+
if (nextStatus != null && nextMode != null && nextStartedAt != null && nextTurnId != null && nextPendingItemId != null) {
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
138
315
|
}
|
|
139
|
-
if (
|
|
140
|
-
return {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
startedAt: null,
|
|
144
|
-
supportsAgentMessages: hasAgentMessageSupport
|
|
145
|
-
};
|
|
316
|
+
if (nextStatus == null) {
|
|
317
|
+
return new ChatThreadStatusState({
|
|
318
|
+
supportsAgentMessages: nextSupportsAgentMessages
|
|
319
|
+
});
|
|
146
320
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
321
|
+
nextMode ??= "busy";
|
|
322
|
+
nextStartedAt ??= previous?.hasStatus === true ? previous.startedAt : /* @__PURE__ */ new Date();
|
|
323
|
+
return new ChatThreadStatusState({
|
|
324
|
+
text: nextStatus,
|
|
325
|
+
startedAt: nextStartedAt,
|
|
326
|
+
mode: nextMode,
|
|
327
|
+
turnId: nextTurnId,
|
|
328
|
+
pendingMessages: nextPendingMessages,
|
|
329
|
+
pendingItemId: nextPendingItemId,
|
|
330
|
+
supportsAgentMessages: nextSupportsAgentMessages
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
function pendingMessagesEqual(left, right) {
|
|
334
|
+
return left.length === right.length && left.every((message, index) => {
|
|
335
|
+
const other = right[index];
|
|
336
|
+
return message.messageId === other.messageId && message.messageType === other.messageType && message.text === other.text && stringArraysEqual(message.attachments, other.attachments) && message.senderName === other.senderName;
|
|
337
|
+
});
|
|
153
338
|
}
|
|
154
339
|
function threadStatusEquals(left, right) {
|
|
155
|
-
return left.text === right.text && left.mode === right.mode && left.startedAt?.getTime() === right.startedAt?.getTime() && left.supportsAgentMessages === right.supportsAgentMessages;
|
|
340
|
+
return left.text === right.text && left.mode === right.mode && left.startedAt?.getTime() === right.startedAt?.getTime() && left.turnId === right.turnId && left.pendingItemId === right.pendingItemId && pendingMessagesEqual(left.pendingMessages, right.pendingMessages) && left.supportsAgentMessages === right.supportsAgentMessages;
|
|
156
341
|
}
|
|
157
342
|
function formatThreadStatusText(text, startedAt) {
|
|
158
343
|
if (!(startedAt instanceof Date) || Number.isNaN(startedAt.getTime())) {
|
|
@@ -337,8 +522,15 @@ function useThreadStatus({ room, path, agentName }) {
|
|
|
337
522
|
const [status, setStatus] = useState(() => resolveThreadStatus({ room, path, agentName }));
|
|
338
523
|
useEffect(() => {
|
|
339
524
|
const updateStatus = () => {
|
|
340
|
-
|
|
341
|
-
|
|
525
|
+
setStatus((currentStatus) => {
|
|
526
|
+
const nextStatus = resolveThreadStatus({
|
|
527
|
+
room,
|
|
528
|
+
path,
|
|
529
|
+
agentName,
|
|
530
|
+
previous: currentStatus
|
|
531
|
+
});
|
|
532
|
+
return threadStatusEquals(currentStatus, nextStatus) ? currentStatus : nextStatus;
|
|
533
|
+
});
|
|
342
534
|
};
|
|
343
535
|
const roomSubscription = subscribe(room.listen(), {
|
|
344
536
|
next: (event) => {
|
|
@@ -349,23 +541,22 @@ function useThreadStatus({ room, path, agentName }) {
|
|
|
349
541
|
updateStatus();
|
|
350
542
|
}
|
|
351
543
|
});
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
room.messaging.on("participant_added", handleParticipantsChanged);
|
|
356
|
-
room.messaging.on("participant_removed", handleParticipantsChanged);
|
|
357
|
-
room.messaging.on("messaging_enabled", handleParticipantsChanged);
|
|
544
|
+
room.messaging.on("participant_added", updateStatus);
|
|
545
|
+
room.messaging.on("participant_removed", updateStatus);
|
|
546
|
+
room.messaging.on("messaging_enabled", updateStatus);
|
|
358
547
|
updateStatus();
|
|
359
548
|
return () => {
|
|
360
549
|
roomSubscription.unsubscribe();
|
|
361
|
-
room.messaging.off("participant_added",
|
|
362
|
-
room.messaging.off("participant_removed",
|
|
363
|
-
room.messaging.off("messaging_enabled",
|
|
550
|
+
room.messaging.off("participant_added", updateStatus);
|
|
551
|
+
room.messaging.off("participant_removed", updateStatus);
|
|
552
|
+
room.messaging.off("messaging_enabled", updateStatus);
|
|
364
553
|
};
|
|
365
554
|
}, [agentName, path, room]);
|
|
366
555
|
return status;
|
|
367
556
|
}
|
|
368
557
|
export {
|
|
558
|
+
ChatThreadStatusState,
|
|
559
|
+
PendingAgentMessage,
|
|
369
560
|
formatThreadStatusText,
|
|
370
561
|
useChatThread,
|
|
371
562
|
useThreadStatus
|