@copilotz/chat-adapter 0.3.9 → 0.4.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/README.md +13 -0
- package/dist/index.js +210 -236
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -107,6 +107,19 @@ Messages stream token-by-token with a thinking indicator while waiting for the f
|
|
|
107
107
|
<CopilotzChat userId="user-123" />
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
+
### Live Stream Contract
|
|
111
|
+
|
|
112
|
+
From `0.4.0` onward, the adapter treats the Copilotz live stream as a lifecycle-native contract:
|
|
113
|
+
|
|
114
|
+
- `TOKEN` streams partial assistant text and reasoning
|
|
115
|
+
- `TOOL_CALL` starts or updates the tool execution UI
|
|
116
|
+
- `TOOL_RESULT` completes the tool execution UI
|
|
117
|
+
- `LLM_RESULT` finalizes the active assistant turn
|
|
118
|
+
- `ASSET_CREATED` remains an optional live artifact event
|
|
119
|
+
- `NEW_MESSAGE` is treated as a history/artifact event, not the primary live completion signal
|
|
120
|
+
|
|
121
|
+
If you stream Copilotz events through a custom bridge, keep those event names intact.
|
|
122
|
+
|
|
110
123
|
### Tool Calls with Live Status
|
|
111
124
|
|
|
112
125
|
When your agent calls tools, the UI shows real-time status updates:
|
package/dist/index.js
CHANGED
|
@@ -337,6 +337,8 @@ async function runCopilotzStream(options) {
|
|
|
337
337
|
const threadName = mergedThreadMetadata.name ?? null;
|
|
338
338
|
const { name: _threadName, ...restThreadMetadata } = mergedThreadMetadata;
|
|
339
339
|
const resolvedParticipants = Array.isArray(participants) && participants.length > 0 ? participants : [selectedAgent || "assistant"];
|
|
340
|
+
const resolvedTarget = targetAgent?.trim() || null;
|
|
341
|
+
const toolCallSenderId = selectedAgent || resolvedParticipants[0] || "assistant";
|
|
340
342
|
const threadPayload = threadId || threadExternalId || threadName || Object.keys(restThreadMetadata).length > 0 ? {
|
|
341
343
|
id: threadId ?? null,
|
|
342
344
|
externalId: threadExternalId ?? null,
|
|
@@ -379,14 +381,13 @@ async function runCopilotzStream(options) {
|
|
|
379
381
|
if (parts.length === 1 && parts[0].type === "text") return parts[0].text;
|
|
380
382
|
return parts;
|
|
381
383
|
})();
|
|
382
|
-
const resolvedTarget = targetAgent?.trim() || null;
|
|
383
384
|
const payload = {
|
|
384
385
|
content: contentParts,
|
|
385
386
|
sender: {
|
|
386
387
|
type: normalizedToolCalls.length > 0 ? "agent" : "user",
|
|
387
|
-
externalId: user.externalId,
|
|
388
|
-
id: normalizedToolCalls.length > 0 ?
|
|
389
|
-
name: normalizedToolCalls.length > 0 ?
|
|
388
|
+
externalId: normalizedToolCalls.length > 0 ? toolCallSenderId : user.externalId,
|
|
389
|
+
id: normalizedToolCalls.length > 0 ? toolCallSenderId : void 0,
|
|
390
|
+
name: normalizedToolCalls.length > 0 ? toolCallSenderId : user.name ?? null,
|
|
390
391
|
metadata: Object.keys(senderMetadata).length > 0 ? senderMetadata : null
|
|
391
392
|
},
|
|
392
393
|
metadata: messageMetadata ?? null,
|
|
@@ -475,15 +476,11 @@ async function runCopilotzStream(options) {
|
|
|
475
476
|
}
|
|
476
477
|
break;
|
|
477
478
|
}
|
|
478
|
-
case "
|
|
479
|
+
case "NEW_MESSAGE": {
|
|
479
480
|
hadNonReasoningContent = true;
|
|
480
481
|
lastTokenWasReasoning = false;
|
|
481
482
|
collectedMessages.push(payload2);
|
|
482
483
|
onMessageEvent?.(payload2);
|
|
483
|
-
const senderType = payload2?.payload?.senderType ?? payload2?.payload?.sender?.type;
|
|
484
|
-
if (senderType === "agent" && typeof payload2?.payload?.content === "string") {
|
|
485
|
-
aggregatedText = payload2.payload.content;
|
|
486
|
-
}
|
|
487
484
|
break;
|
|
488
485
|
}
|
|
489
486
|
case "TOOL_CALL": {
|
|
@@ -492,6 +489,13 @@ async function runCopilotzStream(options) {
|
|
|
492
489
|
onMessageEvent?.(payload2);
|
|
493
490
|
break;
|
|
494
491
|
}
|
|
492
|
+
case "TOOL_RESULT":
|
|
493
|
+
case "LLM_RESULT": {
|
|
494
|
+
hadNonReasoningContent = true;
|
|
495
|
+
lastTokenWasReasoning = false;
|
|
496
|
+
onMessageEvent?.(payload2);
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
495
499
|
case "ASSET_CREATED": {
|
|
496
500
|
const assetPayload = payload2 && typeof payload2 === "object" && "payload" in payload2 ? payload2.payload : payload2;
|
|
497
501
|
if (assetPayload?.dataUrl) {
|
|
@@ -504,8 +508,15 @@ async function runCopilotzStream(options) {
|
|
|
504
508
|
}
|
|
505
509
|
case "ERROR":
|
|
506
510
|
throw new Error(payload2?.error || "Copilotz stream error");
|
|
507
|
-
default:
|
|
508
|
-
|
|
511
|
+
default: {
|
|
512
|
+
const hasEnvelope = payload2 && typeof payload2 === "object" && "type" in payload2;
|
|
513
|
+
if (hasEnvelope) {
|
|
514
|
+
onMessageEvent?.(payload2);
|
|
515
|
+
} else {
|
|
516
|
+
onMessageEvent?.({ type: eventType, payload: payload2 });
|
|
517
|
+
}
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
509
520
|
}
|
|
510
521
|
};
|
|
511
522
|
while (true) {
|
|
@@ -661,7 +672,8 @@ async function getAssetDataUrl(refOrId) {
|
|
|
661
672
|
const text = await res.text().catch(() => res.statusText);
|
|
662
673
|
throw new Error(text || `Failed to fetch asset ${refOrId}`);
|
|
663
674
|
}
|
|
664
|
-
const
|
|
675
|
+
const body = await res.json();
|
|
676
|
+
const data = body?.data ?? body;
|
|
665
677
|
if (!data?.dataUrl) {
|
|
666
678
|
throw new Error(data?.error || `Asset ${refOrId} has no dataUrl`);
|
|
667
679
|
}
|
|
@@ -858,6 +870,67 @@ var parseToolArguments = (value) => {
|
|
|
858
870
|
}
|
|
859
871
|
return {};
|
|
860
872
|
};
|
|
873
|
+
var matchesToolResultUpdate = (target, update) => {
|
|
874
|
+
if (update.id && target.id) {
|
|
875
|
+
return update.id === target.id;
|
|
876
|
+
}
|
|
877
|
+
return Boolean(update.name && target.name && update.name === target.name);
|
|
878
|
+
};
|
|
879
|
+
var findMatchingToolCallIndex = (toolCalls, update) => toolCalls.findIndex((toolCall) => matchesToolResultUpdate(
|
|
880
|
+
{ id: toolCall.id, name: toolCall.name },
|
|
881
|
+
update
|
|
882
|
+
) && (toolCall.status === "pending" || toolCall.status === "running" || typeof toolCall.result === "undefined"));
|
|
883
|
+
var applyToolResultUpdateToMessages = (messages, update, assistantPatch) => {
|
|
884
|
+
const nextMessages = [...messages];
|
|
885
|
+
for (let i = nextMessages.length - 1; i >= 0; i--) {
|
|
886
|
+
const message = nextMessages[i];
|
|
887
|
+
if (message.role !== "assistant" || !Array.isArray(message.toolCalls) || message.toolCalls.length === 0) {
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
const toolCallIndex = findMatchingToolCallIndex(message.toolCalls, update);
|
|
891
|
+
if (toolCallIndex === -1) continue;
|
|
892
|
+
const updatedToolCalls = [...message.toolCalls];
|
|
893
|
+
const current = updatedToolCalls[toolCallIndex];
|
|
894
|
+
updatedToolCalls[toolCallIndex] = {
|
|
895
|
+
...current,
|
|
896
|
+
status: update.status,
|
|
897
|
+
...update.result !== void 0 ? { result: update.result } : {},
|
|
898
|
+
endTime: update.endTime
|
|
899
|
+
};
|
|
900
|
+
nextMessages[i] = {
|
|
901
|
+
...message,
|
|
902
|
+
toolCalls: updatedToolCalls,
|
|
903
|
+
...assistantPatch ?? {}
|
|
904
|
+
};
|
|
905
|
+
return { messages: nextMessages, matched: true };
|
|
906
|
+
}
|
|
907
|
+
return { messages, matched: false };
|
|
908
|
+
};
|
|
909
|
+
var extractLiveToolCall = (payload) => {
|
|
910
|
+
const toolCall = payload?.toolCall;
|
|
911
|
+
if (!toolCall) return null;
|
|
912
|
+
const tool = toolCall.tool;
|
|
913
|
+
const name = typeof tool?.name === "string" ? tool.name : typeof tool?.id === "string" ? tool.id : "tool";
|
|
914
|
+
const result = toolCall.output !== void 0 ? toolCall.output : void 0;
|
|
915
|
+
return {
|
|
916
|
+
...typeof toolCall.id === "string" ? { id: toolCall.id } : {},
|
|
917
|
+
name,
|
|
918
|
+
arguments: parseToolArguments(toolCall.args),
|
|
919
|
+
status: normalizeToolStatus(toolCall.status ?? payload?.status ?? "running"),
|
|
920
|
+
...result !== void 0 ? { result } : {}
|
|
921
|
+
};
|
|
922
|
+
};
|
|
923
|
+
var extractLiveToolResultUpdate = (payload) => {
|
|
924
|
+
const tool = payload?.tool;
|
|
925
|
+
const result = payload?.projectedOutput !== void 0 ? payload.projectedOutput : payload?.output !== void 0 ? payload.output : payload?.content;
|
|
926
|
+
return {
|
|
927
|
+
...typeof payload?.toolCallId === "string" ? { id: payload.toolCallId } : {},
|
|
928
|
+
...typeof tool?.name === "string" ? { name: tool.name } : typeof tool?.id === "string" ? { name: tool.id } : {},
|
|
929
|
+
status: normalizeToolStatus(payload?.status),
|
|
930
|
+
...result !== void 0 ? { result } : {},
|
|
931
|
+
endTime: nowTs()
|
|
932
|
+
};
|
|
933
|
+
};
|
|
861
934
|
var extractToolCallsFromServerMessage = (msg) => {
|
|
862
935
|
const metadata = msg.metadata ?? void 0;
|
|
863
936
|
const topLevelToolCalls = Array.isArray(msg.toolCalls) ? msg.toolCalls || [] : [];
|
|
@@ -924,33 +997,9 @@ var extractToolResultUpdateFromMessage = (msg) => {
|
|
|
924
997
|
};
|
|
925
998
|
var mergePersistedToolResults = (messages, updates) => {
|
|
926
999
|
if (updates.length === 0) return messages;
|
|
927
|
-
|
|
1000
|
+
let nextMessages = messages;
|
|
928
1001
|
for (const update of updates) {
|
|
929
|
-
|
|
930
|
-
const message = nextMessages[i];
|
|
931
|
-
if (message.role !== "assistant" || !Array.isArray(message.toolCalls) || message.toolCalls.length === 0) {
|
|
932
|
-
continue;
|
|
933
|
-
}
|
|
934
|
-
const toolCalls = message.toolCalls;
|
|
935
|
-
let toolCallIndex = update.id ? toolCalls.findIndex((toolCall) => toolCall.id === update.id) : -1;
|
|
936
|
-
if (toolCallIndex === -1 && update.name) {
|
|
937
|
-
toolCallIndex = toolCalls.findIndex((toolCall) => toolCall.name === update.name && (toolCall.status === "pending" || toolCall.status === "running" || typeof toolCall.result === "undefined"));
|
|
938
|
-
}
|
|
939
|
-
if (toolCallIndex === -1) continue;
|
|
940
|
-
const updatedToolCalls = [...toolCalls];
|
|
941
|
-
const current = updatedToolCalls[toolCallIndex];
|
|
942
|
-
updatedToolCalls[toolCallIndex] = {
|
|
943
|
-
...current,
|
|
944
|
-
status: update.status,
|
|
945
|
-
...update.result !== void 0 ? { result: update.result } : {},
|
|
946
|
-
endTime: update.endTime
|
|
947
|
-
};
|
|
948
|
-
nextMessages[i] = {
|
|
949
|
-
...message,
|
|
950
|
-
toolCalls: updatedToolCalls
|
|
951
|
-
};
|
|
952
|
-
break;
|
|
953
|
-
}
|
|
1002
|
+
nextMessages = applyToolResultUpdateToMessages(nextMessages, update).messages;
|
|
954
1003
|
}
|
|
955
1004
|
return nextMessages;
|
|
956
1005
|
};
|
|
@@ -1070,6 +1119,7 @@ function useCopilotz({
|
|
|
1070
1119
|
const messagePageInfoRef = useRef2(messagePageInfo);
|
|
1071
1120
|
const isLoadingOlderMessagesRef = useRef2(isLoadingOlderMessages);
|
|
1072
1121
|
const persistedToolUpdatesRef = useRef2([]);
|
|
1122
|
+
const liveToolUpdatesRef = useRef2([]);
|
|
1073
1123
|
threadsRef.current = threads;
|
|
1074
1124
|
threadMetadataMapRef.current = threadMetadataMap;
|
|
1075
1125
|
threadExternalIdMapRef.current = threadExternalIdMap;
|
|
@@ -1133,87 +1183,46 @@ function useCopilotz({
|
|
|
1133
1183
|
return;
|
|
1134
1184
|
}
|
|
1135
1185
|
const senderType = getEventSenderType(payload);
|
|
1136
|
-
if (senderType
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
const
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
const resultObj = metadata?.output;
|
|
1148
|
-
const callId = payload.toolCallId || generateId();
|
|
1149
|
-
setMessages((prev) => {
|
|
1150
|
-
const next = [...prev];
|
|
1151
|
-
for (let i = next.length - 1; i >= 0; i--) {
|
|
1152
|
-
const m = next[i];
|
|
1153
|
-
if (m.role === "assistant") {
|
|
1154
|
-
const existing = Array.isArray(m.toolCalls) ? m.toolCalls : [];
|
|
1155
|
-
next[i] = {
|
|
1156
|
-
...m,
|
|
1157
|
-
toolCalls: [
|
|
1158
|
-
...existing,
|
|
1159
|
-
{
|
|
1160
|
-
id: callId,
|
|
1161
|
-
name: toolName,
|
|
1162
|
-
arguments: argsObj,
|
|
1163
|
-
result: resultObj,
|
|
1164
|
-
status: "completed",
|
|
1165
|
-
endTime: Date.now()
|
|
1166
|
-
}
|
|
1167
|
-
]
|
|
1168
|
-
};
|
|
1169
|
-
break;
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
return next;
|
|
1173
|
-
});
|
|
1174
|
-
return;
|
|
1175
|
-
}
|
|
1176
|
-
if (senderType === "agent" && typeof payload.content === "string") {
|
|
1177
|
-
const agentSenderId = payload.senderId ?? payload.sender?.id ?? payload.sender?.name ?? void 0;
|
|
1178
|
-
const agentSenderName = payload.sender?.name ?? payload.senderId ?? void 0;
|
|
1179
|
-
const incomingAgentKey = agentSenderId ?? agentSenderName ?? null;
|
|
1180
|
-
setMessages((prev) => {
|
|
1181
|
-
const next = [...prev];
|
|
1182
|
-
for (let i = next.length - 1; i >= 0; i--) {
|
|
1183
|
-
const m = next[i];
|
|
1184
|
-
if (m.role === "assistant" && m.isStreaming && (!incomingAgentKey || messageAgentKey(m) === incomingAgentKey)) {
|
|
1185
|
-
next[i] = {
|
|
1186
|
-
...m,
|
|
1187
|
-
content: payload.content,
|
|
1188
|
-
isStreaming: false,
|
|
1189
|
-
isComplete: true,
|
|
1190
|
-
...agentSenderId ? { senderAgentId: agentSenderId } : {},
|
|
1191
|
-
...agentSenderName ? { senderName: agentSenderName } : {}
|
|
1192
|
-
};
|
|
1193
|
-
return next;
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
const trimmedContent = payload.content.trim();
|
|
1197
|
-
if (!trimmedContent) {
|
|
1198
|
-
return prev;
|
|
1199
|
-
}
|
|
1200
|
-
return [
|
|
1201
|
-
...next,
|
|
1202
|
-
{
|
|
1203
|
-
id: generateId(),
|
|
1204
|
-
role: "assistant",
|
|
1186
|
+
if (senderType !== "agent" || typeof payload.content !== "string") return;
|
|
1187
|
+
const agentSenderId = payload.senderId ?? payload.sender?.id ?? payload.sender?.name ?? void 0;
|
|
1188
|
+
const agentSenderName = payload.sender?.name ?? payload.senderId ?? void 0;
|
|
1189
|
+
const incomingAgentKey = agentSenderId ?? agentSenderName ?? null;
|
|
1190
|
+
setMessages((prev) => {
|
|
1191
|
+
const next = [...prev];
|
|
1192
|
+
for (let i = next.length - 1; i >= 0; i--) {
|
|
1193
|
+
const m = next[i];
|
|
1194
|
+
if (m.role === "assistant" && m.isStreaming && (!incomingAgentKey || messageAgentKey(m) === incomingAgentKey)) {
|
|
1195
|
+
next[i] = {
|
|
1196
|
+
...m,
|
|
1205
1197
|
content: payload.content,
|
|
1206
|
-
timestamp: nowTs(),
|
|
1207
1198
|
isStreaming: false,
|
|
1208
1199
|
isComplete: true,
|
|
1209
|
-
metadata: liveMetadata,
|
|
1210
1200
|
...agentSenderId ? { senderAgentId: agentSenderId } : {},
|
|
1211
1201
|
...agentSenderName ? { senderName: agentSenderName } : {}
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1202
|
+
};
|
|
1203
|
+
return next;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
const trimmedContent = payload.content.trim();
|
|
1207
|
+
if (!trimmedContent) {
|
|
1208
|
+
return prev;
|
|
1209
|
+
}
|
|
1210
|
+
return [
|
|
1211
|
+
...next,
|
|
1212
|
+
{
|
|
1213
|
+
id: generateId(),
|
|
1214
|
+
role: "assistant",
|
|
1215
|
+
content: payload.content,
|
|
1216
|
+
timestamp: nowTs(),
|
|
1217
|
+
isStreaming: false,
|
|
1218
|
+
isComplete: true,
|
|
1219
|
+
metadata: liveMetadata,
|
|
1220
|
+
...agentSenderId ? { senderAgentId: agentSenderId } : {},
|
|
1221
|
+
...agentSenderName ? { senderName: agentSenderName } : {}
|
|
1222
|
+
}
|
|
1223
|
+
];
|
|
1224
|
+
});
|
|
1225
|
+
}, []);
|
|
1217
1226
|
const updateThreadsState = useCallback2((rawThreads, preferredExternalId) => {
|
|
1218
1227
|
const metadataMap = {};
|
|
1219
1228
|
const externalMap = {};
|
|
@@ -1302,6 +1311,7 @@ function useCopilotz({
|
|
|
1302
1311
|
setIsLoadingOlderMessages(false);
|
|
1303
1312
|
setMessagePageInfo(createEmptyMessagePageInfo());
|
|
1304
1313
|
persistedToolUpdatesRef.current = [];
|
|
1314
|
+
liveToolUpdatesRef.current = [];
|
|
1305
1315
|
try {
|
|
1306
1316
|
const page = await fetchThreadMessagesPage(
|
|
1307
1317
|
threadId,
|
|
@@ -1597,78 +1607,70 @@ function useCopilotz({
|
|
|
1597
1607
|
});
|
|
1598
1608
|
};
|
|
1599
1609
|
const curThreadId = currentThreadIdRef.current;
|
|
1610
|
+
const applyLiveToolResultUpdate = (update) => {
|
|
1611
|
+
let matched = false;
|
|
1612
|
+
setMessages((prev) => {
|
|
1613
|
+
const next = applyToolResultUpdateToMessages(prev, update, {
|
|
1614
|
+
isStreaming: true,
|
|
1615
|
+
isComplete: false
|
|
1616
|
+
});
|
|
1617
|
+
matched = next.matched;
|
|
1618
|
+
return next.matched ? next.messages : prev;
|
|
1619
|
+
});
|
|
1620
|
+
if (!matched) {
|
|
1621
|
+
liveToolUpdatesRef.current.push(update);
|
|
1622
|
+
}
|
|
1623
|
+
};
|
|
1624
|
+
const finalizeActiveAssistantTurn = (finalAnswer) => {
|
|
1625
|
+
setMessages((prev) => {
|
|
1626
|
+
const currentIdx = prev.findIndex((message2) => message2.id === currentAssistantId && message2.role === "assistant");
|
|
1627
|
+
const fallbackIdx = currentIdx >= 0 ? currentIdx : (() => {
|
|
1628
|
+
for (let i = prev.length - 1; i >= 0; i--) {
|
|
1629
|
+
if (prev[i].role === "assistant" && prev[i].isStreaming) {
|
|
1630
|
+
return i;
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
return -1;
|
|
1634
|
+
})();
|
|
1635
|
+
if (fallbackIdx < 0) return prev;
|
|
1636
|
+
const message = prev[fallbackIdx];
|
|
1637
|
+
const nextMessage = {
|
|
1638
|
+
...message,
|
|
1639
|
+
...typeof finalAnswer === "string" && finalAnswer.length > 0 ? { content: finalAnswer } : {},
|
|
1640
|
+
isStreaming: false,
|
|
1641
|
+
isComplete: true,
|
|
1642
|
+
...message.reasoning ? { isReasoningStreaming: false } : {}
|
|
1643
|
+
};
|
|
1644
|
+
if (message.content === nextMessage.content && message.isStreaming === nextMessage.isStreaming && message.isComplete === nextMessage.isComplete && message.isReasoningStreaming === nextMessage.isReasoningStreaming) {
|
|
1645
|
+
return prev;
|
|
1646
|
+
}
|
|
1647
|
+
const updated = [...prev];
|
|
1648
|
+
updated[fallbackIdx] = nextMessage;
|
|
1649
|
+
currentAssistantId = nextMessage.id;
|
|
1650
|
+
return updated;
|
|
1651
|
+
});
|
|
1652
|
+
};
|
|
1600
1653
|
const toServerMessageFromEvent = async (event) => {
|
|
1601
1654
|
if (!event) return null;
|
|
1602
1655
|
const type = event?.type || "";
|
|
1603
1656
|
const payload = event?.payload ?? event;
|
|
1604
1657
|
if (type === "TOOL_CALL") {
|
|
1605
|
-
const
|
|
1606
|
-
|
|
1607
|
-
const tcTool = tc?.tool ?? void 0;
|
|
1608
|
-
const call = payload?.call ?? metadata?.call;
|
|
1609
|
-
const func = call?.function ?? payload?.function;
|
|
1610
|
-
const toolName = tcTool?.name || func?.name || payload?.name || call?.name || metadata.toolName || metadata.tool || "tool";
|
|
1611
|
-
let argsObj = {};
|
|
1612
|
-
const possibleArgs = [
|
|
1613
|
-
tc?.args,
|
|
1614
|
-
func?.arguments,
|
|
1615
|
-
payload?.args,
|
|
1616
|
-
call?.arguments,
|
|
1617
|
-
metadata?.args,
|
|
1618
|
-
metadata?.arguments
|
|
1619
|
-
];
|
|
1620
|
-
for (const candidate of possibleArgs) {
|
|
1621
|
-
if (candidate === void 0 || candidate === null) continue;
|
|
1622
|
-
try {
|
|
1623
|
-
if (typeof candidate === "string") {
|
|
1624
|
-
argsObj = JSON.parse(candidate);
|
|
1625
|
-
break;
|
|
1626
|
-
}
|
|
1627
|
-
if (typeof candidate === "object") {
|
|
1628
|
-
argsObj = candidate;
|
|
1629
|
-
break;
|
|
1630
|
-
}
|
|
1631
|
-
} catch {
|
|
1632
|
-
}
|
|
1633
|
-
}
|
|
1634
|
-
const output = (tc?.output !== void 0 ? tc.output : void 0) ?? (metadata?.output !== void 0 ? metadata.output : void 0) ?? (payload?.output !== void 0 ? payload.output : void 0);
|
|
1635
|
-
const callId = tc?.id || call?.id || func?.id || payload?.id || generateId();
|
|
1636
|
-
const statusVal = tc?.status || payload?.status || event?.status || "pending";
|
|
1658
|
+
const parsedToolCall = extractLiveToolCall(payload);
|
|
1659
|
+
if (!parsedToolCall) return null;
|
|
1637
1660
|
return {
|
|
1638
1661
|
id: generateId(),
|
|
1639
1662
|
threadId: curThreadId ?? "",
|
|
1640
1663
|
senderType: "tool",
|
|
1641
1664
|
content: "",
|
|
1642
1665
|
toolCalls: [{
|
|
1643
|
-
id:
|
|
1644
|
-
name:
|
|
1645
|
-
args:
|
|
1646
|
-
output,
|
|
1647
|
-
status:
|
|
1666
|
+
id: parsedToolCall.id ?? generateId(),
|
|
1667
|
+
name: parsedToolCall.name,
|
|
1668
|
+
args: parsedToolCall.arguments,
|
|
1669
|
+
...parsedToolCall.result !== void 0 ? { output: parsedToolCall.result } : {},
|
|
1670
|
+
status: parsedToolCall.status
|
|
1648
1671
|
}]
|
|
1649
1672
|
};
|
|
1650
1673
|
}
|
|
1651
|
-
if (type === "MESSAGE" || type === "NEW_MESSAGE") {
|
|
1652
|
-
const senderType = payload?.senderType || payload?.sender?.type;
|
|
1653
|
-
const liveMetadata = event?.metadata && typeof event.metadata === "object" ? event.metadata : payload?.metadata;
|
|
1654
|
-
if (isInternalMessageMetadata(liveMetadata)) {
|
|
1655
|
-
return null;
|
|
1656
|
-
}
|
|
1657
|
-
if (senderType !== "agent") {
|
|
1658
|
-
return null;
|
|
1659
|
-
}
|
|
1660
|
-
const content = typeof payload?.content === "string" ? payload.content : "";
|
|
1661
|
-
if (!content.trim()) {
|
|
1662
|
-
return null;
|
|
1663
|
-
}
|
|
1664
|
-
return {
|
|
1665
|
-
id: generateId(),
|
|
1666
|
-
threadId: curThreadId ?? "",
|
|
1667
|
-
senderType: "agent",
|
|
1668
|
-
content,
|
|
1669
|
-
metadata: liveMetadata ?? {}
|
|
1670
|
-
};
|
|
1671
|
-
}
|
|
1672
1674
|
if (type === "ASSET_CREATED") {
|
|
1673
1675
|
const by = payload?.by || "";
|
|
1674
1676
|
if (by && by !== "tool") return null;
|
|
@@ -1694,6 +1696,7 @@ function useCopilotz({
|
|
|
1694
1696
|
abortControllerRef.current?.abort();
|
|
1695
1697
|
abortControllerRef.current = abortController;
|
|
1696
1698
|
setIsStreaming(true);
|
|
1699
|
+
liveToolUpdatesRef.current = [];
|
|
1697
1700
|
try {
|
|
1698
1701
|
const normalizedUserMetadata = params.userMetadata ? JSON.parse(JSON.stringify(params.userMetadata)) : void 0;
|
|
1699
1702
|
const contextSeed = userContextSeedRef.current;
|
|
@@ -1739,68 +1742,38 @@ function useCopilotz({
|
|
|
1739
1742
|
}
|
|
1740
1743
|
const type = event?.type || "";
|
|
1741
1744
|
const payload = getEventPayload(event);
|
|
1745
|
+
if (type === "TOOL_RESULT") {
|
|
1746
|
+
processToolOutput(payload ?? {});
|
|
1747
|
+
applyLiveToolResultUpdate(extractLiveToolResultUpdate(
|
|
1748
|
+
payload ?? {}
|
|
1749
|
+
));
|
|
1750
|
+
return;
|
|
1751
|
+
}
|
|
1752
|
+
if (type === "LLM_RESULT") {
|
|
1753
|
+
const finalAnswer = typeof payload?.answer === "string" ? payload.answer : void 0;
|
|
1754
|
+
finalizeActiveAssistantTurn(finalAnswer);
|
|
1755
|
+
pendingStartNewAssistantBubble = true;
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1742
1758
|
if (type === "MESSAGE" || type === "NEW_MESSAGE") {
|
|
1743
|
-
const senderType = getEventSenderType(payload);
|
|
1744
|
-
if (senderType === "tool") {
|
|
1745
|
-
const metadata = payload?.metadata ?? {};
|
|
1746
|
-
const toolCallsArray = metadata?.toolCalls;
|
|
1747
|
-
const toolCallData = toolCallsArray && toolCallsArray.length > 0 ? toolCallsArray[0] : void 0;
|
|
1748
|
-
if (!toolCallData) {
|
|
1749
|
-
return;
|
|
1750
|
-
}
|
|
1751
|
-
processToolOutput(metadata);
|
|
1752
|
-
const toolCallId = toolCallData.id;
|
|
1753
|
-
const toolCallName = toolCallData.name;
|
|
1754
|
-
const toolResult = toolCallData.output || payload?.content;
|
|
1755
|
-
const toolStatus = toolCallData.status || "completed";
|
|
1756
|
-
const isFailed = toolStatus === "failed" || toolCallData?.error;
|
|
1757
|
-
setMessages((prev) => {
|
|
1758
|
-
const updated = [...prev];
|
|
1759
|
-
for (let i = updated.length - 1; i >= 0; i--) {
|
|
1760
|
-
if (updated[i].role === "assistant" && updated[i].toolCalls) {
|
|
1761
|
-
const toolCalls = updated[i].toolCalls;
|
|
1762
|
-
if (toolCalls) {
|
|
1763
|
-
let toolCallIndex = toolCallId ? toolCalls.findIndex((tc) => tc.id === toolCallId) : -1;
|
|
1764
|
-
if (toolCallIndex === -1 && toolCallName) {
|
|
1765
|
-
toolCallIndex = toolCalls.findIndex(
|
|
1766
|
-
(tc) => tc.name === toolCallName && (tc.status === "pending" || tc.status === "running")
|
|
1767
|
-
);
|
|
1768
|
-
}
|
|
1769
|
-
if (toolCallIndex !== -1) {
|
|
1770
|
-
const updatedToolCalls = [...toolCalls];
|
|
1771
|
-
updatedToolCalls[toolCallIndex] = {
|
|
1772
|
-
...updatedToolCalls[toolCallIndex],
|
|
1773
|
-
status: isFailed ? "failed" : "completed",
|
|
1774
|
-
result: toolResult,
|
|
1775
|
-
endTime: Date.now()
|
|
1776
|
-
};
|
|
1777
|
-
updated[i] = {
|
|
1778
|
-
...updated[i],
|
|
1779
|
-
toolCalls: updatedToolCalls,
|
|
1780
|
-
isStreaming: true,
|
|
1781
|
-
isComplete: false
|
|
1782
|
-
};
|
|
1783
|
-
break;
|
|
1784
|
-
}
|
|
1785
|
-
}
|
|
1786
|
-
}
|
|
1787
|
-
}
|
|
1788
|
-
return updated;
|
|
1789
|
-
});
|
|
1790
|
-
return;
|
|
1791
|
-
}
|
|
1792
|
-
handleStreamMessageEvent(event);
|
|
1793
|
-
if (senderType === "agent") {
|
|
1794
|
-
currentAssistantId = generateId();
|
|
1795
|
-
pendingStartNewAssistantBubble = true;
|
|
1796
|
-
}
|
|
1797
1759
|
return;
|
|
1798
1760
|
}
|
|
1799
1761
|
if (type === "TOOL_CALL") {
|
|
1800
|
-
const
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
if (!
|
|
1762
|
+
const parsedToolCall = extractLiveToolCall(
|
|
1763
|
+
payload ?? {}
|
|
1764
|
+
);
|
|
1765
|
+
if (!parsedToolCall) return;
|
|
1766
|
+
const callId = parsedToolCall.id ?? generateId();
|
|
1767
|
+
const toolName = parsedToolCall.name;
|
|
1768
|
+
const bufferedUpdates = liveToolUpdatesRef.current;
|
|
1769
|
+
const matchingUpdateIndex = bufferedUpdates.findIndex((upd) => matchesToolResultUpdate({ id: callId, name: toolName }, upd));
|
|
1770
|
+
const bufferedUpdate = matchingUpdateIndex >= 0 ? bufferedUpdates[matchingUpdateIndex] : void 0;
|
|
1771
|
+
if (matchingUpdateIndex >= 0) {
|
|
1772
|
+
bufferedUpdates.splice(matchingUpdateIndex, 1);
|
|
1773
|
+
}
|
|
1774
|
+
const initialStatus = bufferedUpdate ? bufferedUpdate.status : parsedToolCall.status;
|
|
1775
|
+
const initialResult = bufferedUpdate && bufferedUpdate.result !== void 0 ? bufferedUpdate.result : parsedToolCall.result;
|
|
1776
|
+
const endTime = bufferedUpdate?.endTime;
|
|
1804
1777
|
setMessages(
|
|
1805
1778
|
(prev) => (() => {
|
|
1806
1779
|
const appendToolCall = (msg) => ({
|
|
@@ -1808,12 +1781,13 @@ function useCopilotz({
|
|
|
1808
1781
|
toolCalls: [
|
|
1809
1782
|
...Array.isArray(msg.toolCalls) ? msg.toolCalls : [],
|
|
1810
1783
|
{
|
|
1811
|
-
id:
|
|
1812
|
-
name:
|
|
1813
|
-
arguments:
|
|
1814
|
-
result:
|
|
1815
|
-
status:
|
|
1816
|
-
startTime: Date.now()
|
|
1784
|
+
id: callId,
|
|
1785
|
+
name: toolName,
|
|
1786
|
+
arguments: parsedToolCall.arguments,
|
|
1787
|
+
...initialResult !== void 0 ? { result: initialResult } : {},
|
|
1788
|
+
status: initialStatus,
|
|
1789
|
+
startTime: Date.now(),
|
|
1790
|
+
...endTime !== void 0 ? { endTime } : {}
|
|
1817
1791
|
}
|
|
1818
1792
|
]
|
|
1819
1793
|
});
|