@copilotz/chat-adapter 0.9.42 → 0.9.44
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 +2 -2
- package/dist/index.js +163 -68
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -57,8 +57,8 @@ type StreamCallbacks = {
|
|
|
57
57
|
onToken?: (token: string, isComplete: boolean, raw?: any, options?: {
|
|
58
58
|
isReasoning?: boolean;
|
|
59
59
|
}) => void;
|
|
60
|
-
onMessageEvent?: (payload: any) => void
|
|
61
|
-
onAssetEvent?: (payload: any) => void
|
|
60
|
+
onMessageEvent?: (payload: any) => void | Promise<void>;
|
|
61
|
+
onAssetEvent?: (payload: any) => void | Promise<void>;
|
|
62
62
|
signal?: AbortSignal;
|
|
63
63
|
};
|
|
64
64
|
type RunOptions = {
|
package/dist/index.js
CHANGED
|
@@ -436,7 +436,7 @@ async function runCopilotzStream(options) {
|
|
|
436
436
|
lastTokenWasReasoning = false;
|
|
437
437
|
hadNonReasoningContent = false;
|
|
438
438
|
};
|
|
439
|
-
const processEvent = (eventChunk) => {
|
|
439
|
+
const processEvent = async (eventChunk) => {
|
|
440
440
|
if (!eventChunk.trim()) return;
|
|
441
441
|
const lines = eventChunk.split("\n");
|
|
442
442
|
let eventType = "message";
|
|
@@ -496,13 +496,13 @@ async function runCopilotzStream(options) {
|
|
|
496
496
|
hadNonReasoningContent = true;
|
|
497
497
|
lastTokenWasReasoning = false;
|
|
498
498
|
collectedMessages.push(payload2);
|
|
499
|
-
onMessageEvent?.(payload2);
|
|
499
|
+
await onMessageEvent?.(payload2);
|
|
500
500
|
break;
|
|
501
501
|
}
|
|
502
502
|
case "TOOL_CALL": {
|
|
503
503
|
hadNonReasoningContent = true;
|
|
504
504
|
lastTokenWasReasoning = false;
|
|
505
|
-
onMessageEvent?.(payload2);
|
|
505
|
+
await onMessageEvent?.(payload2);
|
|
506
506
|
break;
|
|
507
507
|
}
|
|
508
508
|
case "TOOL_RESULT":
|
|
@@ -512,7 +512,7 @@ async function runCopilotzStream(options) {
|
|
|
512
512
|
lastCompletedText = resultAnswer;
|
|
513
513
|
}
|
|
514
514
|
resetTokenAggregation();
|
|
515
|
-
onMessageEvent?.(payload2);
|
|
515
|
+
await onMessageEvent?.(payload2);
|
|
516
516
|
break;
|
|
517
517
|
}
|
|
518
518
|
case "ASSET_CREATED": {
|
|
@@ -522,7 +522,7 @@ async function runCopilotzStream(options) {
|
|
|
522
522
|
[assetPayload.assetId || "0"]: assetPayload.dataUrl
|
|
523
523
|
};
|
|
524
524
|
}
|
|
525
|
-
onAssetEvent?.(assetPayload);
|
|
525
|
+
await onAssetEvent?.(assetPayload);
|
|
526
526
|
break;
|
|
527
527
|
}
|
|
528
528
|
case "ERROR":
|
|
@@ -530,9 +530,9 @@ async function runCopilotzStream(options) {
|
|
|
530
530
|
default: {
|
|
531
531
|
const hasEnvelope = payload2 && typeof payload2 === "object" && "type" in payload2;
|
|
532
532
|
if (hasEnvelope) {
|
|
533
|
-
onMessageEvent?.(payload2);
|
|
533
|
+
await onMessageEvent?.(payload2);
|
|
534
534
|
} else {
|
|
535
|
-
onMessageEvent?.({ type: eventType, payload: payload2 });
|
|
535
|
+
await onMessageEvent?.({ type: eventType, payload: payload2 });
|
|
536
536
|
}
|
|
537
537
|
break;
|
|
538
538
|
}
|
|
@@ -549,12 +549,12 @@ async function runCopilotzStream(options) {
|
|
|
549
549
|
while (eventBoundary >= 0) {
|
|
550
550
|
const chunk = buffer.slice(0, eventBoundary);
|
|
551
551
|
buffer = buffer.slice(eventBoundary + SSE_LINE_BREAK.length);
|
|
552
|
-
processEvent(chunk);
|
|
552
|
+
await processEvent(chunk);
|
|
553
553
|
eventBoundary = buffer.indexOf(SSE_LINE_BREAK);
|
|
554
554
|
}
|
|
555
555
|
}
|
|
556
556
|
if (buffer.length > 0) {
|
|
557
|
-
processEvent(buffer);
|
|
557
|
+
await processEvent(buffer);
|
|
558
558
|
}
|
|
559
559
|
return {
|
|
560
560
|
text: lastCompletedText || aggregatedText,
|
|
@@ -925,27 +925,33 @@ var applyAssistantToolResult = (message, update) => {
|
|
|
925
925
|
const index = items.findIndex((item2) => item2.kind === "tool" && (update.id && item2.id === update.id || !update.id && item2.toolName === update.name));
|
|
926
926
|
if (index === -1) return message;
|
|
927
927
|
const item = items[index];
|
|
928
|
+
const { error, ...toolCallUpdate } = update;
|
|
928
929
|
const toolCall = item.details?.toolCall;
|
|
929
|
-
const nextToolCall = toolCall ? { ...toolCall, ...
|
|
930
|
-
id:
|
|
931
|
-
name:
|
|
930
|
+
const nextToolCall = toolCall ? { ...toolCall, ...toolCallUpdate } : {
|
|
931
|
+
id: toolCallUpdate.id ?? item.id,
|
|
932
|
+
name: toolCallUpdate.name,
|
|
932
933
|
arguments: {},
|
|
933
|
-
status:
|
|
934
|
-
...
|
|
935
|
-
...
|
|
934
|
+
status: toolCallUpdate.status,
|
|
935
|
+
...toolCallUpdate.result !== void 0 ? { result: toolCallUpdate.result } : {},
|
|
936
|
+
...toolCallUpdate.endTime !== void 0 ? { endTime: toolCallUpdate.endTime } : {}
|
|
936
937
|
};
|
|
937
938
|
const status = toolStatusToActivityStatus(update.status);
|
|
939
|
+
const details = {
|
|
940
|
+
...item.details ?? {},
|
|
941
|
+
toolCall: nextToolCall,
|
|
942
|
+
...update.result !== void 0 ? { result: update.result } : {},
|
|
943
|
+
...error !== void 0 ? { error } : {}
|
|
944
|
+
};
|
|
945
|
+
if (error === void 0 && update.status !== "failed") {
|
|
946
|
+
delete details.error;
|
|
947
|
+
}
|
|
938
948
|
const next = [...items];
|
|
939
949
|
next[index] = {
|
|
940
950
|
...item,
|
|
941
951
|
status,
|
|
942
952
|
toolName: update.name,
|
|
943
953
|
...status !== "active" ? { completedAt: update.endTime ?? Date.now() } : {},
|
|
944
|
-
details
|
|
945
|
-
...item.details ?? {},
|
|
946
|
-
toolCall: nextToolCall,
|
|
947
|
-
...update.result !== void 0 ? { result: update.result } : {}
|
|
948
|
-
}
|
|
954
|
+
details
|
|
949
955
|
};
|
|
950
956
|
return setItems(message, next);
|
|
951
957
|
};
|
|
@@ -1243,8 +1249,18 @@ var expectToolStatus = (status, path) => {
|
|
|
1243
1249
|
if (status === "pending") return "pending";
|
|
1244
1250
|
if (status === "running" || status === "processing") return "running";
|
|
1245
1251
|
if (status === "failed") return "failed";
|
|
1252
|
+
if (status === "cancelled") return "failed";
|
|
1246
1253
|
if (status === "completed") return "completed";
|
|
1247
|
-
return fail(`${path} must be pending, running, processing, completed, or
|
|
1254
|
+
return fail(`${path} must be pending, running, processing, completed, failed, or cancelled`);
|
|
1255
|
+
};
|
|
1256
|
+
var formatToolError = (error) => {
|
|
1257
|
+
if (error === void 0) return void 0;
|
|
1258
|
+
if (typeof error === "string") return error;
|
|
1259
|
+
try {
|
|
1260
|
+
return JSON.stringify(error);
|
|
1261
|
+
} catch {
|
|
1262
|
+
return String(error);
|
|
1263
|
+
}
|
|
1248
1264
|
};
|
|
1249
1265
|
var expectToolArguments = (value, path) => {
|
|
1250
1266
|
if (isRecord(value)) return value;
|
|
@@ -1271,7 +1287,7 @@ var matchesToolResultUpdate = (target, update) => {
|
|
|
1271
1287
|
var findMatchingToolItem = (toolItems, update) => toolItems.find((item) => matchesToolResultUpdate(
|
|
1272
1288
|
{ id: item.id, name: item.toolName },
|
|
1273
1289
|
update
|
|
1274
|
-
) && (item.status === "active" || item.details?.result === void 0));
|
|
1290
|
+
) && (item.status === "active" || item.details?.result === void 0 && item.details?.error === void 0));
|
|
1275
1291
|
var applyToolResultUpdateToMessages = (messages, update, assistantPatch) => {
|
|
1276
1292
|
const nextMessages = [...messages];
|
|
1277
1293
|
for (let i = nextMessages.length - 1; i >= 0; i--) {
|
|
@@ -1289,6 +1305,7 @@ var applyToolResultUpdateToMessages = (messages, update, assistantPatch) => {
|
|
|
1289
1305
|
name: update.name ?? toolItem.toolName ?? toolItem.id,
|
|
1290
1306
|
status: update.status,
|
|
1291
1307
|
...update.result !== void 0 ? { result: update.result } : {},
|
|
1308
|
+
...update.error !== void 0 ? { error: update.error } : {},
|
|
1292
1309
|
endTime: update.endTime
|
|
1293
1310
|
}),
|
|
1294
1311
|
...assistantPatch ?? {}
|
|
@@ -1314,12 +1331,13 @@ var extractLiveToolResultUpdate = (payload, now = () => Date.now()) => {
|
|
|
1314
1331
|
const payloadRecord = expectRecord(payload, "TOOL_RESULT payload");
|
|
1315
1332
|
const tool = expectRecord(payloadRecord.tool, "TOOL_RESULT payload.tool");
|
|
1316
1333
|
const result = payloadRecord.projectedOutput !== void 0 ? payloadRecord.projectedOutput : payloadRecord.output;
|
|
1317
|
-
|
|
1334
|
+
const error = formatToolError(payloadRecord.error);
|
|
1318
1335
|
return {
|
|
1319
1336
|
id: expectString(payloadRecord.toolCallId, "TOOL_RESULT payload.toolCallId"),
|
|
1320
1337
|
name: expectToolName(tool, "TOOL_RESULT payload.tool.id"),
|
|
1321
1338
|
status: expectToolStatus(payloadRecord.status, "TOOL_RESULT payload.status"),
|
|
1322
|
-
result,
|
|
1339
|
+
...result !== void 0 ? { result } : {},
|
|
1340
|
+
...error !== void 0 ? { error } : {},
|
|
1323
1341
|
endTime: now()
|
|
1324
1342
|
};
|
|
1325
1343
|
};
|
|
@@ -1342,6 +1360,7 @@ var extractToolCallsFromServerMessage = (msg) => {
|
|
|
1342
1360
|
const name = expectToolName(tool, "toolCall.tool.id");
|
|
1343
1361
|
const argsRaw = primary.args ?? secondary?.args;
|
|
1344
1362
|
const result = primary.output !== void 0 ? primary.output : secondary?.output !== void 0 ? secondary.output : primary.projectedOutput !== void 0 ? primary.projectedOutput : secondary?.projectedOutput;
|
|
1363
|
+
const error = formatToolError(primary.error !== void 0 ? primary.error : secondary?.error);
|
|
1345
1364
|
const rawStatus = primary.status ?? secondary?.status;
|
|
1346
1365
|
return {
|
|
1347
1366
|
id,
|
|
@@ -1349,6 +1368,7 @@ var extractToolCallsFromServerMessage = (msg) => {
|
|
|
1349
1368
|
name,
|
|
1350
1369
|
arguments: expectToolArguments(argsRaw, "toolCall.args"),
|
|
1351
1370
|
...result !== void 0 ? { result } : {},
|
|
1371
|
+
...error !== void 0 ? { error } : {},
|
|
1352
1372
|
status: rawStatus === void 0 ? "running" : expectToolStatus(rawStatus, "toolCall.status")
|
|
1353
1373
|
};
|
|
1354
1374
|
};
|
|
@@ -1374,13 +1394,13 @@ var extractToolResultUpdateFromMessage = (msg, now = () => Date.now()) => {
|
|
|
1374
1394
|
const toolCalls = extractToolCallsFromServerMessage(msg);
|
|
1375
1395
|
if (toolCalls.length === 0) fail("tool message requires metadata.toolCalls");
|
|
1376
1396
|
const firstToolCall = toolCalls[0];
|
|
1377
|
-
if (firstToolCall.result === void 0) fail("tool result message requires tool call output");
|
|
1378
1397
|
expectStringValue(msg.createdAt, "tool result message.createdAt");
|
|
1379
1398
|
return {
|
|
1380
1399
|
id: firstToolCall.id,
|
|
1381
1400
|
...firstToolCall.toolExecutionId ? { toolExecutionId: firstToolCall.toolExecutionId } : {},
|
|
1382
1401
|
name: firstToolCall.name,
|
|
1383
|
-
result: firstToolCall.result,
|
|
1402
|
+
...firstToolCall.result !== void 0 ? { result: firstToolCall.result } : {},
|
|
1403
|
+
...firstToolCall.error !== void 0 ? { error: firstToolCall.error } : {},
|
|
1384
1404
|
status: firstToolCall.status,
|
|
1385
1405
|
endTime: new Date(msg.createdAt).getTime()
|
|
1386
1406
|
};
|
|
@@ -1618,6 +1638,17 @@ var getStreamEventPayload = (event) => {
|
|
|
1618
1638
|
if (!isRecord2(event)) return event;
|
|
1619
1639
|
return "payload" in event ? event.payload : event;
|
|
1620
1640
|
};
|
|
1641
|
+
var getLlmAttemptId = (event) => {
|
|
1642
|
+
if (!isRecord2(event)) return null;
|
|
1643
|
+
const metadata = isRecord2(event.metadata) ? event.metadata : {};
|
|
1644
|
+
if (typeof metadata.llmAttemptId === "string" && metadata.llmAttemptId.trim().length > 0) {
|
|
1645
|
+
return metadata.llmAttemptId.trim();
|
|
1646
|
+
}
|
|
1647
|
+
if (event.subjectType === "llm_attempt" && typeof event.subjectId === "string" && event.subjectId.trim().length > 0) {
|
|
1648
|
+
return event.subjectId.trim();
|
|
1649
|
+
}
|
|
1650
|
+
return null;
|
|
1651
|
+
};
|
|
1621
1652
|
var isTerminalEmptyLlmResultEvent = (event) => {
|
|
1622
1653
|
if (!isRecord2(event) || event.type !== "LLM_RESULT") return false;
|
|
1623
1654
|
const payload = getStreamEventPayload(event);
|
|
@@ -1632,40 +1663,18 @@ var isTerminalEmptyLlmResultEvent = (event) => {
|
|
|
1632
1663
|
return true;
|
|
1633
1664
|
};
|
|
1634
1665
|
|
|
1635
|
-
// src/
|
|
1636
|
-
var
|
|
1637
|
-
var
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
var normalizeThreadTag = (value) => {
|
|
1643
|
-
if (!isRecord3(value)) return null;
|
|
1644
|
-
const id = typeof value.id === "string" ? value.id.trim() : "";
|
|
1645
|
-
const name = typeof value.name === "string" ? value.name.trim() : "";
|
|
1646
|
-
const color = typeof value.color === "string" && value.color.trim() ? value.color.trim() : void 0;
|
|
1647
|
-
if (!id || !name) return null;
|
|
1648
|
-
return color ? { id, name, color } : { id, name };
|
|
1666
|
+
// src/threadIdentity.ts
|
|
1667
|
+
var identityValues = ({ id, externalId }) => [id, externalId].filter((value) => typeof value === "string" && value.length > 0);
|
|
1668
|
+
var isSameThreadIdentity = (owner, current) => {
|
|
1669
|
+
const ownerValues = identityValues(owner);
|
|
1670
|
+
if (ownerValues.length === 0) return true;
|
|
1671
|
+
const currentValues = new Set(identityValues(current));
|
|
1672
|
+
return ownerValues.some((value) => currentValues.has(value));
|
|
1649
1673
|
};
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
return tags.map(normalizeThreadTag).filter((tag) => !!tag);
|
|
1655
|
-
};
|
|
1656
|
-
var patchMetadataPublicTags = (metadata, tags) => ({
|
|
1657
|
-
...metadata ?? {},
|
|
1658
|
-
public: {
|
|
1659
|
-
...isRecord3(metadata?.public) ? metadata.public : {},
|
|
1660
|
-
tags
|
|
1661
|
-
}
|
|
1662
|
-
});
|
|
1663
|
-
var THREAD_MESSAGES_PAGE_SIZE = 50;
|
|
1664
|
-
var createEmptyMessagePageInfo = () => ({
|
|
1665
|
-
hasMoreBefore: false,
|
|
1666
|
-
oldestMessageId: null,
|
|
1667
|
-
newestMessageId: null
|
|
1668
|
-
});
|
|
1674
|
+
|
|
1675
|
+
// src/messageReconciliation.ts
|
|
1676
|
+
var CLIENT_MESSAGE_ID_METADATA_KEY = "clientMessageId";
|
|
1677
|
+
var LLM_ATTEMPT_ID_METADATA_KEY = "llmAttemptId";
|
|
1669
1678
|
var stringifyForCompare = (value) => {
|
|
1670
1679
|
if (value === void 0) return "";
|
|
1671
1680
|
try {
|
|
@@ -1690,6 +1699,36 @@ var getMessageSignature = (message) => JSON.stringify({
|
|
|
1690
1699
|
agentId: message.sender.agentId
|
|
1691
1700
|
} : null
|
|
1692
1701
|
});
|
|
1702
|
+
var getMetadataString = (message, key) => {
|
|
1703
|
+
const value = message.metadata?.[key];
|
|
1704
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
1705
|
+
};
|
|
1706
|
+
var getCorrelationKeys = (message) => {
|
|
1707
|
+
const clientMessageId = getMetadataString(
|
|
1708
|
+
message,
|
|
1709
|
+
CLIENT_MESSAGE_ID_METADATA_KEY
|
|
1710
|
+
);
|
|
1711
|
+
const llmAttemptId = getMetadataString(
|
|
1712
|
+
message,
|
|
1713
|
+
LLM_ATTEMPT_ID_METADATA_KEY
|
|
1714
|
+
);
|
|
1715
|
+
return [
|
|
1716
|
+
...clientMessageId ? [`client-message:${message.role}:${clientMessageId}`] : [],
|
|
1717
|
+
...llmAttemptId ? [`llm-attempt:${message.role}:${llmAttemptId}`] : []
|
|
1718
|
+
];
|
|
1719
|
+
};
|
|
1720
|
+
var indexUniqueFreshCorrelations = (freshMessages) => {
|
|
1721
|
+
const messagesByCorrelation = /* @__PURE__ */ new Map();
|
|
1722
|
+
for (const message of freshMessages) {
|
|
1723
|
+
for (const key of getCorrelationKeys(message)) {
|
|
1724
|
+
messagesByCorrelation.set(
|
|
1725
|
+
key,
|
|
1726
|
+
messagesByCorrelation.has(key) ? null : message
|
|
1727
|
+
);
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
return messagesByCorrelation;
|
|
1731
|
+
};
|
|
1693
1732
|
var reconcileThreadMessages = (currentMessages, freshMessages) => {
|
|
1694
1733
|
if (freshMessages.length === 0) {
|
|
1695
1734
|
return { messages: currentMessages, changed: false };
|
|
@@ -1698,12 +1737,15 @@ var reconcileThreadMessages = (currentMessages, freshMessages) => {
|
|
|
1698
1737
|
return { messages: freshMessages, changed: true };
|
|
1699
1738
|
}
|
|
1700
1739
|
const freshById = new Map(freshMessages.map((message) => [message.id, message]));
|
|
1740
|
+
const freshByCorrelation = indexUniqueFreshCorrelations(freshMessages);
|
|
1701
1741
|
const seen = /* @__PURE__ */ new Set();
|
|
1702
1742
|
let changed = false;
|
|
1703
1743
|
const nextMessages = currentMessages.map((message) => {
|
|
1704
|
-
const
|
|
1744
|
+
const exactMatch = freshById.get(message.id);
|
|
1745
|
+
const correlatedMatch = exactMatch ? null : getCorrelationKeys(message).map((key) => freshByCorrelation.get(key)).find((candidate) => candidate !== null && candidate !== void 0 && !seen.has(candidate.id));
|
|
1746
|
+
const fresh = exactMatch ?? correlatedMatch;
|
|
1705
1747
|
if (!fresh) return message;
|
|
1706
|
-
seen.add(
|
|
1748
|
+
seen.add(fresh.id);
|
|
1707
1749
|
if (getMessageSignature(message) === getMessageSignature(fresh)) {
|
|
1708
1750
|
return message;
|
|
1709
1751
|
}
|
|
@@ -1721,6 +1763,41 @@ var reconcileThreadMessages = (currentMessages, freshMessages) => {
|
|
|
1721
1763
|
}
|
|
1722
1764
|
return changed ? { messages: nextMessages, changed } : { messages: currentMessages, changed: false };
|
|
1723
1765
|
};
|
|
1766
|
+
|
|
1767
|
+
// src/useCopilotzChat.ts
|
|
1768
|
+
var nowTs = () => Date.now();
|
|
1769
|
+
var generateId = () => globalThis.crypto?.randomUUID?.() ?? `id-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1770
|
+
var isAbortError = (error) => error instanceof DOMException && error.name === "AbortError" || typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
|
|
1771
|
+
var getEventPayload = (event) => getStreamEventPayload(event);
|
|
1772
|
+
var getEventSenderType = (payload) => payload?.senderType || payload?.sender?.type;
|
|
1773
|
+
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1774
|
+
var normalizeThreadTag = (value) => {
|
|
1775
|
+
if (!isRecord3(value)) return null;
|
|
1776
|
+
const id = typeof value.id === "string" ? value.id.trim() : "";
|
|
1777
|
+
const name = typeof value.name === "string" ? value.name.trim() : "";
|
|
1778
|
+
const color = typeof value.color === "string" && value.color.trim() ? value.color.trim() : void 0;
|
|
1779
|
+
if (!id || !name) return null;
|
|
1780
|
+
return color ? { id, name, color } : { id, name };
|
|
1781
|
+
};
|
|
1782
|
+
var getThreadTagsFromMetadata = (metadata) => {
|
|
1783
|
+
if (!isRecord3(metadata) || !isRecord3(metadata.public)) return [];
|
|
1784
|
+
const tags = metadata.public.tags;
|
|
1785
|
+
if (!Array.isArray(tags)) return [];
|
|
1786
|
+
return tags.map(normalizeThreadTag).filter((tag) => !!tag);
|
|
1787
|
+
};
|
|
1788
|
+
var patchMetadataPublicTags = (metadata, tags) => ({
|
|
1789
|
+
...metadata ?? {},
|
|
1790
|
+
public: {
|
|
1791
|
+
...isRecord3(metadata?.public) ? metadata.public : {},
|
|
1792
|
+
tags
|
|
1793
|
+
}
|
|
1794
|
+
});
|
|
1795
|
+
var THREAD_MESSAGES_PAGE_SIZE = 50;
|
|
1796
|
+
var createEmptyMessagePageInfo = () => ({
|
|
1797
|
+
hasMoreBefore: false,
|
|
1798
|
+
oldestMessageId: null,
|
|
1799
|
+
newestMessageId: null
|
|
1800
|
+
});
|
|
1724
1801
|
var createPendingAssistantActivity = () => ({
|
|
1725
1802
|
items: [
|
|
1726
1803
|
{
|
|
@@ -2328,7 +2405,10 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2328
2405
|
let currentAssistantSender = params.assistantSender;
|
|
2329
2406
|
const streamOwnerThreadId = currentThreadIdRef.current;
|
|
2330
2407
|
const streamOwnerThreadExternalId = params.threadExternalId ?? currentThreadExternalIdRef.current;
|
|
2331
|
-
const streamStillOwnsVisibleThread = () =>
|
|
2408
|
+
const streamStillOwnsVisibleThread = () => isSameThreadIdentity(
|
|
2409
|
+
{ id: streamOwnerThreadId, externalId: streamOwnerThreadExternalId },
|
|
2410
|
+
{ id: currentThreadIdRef.current, externalId: currentThreadExternalIdRef.current }
|
|
2411
|
+
);
|
|
2332
2412
|
params.onBeforeStart?.(currentAssistantId);
|
|
2333
2413
|
let hasStreamProgress = false;
|
|
2334
2414
|
const updateStreamingMessage = (partial, opts) => {
|
|
@@ -2421,7 +2501,7 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2421
2501
|
liveToolUpdatesRef.current.push(update);
|
|
2422
2502
|
}
|
|
2423
2503
|
};
|
|
2424
|
-
const finalizeActiveAssistantTurn = (finalAnswer) => {
|
|
2504
|
+
const finalizeActiveAssistantTurn = (finalAnswer, llmAttemptId) => {
|
|
2425
2505
|
if (!streamStillOwnsVisibleThread()) return;
|
|
2426
2506
|
setMessages((prev) => {
|
|
2427
2507
|
const currentIdx = prev.findIndex((message2) => message2.id === currentAssistantId && message2.role === "assistant");
|
|
@@ -2435,8 +2515,15 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2435
2515
|
})();
|
|
2436
2516
|
if (fallbackIdx < 0) return prev;
|
|
2437
2517
|
const message = prev[fallbackIdx];
|
|
2438
|
-
const
|
|
2439
|
-
|
|
2518
|
+
const correlatedMessage = llmAttemptId ? {
|
|
2519
|
+
...message,
|
|
2520
|
+
metadata: {
|
|
2521
|
+
...message.metadata ?? {},
|
|
2522
|
+
[LLM_ATTEMPT_ID_METADATA_KEY]: llmAttemptId
|
|
2523
|
+
}
|
|
2524
|
+
} : message;
|
|
2525
|
+
const nextMessage = finalizeAssistantMessage(correlatedMessage, finalAnswer);
|
|
2526
|
+
if (message.content === nextMessage.content && message.isStreaming === nextMessage.isStreaming && message.isComplete === nextMessage.isComplete && message.activity === nextMessage.activity && message.metadata === nextMessage.metadata) {
|
|
2440
2527
|
return prev;
|
|
2441
2528
|
}
|
|
2442
2529
|
const updated = [...prev];
|
|
@@ -2545,7 +2632,7 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2545
2632
|
}
|
|
2546
2633
|
if (type === "LLM_RESULT") {
|
|
2547
2634
|
const finalAnswer = typeof payload?.answer === "string" ? payload.answer : void 0;
|
|
2548
|
-
finalizeActiveAssistantTurn(finalAnswer);
|
|
2635
|
+
finalizeActiveAssistantTurn(finalAnswer, getLlmAttemptId(event));
|
|
2549
2636
|
if (isTerminalEmptyLlmResultEvent(event)) {
|
|
2550
2637
|
finalizeStreamingPlaceholders();
|
|
2551
2638
|
}
|
|
@@ -2724,16 +2811,23 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2724
2811
|
}
|
|
2725
2812
|
const conversationKey = threadIdForSend ?? effectiveThreadExternalId;
|
|
2726
2813
|
const sendOwnerThreadExternalId = effectiveThreadExternalId ?? curThreadExtId;
|
|
2727
|
-
const stillShowingSendOwnerThread = () =>
|
|
2814
|
+
const stillShowingSendOwnerThread = () => isSameThreadIdentity(
|
|
2815
|
+
{ id: sendOwnerThreadId, externalId: sendOwnerThreadExternalId },
|
|
2816
|
+
{ id: currentThreadIdRef.current, externalId: currentThreadExternalIdRef.current }
|
|
2817
|
+
);
|
|
2728
2818
|
const currentMetadata = threadMetadataMapRef.current[conversationKey];
|
|
2729
2819
|
const pendingTitle = currentMetadata?.pendingTitle;
|
|
2820
|
+
const userMessageId = generateId();
|
|
2730
2821
|
const userMessage = {
|
|
2731
|
-
id:
|
|
2822
|
+
id: userMessageId,
|
|
2732
2823
|
role: "user",
|
|
2733
2824
|
content,
|
|
2734
2825
|
timestamp,
|
|
2735
2826
|
attachments: attachments.length > 0 ? attachments : void 0,
|
|
2736
2827
|
isComplete: true,
|
|
2828
|
+
metadata: {
|
|
2829
|
+
[CLIENT_MESSAGE_ID_METADATA_KEY]: userMessageId
|
|
2830
|
+
},
|
|
2737
2831
|
sender: resolveUserSender({
|
|
2738
2832
|
id: userId,
|
|
2739
2833
|
name: getCurrentUserDisplayName(userName, userId)
|
|
@@ -2782,6 +2876,7 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2782
2876
|
userId,
|
|
2783
2877
|
userName: getCurrentUserDisplayName(userName, userId),
|
|
2784
2878
|
agentName: preferredAgentRef.current,
|
|
2879
|
+
metadata: userMessage.metadata,
|
|
2785
2880
|
assistantMessageId: assistantPlaceholder.id,
|
|
2786
2881
|
assistantSender,
|
|
2787
2882
|
preserveActiveRun,
|