@copilotz/chat-adapter 0.1.23 → 0.1.24
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/dist/index.d.ts +3 -4
- package/dist/index.js +89 -150
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -130,10 +130,9 @@ type RestMessage = {
|
|
|
130
130
|
updatedAt?: string;
|
|
131
131
|
};
|
|
132
132
|
type StreamCallbacks = {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
onToken?: (text: string, isComplete: boolean, raw?: any, reasoningText?: string) => void;
|
|
133
|
+
onToken?: (token: string, isComplete: boolean, raw?: any, options?: {
|
|
134
|
+
isReasoning?: boolean;
|
|
135
|
+
}) => void;
|
|
137
136
|
onMessageEvent?: (payload: any) => void;
|
|
138
137
|
onAssetEvent?: (payload: any) => void;
|
|
139
138
|
signal?: AbortSignal;
|
package/dist/index.js
CHANGED
|
@@ -431,9 +431,8 @@ async function runCopilotzStream(options) {
|
|
|
431
431
|
switch (eventType) {
|
|
432
432
|
case "TOKEN": {
|
|
433
433
|
const inner = payload2?.payload ?? payload2;
|
|
434
|
-
const chunk = typeof inner?.token === "string" ? inner.token :
|
|
434
|
+
const chunk = typeof inner?.token === "string" ? inner.token : "";
|
|
435
435
|
const isReasoning = Boolean(inner?.isReasoning);
|
|
436
|
-
const isComplete = Boolean(inner?.isComplete ?? payload2?.isComplete);
|
|
437
436
|
if (chunk) {
|
|
438
437
|
if (isReasoning) {
|
|
439
438
|
aggregatedReasoning = appendChunk(aggregatedReasoning, chunk);
|
|
@@ -441,8 +440,10 @@ async function runCopilotzStream(options) {
|
|
|
441
440
|
aggregatedText = appendChunk(aggregatedText, chunk);
|
|
442
441
|
}
|
|
443
442
|
}
|
|
443
|
+
const isComplete = Boolean(inner?.isComplete);
|
|
444
444
|
if (chunk || isComplete) {
|
|
445
|
-
|
|
445
|
+
const tokenText = isReasoning ? aggregatedReasoning : aggregatedText;
|
|
446
|
+
onToken?.(tokenText, isComplete, payload2, { isReasoning });
|
|
446
447
|
}
|
|
447
448
|
break;
|
|
448
449
|
}
|
|
@@ -510,12 +511,11 @@ async function fetchThreads(userId, getRequestHeaders) {
|
|
|
510
511
|
const errorText = await res.text().catch(() => res.statusText);
|
|
511
512
|
throw new Error(errorText || `Failed to load threads (${res.status})`);
|
|
512
513
|
}
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
if (!Array.isArray(list)) {
|
|
514
|
+
const { data } = await res.json();
|
|
515
|
+
if (!Array.isArray(data)) {
|
|
516
516
|
return [];
|
|
517
517
|
}
|
|
518
|
-
return
|
|
518
|
+
return data;
|
|
519
519
|
}
|
|
520
520
|
async function fetchThreadMessages(threadId, getRequestHeaders) {
|
|
521
521
|
const graphParams = new URLSearchParams();
|
|
@@ -555,12 +555,11 @@ async function fetchThreadMessages(threadId, getRequestHeaders) {
|
|
|
555
555
|
const errorText = await res.text().catch(() => res.statusText);
|
|
556
556
|
throw new Error(errorText || `Failed to load thread messages (${res.status})`);
|
|
557
557
|
}
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
if (!Array.isArray(list)) {
|
|
558
|
+
const { data } = await res.json();
|
|
559
|
+
if (!Array.isArray(data)) {
|
|
561
560
|
return [];
|
|
562
561
|
}
|
|
563
|
-
return
|
|
562
|
+
return data;
|
|
564
563
|
}
|
|
565
564
|
async function updateThread(threadId, updates, getRequestHeaders) {
|
|
566
565
|
const res = await fetch(apiUrl(`/v1/rest/threads/${threadId}`), {
|
|
@@ -805,23 +804,6 @@ var generateId = () => globalThis.crypto?.randomUUID?.() ?? `id-${Date.now()}-${
|
|
|
805
804
|
var isAbortError = (error) => error instanceof DOMException && error.name === "AbortError" || typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
|
|
806
805
|
var getEventPayload = (event) => event?.payload ?? event;
|
|
807
806
|
var getEventSenderType = (payload) => payload?.senderType || payload?.sender?.type;
|
|
808
|
-
var hasToolCallsInPayload = (payload) => {
|
|
809
|
-
if (!payload || typeof payload !== "object") return false;
|
|
810
|
-
const p = payload;
|
|
811
|
-
if (Array.isArray(p.toolCalls) && p.toolCalls.length > 0) return true;
|
|
812
|
-
const meta = p.metadata;
|
|
813
|
-
if (!meta || typeof meta !== "object" || Array.isArray(meta)) return false;
|
|
814
|
-
const m = meta.toolCalls;
|
|
815
|
-
return Array.isArray(m) && m.length > 0;
|
|
816
|
-
};
|
|
817
|
-
var isAgentToolOnlyPlaceholderPayload = (payload) => {
|
|
818
|
-
if (!payload || typeof payload !== "object") return false;
|
|
819
|
-
const p = payload;
|
|
820
|
-
if (getEventSenderType(p) !== "agent") return false;
|
|
821
|
-
const content = typeof p.content === "string" ? p.content : "";
|
|
822
|
-
if (content.trim().length > 0) return false;
|
|
823
|
-
return hasToolCallsInPayload(p);
|
|
824
|
-
};
|
|
825
807
|
var hasVisibleAssistantOutput = (message) => {
|
|
826
808
|
if (message.role !== "assistant") return false;
|
|
827
809
|
if (typeof message.content === "string" && message.content.trim().length > 0) return true;
|
|
@@ -856,29 +838,16 @@ var extractToolCallsFromServerMessage = (msg) => {
|
|
|
856
838
|
const metadataToolCalls = Array.isArray(metadata?.toolCalls) ? metadata.toolCalls : [];
|
|
857
839
|
const usedMetadataIndexes = /* @__PURE__ */ new Set();
|
|
858
840
|
const parsed = [];
|
|
859
|
-
const candidateToolLabel = (c) => {
|
|
860
|
-
if (typeof c.name === "string") return c.name;
|
|
861
|
-
const t = c.tool && typeof c.tool === "object" && c.tool !== null && !Array.isArray(c.tool) ? c.tool : void 0;
|
|
862
|
-
if (typeof t?.name === "string") return t.name;
|
|
863
|
-
if (typeof t?.id === "string") return t.id;
|
|
864
|
-
return void 0;
|
|
865
|
-
};
|
|
866
841
|
const findMatchingMetadataIndex = (toolCall) => {
|
|
867
842
|
const id = typeof toolCall.id === "string" ? toolCall.id : void 0;
|
|
868
|
-
const
|
|
869
|
-
const name = (typeof toolCall.name === "string" ? toolCall.name : void 0) || (typeof nested?.name === "string" ? nested.name : void 0) || (typeof nested?.id === "string" ? nested.id : void 0);
|
|
843
|
+
const name = typeof toolCall.name === "string" ? toolCall.name : void 0;
|
|
870
844
|
const byId = id ? metadataToolCalls.findIndex((candidate, idx) => !usedMetadataIndexes.has(idx) && candidate?.id === id) : -1;
|
|
871
845
|
if (byId >= 0) return byId;
|
|
872
|
-
return name ? metadataToolCalls.findIndex((candidate, idx) =>
|
|
873
|
-
if (usedMetadataIndexes.has(idx)) return false;
|
|
874
|
-
const label = candidateToolLabel(candidate);
|
|
875
|
-
return label === name;
|
|
876
|
-
}) : -1;
|
|
846
|
+
return name ? metadataToolCalls.findIndex((candidate, idx) => !usedMetadataIndexes.has(idx) && candidate?.name === name) : -1;
|
|
877
847
|
};
|
|
878
848
|
const parseToolCall = (primary, secondary) => {
|
|
879
|
-
const nestedTool = primary && typeof primary.tool === "object" && primary.tool !== null && !Array.isArray(primary.tool) ? primary.tool : void 0;
|
|
880
849
|
const id = typeof primary.id === "string" ? primary.id : typeof secondary?.id === "string" ? secondary.id : void 0;
|
|
881
|
-
const name = typeof primary.name === "string" ? primary.name :
|
|
850
|
+
const name = typeof primary.name === "string" ? primary.name : typeof secondary?.name === "string" ? secondary.name : "tool";
|
|
882
851
|
const argsRaw = primary.args ?? primary.arguments ?? secondary?.args ?? secondary?.arguments;
|
|
883
852
|
const result = primary.output !== void 0 ? primary.output : primary.result !== void 0 ? primary.result : secondary?.output !== void 0 ? secondary.output : secondary?.result;
|
|
884
853
|
const status = normalizeToolStatus(primary.status ?? secondary?.status);
|
|
@@ -900,17 +869,7 @@ var extractToolCallsFromServerMessage = (msg) => {
|
|
|
900
869
|
if (usedMetadataIndexes.has(index)) return;
|
|
901
870
|
parsed.push(parseToolCall(toolCall));
|
|
902
871
|
});
|
|
903
|
-
|
|
904
|
-
const deduped = [];
|
|
905
|
-
for (const p of parsed) {
|
|
906
|
-
const id = p.id;
|
|
907
|
-
if (typeof id === "string" && id.length > 0) {
|
|
908
|
-
if (seenIds.has(id)) continue;
|
|
909
|
-
seenIds.add(id);
|
|
910
|
-
}
|
|
911
|
-
deduped.push(p);
|
|
912
|
-
}
|
|
913
|
-
return deduped;
|
|
872
|
+
return parsed;
|
|
914
873
|
};
|
|
915
874
|
var extractToolResultUpdateFromMessage = (msg) => {
|
|
916
875
|
if (msg.senderType !== "tool") return null;
|
|
@@ -1148,11 +1107,6 @@ function useCopilotz({
|
|
|
1148
1107
|
return;
|
|
1149
1108
|
}
|
|
1150
1109
|
if (senderType === "agent" && typeof payload.content === "string") {
|
|
1151
|
-
const trimmedContent = payload.content.trim();
|
|
1152
|
-
const hasToolCalls = hasToolCallsInPayload(payload);
|
|
1153
|
-
if (!trimmedContent && hasToolCalls) {
|
|
1154
|
-
return;
|
|
1155
|
-
}
|
|
1156
1110
|
setMessages((prev) => {
|
|
1157
1111
|
const next = [...prev];
|
|
1158
1112
|
for (let i = next.length - 1; i >= 0; i--) {
|
|
@@ -1162,6 +1116,7 @@ function useCopilotz({
|
|
|
1162
1116
|
return next;
|
|
1163
1117
|
}
|
|
1164
1118
|
}
|
|
1119
|
+
const trimmedContent = payload.content.trim();
|
|
1165
1120
|
if (!trimmedContent) {
|
|
1166
1121
|
return prev;
|
|
1167
1122
|
}
|
|
@@ -1218,11 +1173,9 @@ function useCopilotz({
|
|
|
1218
1173
|
if (!nextThreadId && normalized.length > 0) {
|
|
1219
1174
|
nextThreadId = normalized[0].id;
|
|
1220
1175
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
}
|
|
1225
|
-
return nextThreadId ?? curId ?? null;
|
|
1176
|
+
setCurrentThreadId(nextThreadId ?? null);
|
|
1177
|
+
setCurrentThreadExternalId(nextThreadId ? externalMap[nextThreadId] ?? null : null);
|
|
1178
|
+
return nextThreadId;
|
|
1226
1179
|
}, []);
|
|
1227
1180
|
const fetchAndSetThreadsState = useCallback2(async (uid, preferredExternalId) => {
|
|
1228
1181
|
try {
|
|
@@ -1417,60 +1370,57 @@ function useCopilotz({
|
|
|
1417
1370
|
params.onBeforeStart?.(currentAssistantId);
|
|
1418
1371
|
let hasStreamProgress = false;
|
|
1419
1372
|
let pendingStartNewAssistantBubble = false;
|
|
1420
|
-
const updateStreamingMessage = (partial,
|
|
1373
|
+
const updateStreamingMessage = (partial, opts) => {
|
|
1421
1374
|
if (partial && partial.length > 0) {
|
|
1422
1375
|
hasStreamProgress = true;
|
|
1423
1376
|
}
|
|
1424
|
-
if (reasoningPartial !== void 0 && reasoningPartial.length > 0) {
|
|
1425
|
-
hasStreamProgress = true;
|
|
1426
|
-
}
|
|
1427
1377
|
const nextStreaming = true;
|
|
1428
1378
|
const nextComplete = false;
|
|
1379
|
+
const isReasoning = opts?.isReasoning ?? false;
|
|
1380
|
+
const applyUpdate = (msg) => {
|
|
1381
|
+
if (isReasoning) {
|
|
1382
|
+
return { ...msg, reasoning: partial, isReasoningStreaming: true, isStreaming: nextStreaming, isComplete: nextComplete };
|
|
1383
|
+
}
|
|
1384
|
+
const reasoningPatch = msg.reasoning ? { isReasoningStreaming: false } : {};
|
|
1385
|
+
return { ...msg, content: partial, ...reasoningPatch, isStreaming: nextStreaming, isComplete: nextComplete };
|
|
1386
|
+
};
|
|
1429
1387
|
setMessages((prev) => {
|
|
1430
|
-
const patch = (msg) => ({
|
|
1431
|
-
...msg,
|
|
1432
|
-
content: partial,
|
|
1433
|
-
...reasoningPartial !== void 0 ? { reasoning: reasoningPartial } : {},
|
|
1434
|
-
isStreaming: nextStreaming,
|
|
1435
|
-
isComplete: nextComplete
|
|
1436
|
-
});
|
|
1437
1388
|
const idx = prev.findIndex((m) => m.id === currentAssistantId);
|
|
1438
1389
|
if (idx >= 0 && prev[idx].role === "assistant" && prev[idx].isStreaming) {
|
|
1439
1390
|
const msg = prev[idx];
|
|
1440
|
-
|
|
1391
|
+
const next = applyUpdate(msg);
|
|
1392
|
+
if (msg.content === next.content && msg.reasoning === next.reasoning && msg.isReasoningStreaming === next.isReasoningStreaming && msg.isStreaming === next.isStreaming && msg.isComplete === next.isComplete) {
|
|
1441
1393
|
return prev;
|
|
1442
1394
|
}
|
|
1443
1395
|
const updated = [...prev];
|
|
1444
|
-
updated[idx] =
|
|
1396
|
+
updated[idx] = next;
|
|
1445
1397
|
return updated;
|
|
1446
1398
|
}
|
|
1447
1399
|
const last = prev[prev.length - 1];
|
|
1448
1400
|
if (last && last.role === "assistant" && last.isStreaming) {
|
|
1449
1401
|
currentAssistantId = last.id;
|
|
1450
1402
|
pendingStartNewAssistantBubble = false;
|
|
1451
|
-
|
|
1403
|
+
const next = applyUpdate(last);
|
|
1404
|
+
if (last.content === next.content && last.reasoning === next.reasoning && last.isReasoningStreaming === next.isReasoningStreaming && last.isStreaming === next.isStreaming && last.isComplete === next.isComplete) {
|
|
1452
1405
|
return prev;
|
|
1453
1406
|
}
|
|
1454
1407
|
const updated = [...prev];
|
|
1455
|
-
updated[prev.length - 1] =
|
|
1408
|
+
updated[prev.length - 1] = next;
|
|
1456
1409
|
return updated;
|
|
1457
1410
|
}
|
|
1458
1411
|
if (pendingStartNewAssistantBubble || !prev.length || (prev[prev.length - 1].role !== "assistant" || !prev[prev.length - 1].isStreaming)) {
|
|
1459
1412
|
const newId = generateId();
|
|
1460
1413
|
currentAssistantId = newId;
|
|
1461
1414
|
pendingStartNewAssistantBubble = false;
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
isComplete: nextComplete
|
|
1472
|
-
}
|
|
1473
|
-
];
|
|
1415
|
+
const base = {
|
|
1416
|
+
id: newId,
|
|
1417
|
+
role: "assistant",
|
|
1418
|
+
content: "",
|
|
1419
|
+
timestamp: nowTs(),
|
|
1420
|
+
isStreaming: nextStreaming,
|
|
1421
|
+
isComplete: nextComplete
|
|
1422
|
+
};
|
|
1423
|
+
return [...prev, applyUpdate(base)];
|
|
1474
1424
|
}
|
|
1475
1425
|
return prev;
|
|
1476
1426
|
});
|
|
@@ -1493,21 +1443,37 @@ function useCopilotz({
|
|
|
1493
1443
|
const payload = event?.payload ?? event;
|
|
1494
1444
|
if (type === "TOOL_CALL") {
|
|
1495
1445
|
const metadata = payload?.metadata ?? {};
|
|
1496
|
-
const tc = payload?.toolCall ??
|
|
1497
|
-
const
|
|
1498
|
-
const
|
|
1446
|
+
const tc = payload?.toolCall ?? void 0;
|
|
1447
|
+
const tcTool = tc?.tool ?? void 0;
|
|
1448
|
+
const call = payload?.call ?? metadata?.call;
|
|
1449
|
+
const func = call?.function ?? payload?.function;
|
|
1450
|
+
const toolName = tcTool?.name || func?.name || payload?.name || call?.name || metadata.toolName || metadata.tool || "tool";
|
|
1499
1451
|
let argsObj = {};
|
|
1500
|
-
const
|
|
1501
|
-
|
|
1452
|
+
const possibleArgs = [
|
|
1453
|
+
tc?.args,
|
|
1454
|
+
func?.arguments,
|
|
1455
|
+
payload?.args,
|
|
1456
|
+
call?.arguments,
|
|
1457
|
+
metadata?.args,
|
|
1458
|
+
metadata?.arguments
|
|
1459
|
+
];
|
|
1460
|
+
for (const candidate of possibleArgs) {
|
|
1461
|
+
if (candidate === void 0 || candidate === null) continue;
|
|
1502
1462
|
try {
|
|
1503
|
-
|
|
1463
|
+
if (typeof candidate === "string") {
|
|
1464
|
+
argsObj = JSON.parse(candidate);
|
|
1465
|
+
break;
|
|
1466
|
+
}
|
|
1467
|
+
if (typeof candidate === "object") {
|
|
1468
|
+
argsObj = candidate;
|
|
1469
|
+
break;
|
|
1470
|
+
}
|
|
1504
1471
|
} catch {
|
|
1505
1472
|
}
|
|
1506
|
-
} else if (argsRaw && typeof argsRaw === "object" && !Array.isArray(argsRaw)) {
|
|
1507
|
-
argsObj = argsRaw;
|
|
1508
1473
|
}
|
|
1509
|
-
const
|
|
1510
|
-
const
|
|
1474
|
+
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);
|
|
1475
|
+
const callId = tc?.id || call?.id || func?.id || payload?.id || generateId();
|
|
1476
|
+
const statusVal = tc?.status || payload?.status || event?.status || "pending";
|
|
1511
1477
|
return {
|
|
1512
1478
|
id: generateId(),
|
|
1513
1479
|
threadId: curThreadId ?? "",
|
|
@@ -1517,6 +1483,7 @@ function useCopilotz({
|
|
|
1517
1483
|
id: callId,
|
|
1518
1484
|
name: toolName,
|
|
1519
1485
|
args: argsObj,
|
|
1486
|
+
output,
|
|
1520
1487
|
status: statusVal
|
|
1521
1488
|
}]
|
|
1522
1489
|
};
|
|
@@ -1595,9 +1562,7 @@ function useCopilotz({
|
|
|
1595
1562
|
toolCalls: params.toolCalls,
|
|
1596
1563
|
selectedAgent: params.agentName ?? preferredAgentRef.current ?? null,
|
|
1597
1564
|
getRequestHeaders,
|
|
1598
|
-
onToken: (token,
|
|
1599
|
-
updateStreamingMessage(token, isComplete, raw, reasoning);
|
|
1600
|
-
},
|
|
1565
|
+
onToken: (token, _isComplete, _raw, opts) => updateStreamingMessage(token, opts),
|
|
1601
1566
|
onMessageEvent: async (event) => {
|
|
1602
1567
|
const intercepted = applyEventInterceptor(event);
|
|
1603
1568
|
if (intercepted?.handled) {
|
|
@@ -1607,9 +1572,6 @@ function useCopilotz({
|
|
|
1607
1572
|
const payload = getEventPayload(event);
|
|
1608
1573
|
if (type === "MESSAGE" || type === "NEW_MESSAGE") {
|
|
1609
1574
|
const senderType = getEventSenderType(payload);
|
|
1610
|
-
if (senderType === "agent" && hasStreamProgress) {
|
|
1611
|
-
return;
|
|
1612
|
-
}
|
|
1613
1575
|
if (senderType === "tool") {
|
|
1614
1576
|
const metadata = payload?.metadata ?? {};
|
|
1615
1577
|
const toolCallsArray = metadata?.toolCalls;
|
|
@@ -1619,16 +1581,8 @@ function useCopilotz({
|
|
|
1619
1581
|
}
|
|
1620
1582
|
processToolOutput(metadata);
|
|
1621
1583
|
const toolCallId = toolCallData.id;
|
|
1622
|
-
const
|
|
1623
|
-
const
|
|
1624
|
-
const toolResultRaw = toolCallData.output || payload?.content;
|
|
1625
|
-
const toolResult = typeof toolResultRaw === "string" ? (() => {
|
|
1626
|
-
try {
|
|
1627
|
-
return JSON.parse(toolResultRaw);
|
|
1628
|
-
} catch {
|
|
1629
|
-
return toolResultRaw;
|
|
1630
|
-
}
|
|
1631
|
-
})() : toolResultRaw;
|
|
1584
|
+
const toolCallName = toolCallData.name;
|
|
1585
|
+
const toolResult = toolCallData.output || payload?.content;
|
|
1632
1586
|
const toolStatus = toolCallData.status || "completed";
|
|
1633
1587
|
const isFailed = toolStatus === "failed" || toolCallData?.error;
|
|
1634
1588
|
setMessages((prev) => {
|
|
@@ -1667,7 +1621,7 @@ function useCopilotz({
|
|
|
1667
1621
|
return;
|
|
1668
1622
|
}
|
|
1669
1623
|
handleStreamMessageEvent(event);
|
|
1670
|
-
if (senderType === "agent"
|
|
1624
|
+
if (senderType === "agent") {
|
|
1671
1625
|
currentAssistantId = generateId();
|
|
1672
1626
|
pendingStartNewAssistantBubble = true;
|
|
1673
1627
|
}
|
|
@@ -1680,27 +1634,20 @@ function useCopilotz({
|
|
|
1680
1634
|
if (!toolCall) return;
|
|
1681
1635
|
setMessages(
|
|
1682
1636
|
(prev) => (() => {
|
|
1683
|
-
const appendToolCall = (msg) => {
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
result: toolCall.output,
|
|
1698
|
-
status: toolCall.status ?? "running",
|
|
1699
|
-
startTime: Date.now()
|
|
1700
|
-
}
|
|
1701
|
-
]
|
|
1702
|
-
};
|
|
1703
|
-
};
|
|
1637
|
+
const appendToolCall = (msg) => ({
|
|
1638
|
+
...msg,
|
|
1639
|
+
toolCalls: [
|
|
1640
|
+
...Array.isArray(msg.toolCalls) ? msg.toolCalls : [],
|
|
1641
|
+
{
|
|
1642
|
+
id: toolCall.id ?? generateId(),
|
|
1643
|
+
name: toolCall.name ?? "tool",
|
|
1644
|
+
arguments: toolCall.args ?? toolCall.arguments ?? {},
|
|
1645
|
+
result: toolCall.output,
|
|
1646
|
+
status: toolCall.status ?? "running",
|
|
1647
|
+
startTime: Date.now()
|
|
1648
|
+
}
|
|
1649
|
+
]
|
|
1650
|
+
});
|
|
1704
1651
|
const currentIdx = prev.findIndex((message) => message.id === currentAssistantId && message.role === "assistant" && message.isStreaming);
|
|
1705
1652
|
if (currentIdx >= 0) {
|
|
1706
1653
|
const next = [...prev];
|
|
@@ -1712,7 +1659,7 @@ function useCopilotz({
|
|
|
1712
1659
|
return next;
|
|
1713
1660
|
}
|
|
1714
1661
|
const last = prev[prev.length - 1];
|
|
1715
|
-
if (last?.role === "assistant" && last.isStreaming) {
|
|
1662
|
+
if (!pendingStartNewAssistantBubble && last?.role === "assistant" && last.isStreaming) {
|
|
1716
1663
|
currentAssistantId = last.id;
|
|
1717
1664
|
const next = [...prev];
|
|
1718
1665
|
next[prev.length - 1] = appendToolCall({
|
|
@@ -1739,6 +1686,7 @@ function useCopilotz({
|
|
|
1739
1686
|
})()
|
|
1740
1687
|
);
|
|
1741
1688
|
hasStreamProgress = true;
|
|
1689
|
+
pendingStartNewAssistantBubble = true;
|
|
1742
1690
|
return;
|
|
1743
1691
|
}
|
|
1744
1692
|
const sm = await toServerMessageFromEvent(event);
|
|
@@ -1797,10 +1745,8 @@ function useCopilotz({
|
|
|
1797
1745
|
effectiveThreadExternalId = generateId();
|
|
1798
1746
|
}
|
|
1799
1747
|
setCurrentThreadExternalId(effectiveThreadExternalId);
|
|
1800
|
-
currentThreadExternalIdRef.current = effectiveThreadExternalId;
|
|
1801
1748
|
} else if (curThreadExtId !== (effectiveThreadExternalId ?? null)) {
|
|
1802
1749
|
setCurrentThreadExternalId(effectiveThreadExternalId ?? null);
|
|
1803
|
-
currentThreadExternalIdRef.current = effectiveThreadExternalId ?? null;
|
|
1804
1750
|
}
|
|
1805
1751
|
const conversationKey = threadIdForSend ?? effectiveThreadExternalId;
|
|
1806
1752
|
const currentMetadata = threadMetadataMapRef.current[conversationKey];
|
|
@@ -1834,13 +1780,6 @@ function useCopilotz({
|
|
|
1834
1780
|
setThreads((prev) => [newThread, ...prev]);
|
|
1835
1781
|
setThreadMetadataMap((prev) => ({ ...prev, [conversationKey]: {} }));
|
|
1836
1782
|
setThreadExternalIdMap((prev) => ({ ...prev, [conversationKey]: effectiveThreadExternalId ?? null }));
|
|
1837
|
-
setCurrentThreadId(conversationKey);
|
|
1838
|
-
currentThreadIdRef.current = conversationKey;
|
|
1839
|
-
threadsRef.current = [newThread, ...threadsRef.current];
|
|
1840
|
-
threadExternalIdMapRef.current = {
|
|
1841
|
-
...threadExternalIdMapRef.current,
|
|
1842
|
-
[conversationKey]: effectiveThreadExternalId ?? null
|
|
1843
|
-
};
|
|
1844
1783
|
}
|
|
1845
1784
|
try {
|
|
1846
1785
|
await sendCopilotzMessage({
|