@yumiai/chat-widget 0.1.0 → 0.1.2
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 +14 -0
- package/README.md +187 -0
- package/dist/index.cjs +54 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +55 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -139,6 +139,8 @@ interface Round {
|
|
|
139
139
|
plan?: TaskPlan;
|
|
140
140
|
messages: AggregatedMessage[];
|
|
141
141
|
topPosition?: number;
|
|
142
|
+
/** 本轮次内已收到 agent_end 的 agent_instance_id 集合,与 notification_turns 的 agent start/stop 对齐,用于子 Agent 卡片「已完成」判断 */
|
|
143
|
+
endedAgentInstanceIds?: Set<number>;
|
|
142
144
|
}
|
|
143
145
|
type ExecutionStatus = 'idle' | 'running' | 'compressing' | 'completed' | 'error';
|
|
144
146
|
interface ChatWidgetConfig {
|
|
@@ -273,6 +275,10 @@ interface ChildAgentCardProps {
|
|
|
273
275
|
config?: ChatWidgetConfig;
|
|
274
276
|
defaultExpanded?: boolean;
|
|
275
277
|
parentTaskPurpose?: string;
|
|
278
|
+
/** 本轮次已收到 agent_end 的 agent_instance_id(与 notification_turns 对齐),有则优先据此显示「已完成」 */
|
|
279
|
+
endedAgentInstanceIds?: Set<number>;
|
|
280
|
+
/** 本轮次全部消息,用于判断该 agent 是否有未完成的工具(子 agent 的 MCP 消息可能挂在别的 parent 下,不在此卡片的 children 里) */
|
|
281
|
+
allRoundMessages?: AggregatedMessage[];
|
|
276
282
|
}
|
|
277
283
|
interface PlanCardProps {
|
|
278
284
|
plan: TaskPlan;
|
|
@@ -331,6 +337,8 @@ declare function useSSE(options: UseSSEOptions): UseSSEReturn;
|
|
|
331
337
|
interface MessageAggregatorState {
|
|
332
338
|
rounds: Map<string, Round>;
|
|
333
339
|
currentInteractionId: string | null;
|
|
340
|
+
/** 每轮次已收到 agent_end 的 agent_instance_id,与 notification_turns 的 turn_type=agent_end 对齐 */
|
|
341
|
+
endedAgentInstanceIdsByRound: Map<string, Set<number>>;
|
|
334
342
|
}
|
|
335
343
|
interface UseMessageAggregatorReturn {
|
|
336
344
|
state: MessageAggregatorState;
|
package/dist/index.d.ts
CHANGED
|
@@ -139,6 +139,8 @@ interface Round {
|
|
|
139
139
|
plan?: TaskPlan;
|
|
140
140
|
messages: AggregatedMessage[];
|
|
141
141
|
topPosition?: number;
|
|
142
|
+
/** 本轮次内已收到 agent_end 的 agent_instance_id 集合,与 notification_turns 的 agent start/stop 对齐,用于子 Agent 卡片「已完成」判断 */
|
|
143
|
+
endedAgentInstanceIds?: Set<number>;
|
|
142
144
|
}
|
|
143
145
|
type ExecutionStatus = 'idle' | 'running' | 'compressing' | 'completed' | 'error';
|
|
144
146
|
interface ChatWidgetConfig {
|
|
@@ -273,6 +275,10 @@ interface ChildAgentCardProps {
|
|
|
273
275
|
config?: ChatWidgetConfig;
|
|
274
276
|
defaultExpanded?: boolean;
|
|
275
277
|
parentTaskPurpose?: string;
|
|
278
|
+
/** 本轮次已收到 agent_end 的 agent_instance_id(与 notification_turns 对齐),有则优先据此显示「已完成」 */
|
|
279
|
+
endedAgentInstanceIds?: Set<number>;
|
|
280
|
+
/** 本轮次全部消息,用于判断该 agent 是否有未完成的工具(子 agent 的 MCP 消息可能挂在别的 parent 下,不在此卡片的 children 里) */
|
|
281
|
+
allRoundMessages?: AggregatedMessage[];
|
|
276
282
|
}
|
|
277
283
|
interface PlanCardProps {
|
|
278
284
|
plan: TaskPlan;
|
|
@@ -331,6 +337,8 @@ declare function useSSE(options: UseSSEOptions): UseSSEReturn;
|
|
|
331
337
|
interface MessageAggregatorState {
|
|
332
338
|
rounds: Map<string, Round>;
|
|
333
339
|
currentInteractionId: string | null;
|
|
340
|
+
/** 每轮次已收到 agent_end 的 agent_instance_id,与 notification_turns 的 turn_type=agent_end 对齐 */
|
|
341
|
+
endedAgentInstanceIdsByRound: Map<string, Set<number>>;
|
|
334
342
|
}
|
|
335
343
|
interface UseMessageAggregatorReturn {
|
|
336
344
|
state: MessageAggregatorState;
|
package/dist/index.js
CHANGED
|
@@ -55,7 +55,8 @@ function extractTaskPurposeFromPreview(preview) {
|
|
|
55
55
|
function useMessageAggregator() {
|
|
56
56
|
const [state, setState] = useState({
|
|
57
57
|
rounds: /* @__PURE__ */ new Map(),
|
|
58
|
-
currentInteractionId: null
|
|
58
|
+
currentInteractionId: null,
|
|
59
|
+
endedAgentInstanceIdsByRound: /* @__PURE__ */ new Map()
|
|
59
60
|
});
|
|
60
61
|
const [todoMap, setTodoMap] = useState(/* @__PURE__ */ new Map());
|
|
61
62
|
const todoMapRef = useRef(/* @__PURE__ */ new Map());
|
|
@@ -65,6 +66,7 @@ function useMessageAggregator() {
|
|
|
65
66
|
const roundIndexRef = useRef(/* @__PURE__ */ new Map());
|
|
66
67
|
const processedChunksRef = useRef(/* @__PURE__ */ new Set());
|
|
67
68
|
const callBatchToRoundRef = useRef(/* @__PURE__ */ new Map());
|
|
69
|
+
const endedAgentInstanceIdsByRoundRef = useRef(/* @__PURE__ */ new Map());
|
|
68
70
|
const parsePlan = useCallback((content) => {
|
|
69
71
|
try {
|
|
70
72
|
const parsed = JSON.parse(content);
|
|
@@ -206,6 +208,18 @@ function useMessageAggregator() {
|
|
|
206
208
|
} else if (!existingRoundForBatch) {
|
|
207
209
|
callBatchToRoundRef.current.set(call_batch_id, interaction_id);
|
|
208
210
|
}
|
|
211
|
+
if (msg.notification_type === "agent_end") {
|
|
212
|
+
const iid = interaction_id;
|
|
213
|
+
const aid = msg.agent_instance_id;
|
|
214
|
+
if (iid != null && aid != null) {
|
|
215
|
+
const prev = endedAgentInstanceIdsByRoundRef.current;
|
|
216
|
+
const set = new Set(prev.get(iid) || []);
|
|
217
|
+
set.add(aid);
|
|
218
|
+
endedAgentInstanceIdsByRoundRef.current = new Map(prev).set(iid, set);
|
|
219
|
+
}
|
|
220
|
+
latestInteractionId = interaction_id;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
209
223
|
let round = roundIndexRef.current.get(interaction_id);
|
|
210
224
|
if (!round) {
|
|
211
225
|
round = {
|
|
@@ -353,9 +367,14 @@ function useMessageAggregator() {
|
|
|
353
367
|
}
|
|
354
368
|
setState(() => {
|
|
355
369
|
const newRounds = new Map(roundIndexRef.current);
|
|
370
|
+
const endedByRound = endedAgentInstanceIdsByRoundRef.current;
|
|
371
|
+
const endedAgentInstanceIdsByRound = new Map(
|
|
372
|
+
[...endedByRound.entries()].map(([k, v]) => [k, new Set(v)])
|
|
373
|
+
);
|
|
356
374
|
return {
|
|
357
375
|
rounds: newRounds,
|
|
358
|
-
currentInteractionId: latestInteractionId
|
|
376
|
+
currentInteractionId: latestInteractionId,
|
|
377
|
+
endedAgentInstanceIdsByRound
|
|
359
378
|
};
|
|
360
379
|
});
|
|
361
380
|
if (todoMapChanged) {
|
|
@@ -370,8 +389,12 @@ function useMessageAggregator() {
|
|
|
370
389
|
}
|
|
371
390
|
}, [flushUpdates]);
|
|
372
391
|
const getRoundsList = useCallback(() => {
|
|
373
|
-
|
|
374
|
-
|
|
392
|
+
const endedByRound = state.endedAgentInstanceIdsByRound;
|
|
393
|
+
return Array.from(state.rounds.values()).map((r) => ({
|
|
394
|
+
...r,
|
|
395
|
+
endedAgentInstanceIds: endedByRound.get(r.interactionId) || /* @__PURE__ */ new Set()
|
|
396
|
+
})).sort((a, b) => a.index - b.index);
|
|
397
|
+
}, [state.rounds, state.endedAgentInstanceIdsByRound]);
|
|
375
398
|
const getCurrentRound = useCallback(() => {
|
|
376
399
|
if (!state.currentInteractionId) return null;
|
|
377
400
|
return state.rounds.get(state.currentInteractionId) || null;
|
|
@@ -391,7 +414,8 @@ function useMessageAggregator() {
|
|
|
391
414
|
newRounds.set(interactionId, round);
|
|
392
415
|
return {
|
|
393
416
|
rounds: newRounds,
|
|
394
|
-
currentInteractionId: interactionId
|
|
417
|
+
currentInteractionId: interactionId,
|
|
418
|
+
endedAgentInstanceIdsByRound: prevState.endedAgentInstanceIdsByRound
|
|
395
419
|
};
|
|
396
420
|
});
|
|
397
421
|
}, []);
|
|
@@ -400,6 +424,7 @@ function useMessageAggregator() {
|
|
|
400
424
|
messageIndexRef.current.clear();
|
|
401
425
|
callBatchToRoundRef.current.clear();
|
|
402
426
|
processedChunksRef.current.clear();
|
|
427
|
+
endedAgentInstanceIdsByRoundRef.current.clear();
|
|
403
428
|
const newRounds = /* @__PURE__ */ new Map();
|
|
404
429
|
for (const round of rounds) {
|
|
405
430
|
newRounds.set(round.interactionId, round);
|
|
@@ -412,7 +437,7 @@ function useMessageAggregator() {
|
|
|
412
437
|
}
|
|
413
438
|
}
|
|
414
439
|
const lastId = rounds.length > 0 ? rounds[rounds.length - 1].interactionId : null;
|
|
415
|
-
setState({ rounds: newRounds, currentInteractionId: lastId });
|
|
440
|
+
setState({ rounds: newRounds, currentInteractionId: lastId, endedAgentInstanceIdsByRound: /* @__PURE__ */ new Map() });
|
|
416
441
|
}, []);
|
|
417
442
|
const finalizeRound = useCallback((interactionId) => {
|
|
418
443
|
const round = roundIndexRef.current.get(interactionId);
|
|
@@ -428,9 +453,11 @@ function useMessageAggregator() {
|
|
|
428
453
|
}
|
|
429
454
|
}
|
|
430
455
|
if (changed) {
|
|
456
|
+
const endedByRound = endedAgentInstanceIdsByRoundRef.current;
|
|
431
457
|
setState(() => ({
|
|
432
458
|
rounds: new Map(roundIndexRef.current),
|
|
433
|
-
currentInteractionId: interactionId
|
|
459
|
+
currentInteractionId: interactionId,
|
|
460
|
+
endedAgentInstanceIdsByRound: new Map([...endedByRound.entries()].map(([k, v]) => [k, new Set(v)]))
|
|
434
461
|
}));
|
|
435
462
|
}
|
|
436
463
|
}, []);
|
|
@@ -440,6 +467,7 @@ function useMessageAggregator() {
|
|
|
440
467
|
roundIndexRef.current.clear();
|
|
441
468
|
processedChunksRef.current.clear();
|
|
442
469
|
callBatchToRoundRef.current.clear();
|
|
470
|
+
endedAgentInstanceIdsByRoundRef.current.clear();
|
|
443
471
|
todoMapRef.current.clear();
|
|
444
472
|
if (rafId.current) {
|
|
445
473
|
cancelAnimationFrame(rafId.current);
|
|
@@ -447,7 +475,8 @@ function useMessageAggregator() {
|
|
|
447
475
|
}
|
|
448
476
|
setState({
|
|
449
477
|
rounds: /* @__PURE__ */ new Map(),
|
|
450
|
-
currentInteractionId: null
|
|
478
|
+
currentInteractionId: null,
|
|
479
|
+
endedAgentInstanceIdsByRound: /* @__PURE__ */ new Map()
|
|
451
480
|
});
|
|
452
481
|
setTodoMap(/* @__PURE__ */ new Map());
|
|
453
482
|
}, []);
|
|
@@ -2219,7 +2248,7 @@ var ArtifactCard = ({ artifact, onClick }) => {
|
|
|
2219
2248
|
var MessageContent_default = MessageContent;
|
|
2220
2249
|
|
|
2221
2250
|
// src/components/ChildAgentCard.tsx
|
|
2222
|
-
import { useState as useState10, useRef as useRef5, useEffect as useEffect3 } from "react";
|
|
2251
|
+
import { useState as useState10, useRef as useRef5, useEffect as useEffect3, useMemo as useMemo4 } from "react";
|
|
2223
2252
|
import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2224
2253
|
var ChildAgentCard = ({
|
|
2225
2254
|
message,
|
|
@@ -2228,14 +2257,25 @@ var ChildAgentCard = ({
|
|
|
2228
2257
|
config,
|
|
2229
2258
|
onArtifactClick,
|
|
2230
2259
|
defaultExpanded = false,
|
|
2231
|
-
parentTaskPurpose
|
|
2260
|
+
parentTaskPurpose,
|
|
2261
|
+
endedAgentInstanceIds,
|
|
2262
|
+
allRoundMessages
|
|
2232
2263
|
}) => {
|
|
2233
2264
|
const [isExpanded, setIsExpanded] = useState10(defaultExpanded);
|
|
2234
2265
|
const contentRef = useRef5(null);
|
|
2235
|
-
const
|
|
2266
|
+
const allMessages = useMemo4(() => [message, ...children], [message, children]);
|
|
2267
|
+
const hasExplicitEnd = endedAgentInstanceIds != null && endedAgentInstanceIds.has(message.agentInstanceId);
|
|
2268
|
+
const hasActiveContent = allMessages.some(
|
|
2236
2269
|
(m) => m.contentType === "text" && m.contentChunks.join("").trim()
|
|
2237
2270
|
);
|
|
2238
|
-
const
|
|
2271
|
+
const hasInProgressTool = useMemo4(() => {
|
|
2272
|
+
if (allMessages.some((m) => m.toolPhase === "generating" || m.toolPhase === "executing")) return true;
|
|
2273
|
+
if (allRoundMessages == null) return false;
|
|
2274
|
+
return allRoundMessages.some(
|
|
2275
|
+
(m) => m.agentInstanceId === message.agentInstanceId && (m.toolPhase === "generating" || m.toolPhase === "executing")
|
|
2276
|
+
);
|
|
2277
|
+
}, [allMessages, allRoundMessages, message.agentInstanceId]);
|
|
2278
|
+
const status = hasExplicitEnd ? "completed" : hasActiveContent && !hasInProgressTool ? "completed" : "running";
|
|
2239
2279
|
useEffect3(() => {
|
|
2240
2280
|
if (isExpanded && contentRef.current) {
|
|
2241
2281
|
contentRef.current.scrollTop = contentRef.current.scrollHeight;
|
|
@@ -2711,7 +2751,9 @@ var ChatWidget = ({
|
|
|
2711
2751
|
config,
|
|
2712
2752
|
onArtifactClick: handleArtifactClick,
|
|
2713
2753
|
defaultExpanded: true,
|
|
2714
|
-
parentTaskPurpose: msg.taskPurpose
|
|
2754
|
+
parentTaskPurpose: msg.taskPurpose,
|
|
2755
|
+
endedAgentInstanceIds: round.endedAgentInstanceIds,
|
|
2756
|
+
allRoundMessages: round.messages
|
|
2715
2757
|
},
|
|
2716
2758
|
`child-${childKey}-${agentInstanceId}`
|
|
2717
2759
|
)
|