@copilotz/chat-adapter 0.7.1 → 0.7.3
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 +6 -2
- package/dist/index.js +652 -378
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -424,10 +424,17 @@ async function runCopilotzStream(options) {
|
|
|
424
424
|
let buffer = "";
|
|
425
425
|
let aggregatedText = "";
|
|
426
426
|
let aggregatedReasoning = "";
|
|
427
|
+
let lastCompletedText = "";
|
|
427
428
|
let lastTokenWasReasoning = false;
|
|
428
429
|
let hadNonReasoningContent = false;
|
|
429
430
|
const collectedMessages = [];
|
|
430
431
|
let collectedMedia = null;
|
|
432
|
+
const resetTokenAggregation = () => {
|
|
433
|
+
aggregatedText = "";
|
|
434
|
+
aggregatedReasoning = "";
|
|
435
|
+
lastTokenWasReasoning = false;
|
|
436
|
+
hadNonReasoningContent = false;
|
|
437
|
+
};
|
|
431
438
|
const processEvent = (eventChunk) => {
|
|
432
439
|
if (!eventChunk.trim()) return;
|
|
433
440
|
const lines = eventChunk.split("\n");
|
|
@@ -475,6 +482,12 @@ async function runCopilotzStream(options) {
|
|
|
475
482
|
if (chunk || isComplete) {
|
|
476
483
|
const tokenText = isReasoning ? aggregatedReasoning : aggregatedText;
|
|
477
484
|
onToken?.(tokenText, isComplete, payload2, { isReasoning });
|
|
485
|
+
if (isComplete) {
|
|
486
|
+
if (!isReasoning && tokenText) {
|
|
487
|
+
lastCompletedText = tokenText;
|
|
488
|
+
}
|
|
489
|
+
resetTokenAggregation();
|
|
490
|
+
}
|
|
478
491
|
}
|
|
479
492
|
break;
|
|
480
493
|
}
|
|
@@ -493,8 +506,11 @@ async function runCopilotzStream(options) {
|
|
|
493
506
|
}
|
|
494
507
|
case "TOOL_RESULT":
|
|
495
508
|
case "LLM_RESULT": {
|
|
496
|
-
|
|
497
|
-
|
|
509
|
+
const resultAnswer = typeof payload2?.payload?.answer === "string" ? payload2.payload.answer : typeof payload2?.answer === "string" ? payload2.answer : void 0;
|
|
510
|
+
if (resultAnswer) {
|
|
511
|
+
lastCompletedText = resultAnswer;
|
|
512
|
+
}
|
|
513
|
+
resetTokenAggregation();
|
|
498
514
|
onMessageEvent?.(payload2);
|
|
499
515
|
break;
|
|
500
516
|
}
|
|
@@ -540,7 +556,7 @@ async function runCopilotzStream(options) {
|
|
|
540
556
|
processEvent(buffer);
|
|
541
557
|
}
|
|
542
558
|
return {
|
|
543
|
-
text: aggregatedText,
|
|
559
|
+
text: lastCompletedText || aggregatedText,
|
|
544
560
|
messages: collectedMessages,
|
|
545
561
|
media: collectedMedia
|
|
546
562
|
};
|
|
@@ -672,64 +688,6 @@ async function deleteThread(threadId, getRequestHeaders) {
|
|
|
672
688
|
return true;
|
|
673
689
|
}
|
|
674
690
|
|
|
675
|
-
// src/assetsService.ts
|
|
676
|
-
var rawBaseValue2 = import.meta.env?.VITE_API_URL;
|
|
677
|
-
var rawBase2 = typeof rawBaseValue2 === "string" && rawBaseValue2.length > 0 ? rawBaseValue2 : "/api";
|
|
678
|
-
var normalizedBase2 = rawBase2.replace(/\/$/, "");
|
|
679
|
-
var API_BASE2 = normalizedBase2.startsWith("http") || normalizedBase2.startsWith("/") ? normalizedBase2 : `/${normalizedBase2}`;
|
|
680
|
-
var apiUrl2 = (path) => `${API_BASE2}${path}`;
|
|
681
|
-
var extractAssetId = (refOrId) => refOrId.startsWith("asset://") ? refOrId.slice("asset://".length) : refOrId;
|
|
682
|
-
async function getAssetDataUrl(refOrId) {
|
|
683
|
-
const id = extractAssetId(refOrId);
|
|
684
|
-
const res = await fetch(apiUrl2(`/v1/assets/${encodeURIComponent(id)}?format=dataUrl`), {
|
|
685
|
-
method: "GET",
|
|
686
|
-
headers: { Accept: "application/json" }
|
|
687
|
-
});
|
|
688
|
-
if (!res.ok) {
|
|
689
|
-
const text = await res.text().catch(() => res.statusText);
|
|
690
|
-
throw new Error(text || `Failed to fetch asset ${refOrId}`);
|
|
691
|
-
}
|
|
692
|
-
const body = await res.json();
|
|
693
|
-
const data = body?.data ?? body;
|
|
694
|
-
if (!data?.dataUrl) {
|
|
695
|
-
throw new Error(data?.error || `Asset ${refOrId} has no dataUrl`);
|
|
696
|
-
}
|
|
697
|
-
return { dataUrl: data.dataUrl, mime: data.mime, assetId: data.assetId };
|
|
698
|
-
}
|
|
699
|
-
async function resolveAssetsInMessages(messages) {
|
|
700
|
-
const inFlightByRef = /* @__PURE__ */ new Map();
|
|
701
|
-
const resolveAssetRef = (assetRef) => {
|
|
702
|
-
if (!inFlightByRef.has(assetRef)) {
|
|
703
|
-
inFlightByRef.set(assetRef, getAssetDataUrl(assetRef));
|
|
704
|
-
}
|
|
705
|
-
return inFlightByRef.get(assetRef);
|
|
706
|
-
};
|
|
707
|
-
return Promise.all(messages.map(async (msg) => {
|
|
708
|
-
const meta = msg.metadata ?? void 0;
|
|
709
|
-
const attachments = Array.isArray(meta?.attachments) ? meta.attachments : void 0;
|
|
710
|
-
if (!attachments || attachments.length === 0) {
|
|
711
|
-
return msg;
|
|
712
|
-
}
|
|
713
|
-
const newAttachments = await Promise.all(attachments.map(async (att) => {
|
|
714
|
-
const assetRef = typeof att?.assetRef === "string" ? att.assetRef : void 0;
|
|
715
|
-
if (!assetRef) return att;
|
|
716
|
-
try {
|
|
717
|
-
const { dataUrl, mime } = await resolveAssetRef(assetRef);
|
|
718
|
-
const kind = typeof att.kind === "string" ? att.kind : "image";
|
|
719
|
-
return {
|
|
720
|
-
kind,
|
|
721
|
-
dataUrl,
|
|
722
|
-
mimeType: typeof att.mimeType === "string" ? att.mimeType : mime ?? void 0
|
|
723
|
-
};
|
|
724
|
-
} catch {
|
|
725
|
-
return att;
|
|
726
|
-
}
|
|
727
|
-
}));
|
|
728
|
-
const newMeta = { ...meta ?? {}, attachments: newAttachments };
|
|
729
|
-
return { ...msg, metadata: newMeta };
|
|
730
|
-
}));
|
|
731
|
-
}
|
|
732
|
-
|
|
733
691
|
// src/useUrlState.ts
|
|
734
692
|
import { useState, useEffect, useCallback, useRef } from "react";
|
|
735
693
|
var DEFAULT_PARAMS = {
|
|
@@ -835,194 +793,397 @@ function useUrlState(config = {}) {
|
|
|
835
793
|
}
|
|
836
794
|
|
|
837
795
|
// src/activity.ts
|
|
838
|
-
var
|
|
796
|
+
var thinkingId = "thinking";
|
|
797
|
+
var answeringId = "answering";
|
|
798
|
+
var getItems = (message) => Array.isArray(message.activity?.items) ? message.activity.items : [];
|
|
799
|
+
var setItems = (message, items) => ({
|
|
800
|
+
...message,
|
|
801
|
+
activity: items.length > 0 ? { items } : void 0
|
|
802
|
+
});
|
|
803
|
+
var toolStatusToActivityStatus = (status) => {
|
|
804
|
+
if (status === "failed") return "failed";
|
|
805
|
+
if (status === "completed") return "complete";
|
|
806
|
+
return "active";
|
|
807
|
+
};
|
|
808
|
+
var upsertItem = (message, item) => {
|
|
809
|
+
const items = getItems(message);
|
|
810
|
+
const index = items.findIndex((current) => current.id === item.id);
|
|
811
|
+
if (index === -1) return setItems(message, [...items, item]);
|
|
812
|
+
const next = [...items];
|
|
813
|
+
next[index] = {
|
|
814
|
+
...next[index],
|
|
815
|
+
...item,
|
|
816
|
+
details: {
|
|
817
|
+
...next[index].details ?? {},
|
|
818
|
+
...item.details ?? {}
|
|
819
|
+
}
|
|
820
|
+
};
|
|
821
|
+
return setItems(message, next);
|
|
822
|
+
};
|
|
823
|
+
var completeItems = (message, shouldComplete) => setItems(message, getItems(message).map((item) => item.status === "active" && shouldComplete(item) ? { ...item, status: "complete", completedAt: Date.now() } : item));
|
|
839
824
|
var hasVisibleAssistantOutput = (message) => {
|
|
840
825
|
if (message.role !== "assistant") return false;
|
|
841
826
|
if (typeof message.content === "string" && message.content.trim().length > 0) return true;
|
|
842
827
|
if (Array.isArray(message.attachments) && message.attachments.length > 0) return true;
|
|
843
|
-
|
|
844
|
-
return false;
|
|
845
|
-
};
|
|
846
|
-
var buildAssistantActivity = (message) => {
|
|
847
|
-
const toolCalls = Array.isArray(message._activityToolCalls) ? message._activityToolCalls : [];
|
|
848
|
-
const hasReasoning = typeof message._activityReasoning === "string" && message._activityReasoning.length > 0;
|
|
849
|
-
const hasToolCalls = toolCalls.length > 0;
|
|
850
|
-
const runningTools = toolCalls.filter(isToolCallActive);
|
|
851
|
-
const hasRunningTools = runningTools.length > 0;
|
|
852
|
-
const isStreaming = message.isStreaming === true;
|
|
853
|
-
const isReasoningStreaming = message._activityReasoningStreaming === true;
|
|
854
|
-
const hasContent = typeof message.content === "string" && message.content.trim().length > 0;
|
|
855
|
-
if (!hasReasoning && !hasToolCalls && !isStreaming && !isReasoningStreaming) {
|
|
856
|
-
return void 0;
|
|
857
|
-
}
|
|
858
|
-
const isActive = isStreaming || isReasoningStreaming || hasRunningTools;
|
|
859
|
-
const summary = hasRunningTools ? {
|
|
860
|
-
kind: "using_tools",
|
|
861
|
-
...runningTools.length === 1 ? { toolName: runningTools[0].name } : {},
|
|
862
|
-
...runningTools.length > 1 ? { toolCount: runningTools.length } : {}
|
|
863
|
-
} : isStreaming && hasToolCalls && !hasContent ? {
|
|
864
|
-
kind: "using_tools",
|
|
865
|
-
...toolCalls.length === 1 ? { toolName: toolCalls[0].name } : {},
|
|
866
|
-
...toolCalls.length > 1 ? { toolCount: toolCalls.length } : {}
|
|
867
|
-
} : isReasoningStreaming || !hasContent && hasReasoning ? { kind: "thinking" } : isStreaming && hasContent ? { kind: "preparing_answer" } : isStreaming ? { kind: "working" } : hasToolCalls ? {
|
|
868
|
-
kind: "using_tools",
|
|
869
|
-
...toolCalls.length === 1 ? { toolName: toolCalls[0].name } : {},
|
|
870
|
-
...toolCalls.length > 1 ? { toolCount: toolCalls.length } : {}
|
|
871
|
-
} : { kind: "thinking" };
|
|
872
|
-
return {
|
|
873
|
-
isActive,
|
|
874
|
-
...isActive ? {} : { isComplete: true },
|
|
875
|
-
summary,
|
|
876
|
-
...hasReasoning ? { reasoning: message._activityReasoning } : {},
|
|
877
|
-
...hasToolCalls ? { toolCalls } : {}
|
|
878
|
-
};
|
|
879
|
-
};
|
|
880
|
-
var syncAssistantActivity = (message) => {
|
|
881
|
-
if (message.role !== "assistant") {
|
|
882
|
-
const { _activityReasoning, _activityReasoningStreaming, _activityToolCalls, ...rest } = message;
|
|
883
|
-
return rest;
|
|
884
|
-
}
|
|
885
|
-
return {
|
|
886
|
-
...message,
|
|
887
|
-
activity: buildAssistantActivity(message)
|
|
888
|
-
};
|
|
828
|
+
return getItems(message).length > 0;
|
|
889
829
|
};
|
|
890
830
|
var toPublicChatMessage = (message) => {
|
|
891
|
-
|
|
831
|
+
if (message.role === "assistant") return message;
|
|
832
|
+
const { activity, ...rest } = message;
|
|
892
833
|
return rest;
|
|
893
834
|
};
|
|
894
835
|
var updateAssistantMessageToken = (message, params) => {
|
|
895
836
|
if (message.role !== "assistant") return message;
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
837
|
+
if (params.isReasoning) {
|
|
838
|
+
return upsertItem({
|
|
839
|
+
...message,
|
|
840
|
+
isStreaming: true,
|
|
841
|
+
isComplete: false
|
|
842
|
+
}, {
|
|
843
|
+
id: thinkingId,
|
|
844
|
+
kind: "thinking",
|
|
845
|
+
status: "active",
|
|
846
|
+
startedAt: getItems(message).find((item) => item.id === thinkingId)?.startedAt ?? Date.now(),
|
|
847
|
+
details: { reasoning: params.partial }
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
return upsertItem(completeItems({
|
|
904
851
|
...message,
|
|
905
|
-
...params.agentIdentity,
|
|
906
852
|
content: params.partial,
|
|
907
|
-
_activityReasoningStreaming: false,
|
|
908
853
|
isStreaming: true,
|
|
909
854
|
isComplete: false
|
|
910
|
-
}
|
|
911
|
-
|
|
855
|
+
}, (item) => item.kind === "thinking" || item.kind === "tool"), {
|
|
856
|
+
id: answeringId,
|
|
857
|
+
kind: "answering",
|
|
858
|
+
status: "active",
|
|
859
|
+
startedAt: getItems(message).find((item) => item.id === answeringId)?.startedAt ?? Date.now()
|
|
860
|
+
});
|
|
912
861
|
};
|
|
913
862
|
var appendAssistantToolCall = (message, toolCall) => {
|
|
914
863
|
if (message.role !== "assistant") return message;
|
|
915
|
-
|
|
864
|
+
const status = toolStatusToActivityStatus(toolCall.status);
|
|
865
|
+
return upsertItem({
|
|
916
866
|
...message,
|
|
917
|
-
_activityToolCalls: [
|
|
918
|
-
...Array.isArray(message._activityToolCalls) ? message._activityToolCalls : [],
|
|
919
|
-
toolCall
|
|
920
|
-
],
|
|
921
867
|
isStreaming: true,
|
|
922
868
|
isComplete: false
|
|
869
|
+
}, {
|
|
870
|
+
id: toolCall.id,
|
|
871
|
+
kind: "tool",
|
|
872
|
+
status,
|
|
873
|
+
toolName: toolCall.name,
|
|
874
|
+
startedAt: toolCall.startTime ?? Date.now(),
|
|
875
|
+
...status !== "active" ? { completedAt: toolCall.endTime ?? Date.now() } : {},
|
|
876
|
+
details: {
|
|
877
|
+
toolCall,
|
|
878
|
+
...toolCall.result !== void 0 ? { result: toolCall.result } : {}
|
|
879
|
+
}
|
|
923
880
|
});
|
|
924
881
|
};
|
|
925
882
|
var applyAssistantToolResult = (message, update) => {
|
|
926
883
|
if (message.role !== "assistant") return message;
|
|
927
|
-
const
|
|
928
|
-
const
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
...
|
|
939
|
-
|
|
940
|
-
|
|
884
|
+
const items = getItems(message);
|
|
885
|
+
const index = items.findIndex((item2) => item2.kind === "tool" && (update.id && item2.id === update.id || !update.id && item2.toolName === update.name));
|
|
886
|
+
if (index === -1) return message;
|
|
887
|
+
const item = items[index];
|
|
888
|
+
const toolCall = item.details?.toolCall;
|
|
889
|
+
const nextToolCall = toolCall ? { ...toolCall, ...update } : {
|
|
890
|
+
id: update.id ?? item.id,
|
|
891
|
+
name: update.name,
|
|
892
|
+
arguments: {},
|
|
893
|
+
status: update.status,
|
|
894
|
+
...update.result !== void 0 ? { result: update.result } : {},
|
|
895
|
+
...update.endTime !== void 0 ? { endTime: update.endTime } : {}
|
|
896
|
+
};
|
|
897
|
+
const status = toolStatusToActivityStatus(update.status);
|
|
898
|
+
const next = [...items];
|
|
899
|
+
next[index] = {
|
|
900
|
+
...item,
|
|
901
|
+
status,
|
|
902
|
+
toolName: update.name,
|
|
903
|
+
...status !== "active" ? { completedAt: update.endTime ?? Date.now() } : {},
|
|
904
|
+
details: {
|
|
905
|
+
...item.details ?? {},
|
|
906
|
+
toolCall: nextToolCall,
|
|
907
|
+
...update.result !== void 0 ? { result: update.result } : {}
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
return setItems(message, next);
|
|
941
911
|
};
|
|
942
912
|
var finalizeAssistantMessage = (message, finalAnswer) => {
|
|
943
913
|
if (message.role !== "assistant") return message;
|
|
944
|
-
|
|
914
|
+
const completed = completeItems({
|
|
945
915
|
...message,
|
|
946
916
|
...typeof finalAnswer === "string" && finalAnswer.length > 0 ? { content: finalAnswer } : {},
|
|
947
917
|
isStreaming: false,
|
|
948
|
-
isComplete: true
|
|
949
|
-
|
|
950
|
-
|
|
918
|
+
isComplete: true
|
|
919
|
+
}, (item) => item.kind === "thinking" || item.kind === "answering");
|
|
920
|
+
return setItems(completed, getItems(completed).filter((item) => item.kind !== "answering"));
|
|
951
921
|
};
|
|
952
922
|
var closeAssistantMessage = (message) => {
|
|
953
923
|
if (message.role !== "assistant") return message;
|
|
954
|
-
return
|
|
924
|
+
return completeItems({
|
|
955
925
|
...message,
|
|
956
926
|
isStreaming: false,
|
|
957
|
-
isComplete: true
|
|
958
|
-
|
|
959
|
-
});
|
|
927
|
+
isComplete: true
|
|
928
|
+
}, () => true);
|
|
960
929
|
};
|
|
961
930
|
|
|
962
|
-
// src/
|
|
963
|
-
var
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
var isInternalMessageMetadata = (metadata) => metadata?.visibility === "internal";
|
|
969
|
-
var normalizeAgentIdentity = (agent) => {
|
|
970
|
-
const senderAgentId = typeof agent?.id === "string" && agent.id.length > 0 ? agent.id : void 0;
|
|
971
|
-
const senderName = typeof agent?.name === "string" && agent.name.length > 0 ? agent.name : senderAgentId;
|
|
972
|
-
return {
|
|
973
|
-
...senderAgentId ? { senderAgentId } : {},
|
|
974
|
-
...senderName ? { senderName } : {}
|
|
975
|
-
};
|
|
931
|
+
// src/contract.ts
|
|
932
|
+
var ContractViolation = class extends Error {
|
|
933
|
+
constructor(message) {
|
|
934
|
+
super(message);
|
|
935
|
+
this.name = "ContractViolation";
|
|
936
|
+
}
|
|
976
937
|
};
|
|
977
|
-
var
|
|
978
|
-
|
|
979
|
-
|
|
938
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
939
|
+
var expectRecord = (value, path) => {
|
|
940
|
+
if (!isRecord(value)) throw new ContractViolation(`${path} must be an object`);
|
|
941
|
+
return value;
|
|
942
|
+
};
|
|
943
|
+
var expectString = (value, path) => {
|
|
944
|
+
if (typeof value !== "string" || value.trim().length === 0) throw new ContractViolation(`${path} must be a non-empty string`);
|
|
945
|
+
return value;
|
|
946
|
+
};
|
|
947
|
+
var expectOptionalString = (value, path) => {
|
|
948
|
+
if (value === void 0 || value === null) return void 0;
|
|
949
|
+
return expectString(value, path);
|
|
950
|
+
};
|
|
951
|
+
var expectStringValue = (value, path) => {
|
|
952
|
+
if (typeof value !== "string") throw new ContractViolation(`${path} must be a string`);
|
|
953
|
+
return value;
|
|
954
|
+
};
|
|
955
|
+
|
|
956
|
+
// src/senders.ts
|
|
957
|
+
var clean = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
958
|
+
var expectSenderType = (value, path) => {
|
|
959
|
+
if (value === "user" || value === "agent" || value === "tool" || value === "system") return value;
|
|
960
|
+
throw new ContractViolation(`${path} must be user, agent, tool, or system`);
|
|
961
|
+
};
|
|
962
|
+
var defined = (value) => Object.fromEntries(
|
|
963
|
+
Object.entries(value).filter(([, entry]) => entry !== void 0)
|
|
964
|
+
);
|
|
965
|
+
var findAgent = (agents, ...candidates) => {
|
|
966
|
+
const values = candidates.filter(Boolean).map((value) => value.toLowerCase());
|
|
967
|
+
if (!agents || values.length === 0) return void 0;
|
|
968
|
+
return agents.find(
|
|
969
|
+
(agent) => values.includes(agent.id.toLowerCase()) || values.includes(agent.name.toLowerCase())
|
|
970
|
+
);
|
|
980
971
|
};
|
|
981
|
-
var
|
|
982
|
-
|
|
983
|
-
|
|
972
|
+
var fromAgent = (agent, overrides = {}) => defined({
|
|
973
|
+
type: overrides.type ?? "agent",
|
|
974
|
+
id: agent.id,
|
|
975
|
+
name: agent.name,
|
|
976
|
+
agentId: agent.id,
|
|
977
|
+
avatarUrl: agent.avatarUrl,
|
|
978
|
+
color: agent.color,
|
|
979
|
+
...overrides
|
|
980
|
+
});
|
|
981
|
+
var resolveUserSender = (user) => defined({
|
|
982
|
+
type: "user",
|
|
983
|
+
id: user.id,
|
|
984
|
+
externalId: user.id,
|
|
985
|
+
name: clean(user.name) ?? user.id,
|
|
986
|
+
avatarUrl: clean(user.avatarUrl)
|
|
987
|
+
});
|
|
988
|
+
var resolveAssistantFallbackSender = (options = {}) => ({
|
|
989
|
+
type: "agent",
|
|
990
|
+
id: "assistant",
|
|
991
|
+
name: clean(options.assistantName) ?? "Assistant",
|
|
992
|
+
agentId: "assistant"
|
|
993
|
+
});
|
|
994
|
+
var resolveAgentSender = (identity, options = {}, overrides = {}) => {
|
|
995
|
+
const id = expectString(identity.id, "agent.id");
|
|
996
|
+
const name = expectString(identity.name, "agent.name");
|
|
997
|
+
const agent = findAgent(options.agents, id, name);
|
|
984
998
|
if (agent) {
|
|
985
|
-
return
|
|
999
|
+
return fromAgent(agent, defined({
|
|
1000
|
+
...overrides,
|
|
1001
|
+
externalId: id && id !== agent.id ? id : void 0
|
|
1002
|
+
}));
|
|
986
1003
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
id
|
|
990
|
-
name
|
|
1004
|
+
return defined({
|
|
1005
|
+
type: overrides.type ?? "agent",
|
|
1006
|
+
id,
|
|
1007
|
+
name,
|
|
1008
|
+
agentId: id,
|
|
1009
|
+
...overrides
|
|
991
1010
|
});
|
|
992
1011
|
};
|
|
993
|
-
var
|
|
994
|
-
|
|
995
|
-
|
|
1012
|
+
var resolveHydratedMessageSender = (message, options = {}) => {
|
|
1013
|
+
const metadata = message.metadata ? expectRecord(message.metadata, "message.metadata") : {};
|
|
1014
|
+
const type = expectSenderType(message.senderType, "message.senderType");
|
|
1015
|
+
const storedId = expectOptionalString(message.senderId, "message.senderId");
|
|
1016
|
+
const participantId = expectOptionalString(metadata.senderParticipantId, "message.metadata.senderParticipantId") ?? expectOptionalString(message.senderUserId, "message.senderUserId");
|
|
1017
|
+
const externalId = expectString(metadata.senderExternalId, "message.metadata.senderExternalId");
|
|
1018
|
+
const displayName = expectString(metadata.senderDisplayName, "message.metadata.senderDisplayName");
|
|
1019
|
+
if (type === "agent" || type === "tool") {
|
|
1020
|
+
const agent = findAgent(options.agents, externalId, displayName, storedId);
|
|
1021
|
+
if (agent) {
|
|
1022
|
+
return fromAgent(agent, defined({
|
|
1023
|
+
type,
|
|
1024
|
+
participantId: participantId ?? storedId,
|
|
1025
|
+
externalId: externalId && externalId !== agent.id ? externalId : void 0
|
|
1026
|
+
}));
|
|
1027
|
+
}
|
|
1028
|
+
return defined({
|
|
1029
|
+
type,
|
|
1030
|
+
id: externalId,
|
|
1031
|
+
name: displayName,
|
|
1032
|
+
agentId: externalId,
|
|
1033
|
+
participantId: participantId ?? storedId,
|
|
1034
|
+
externalId
|
|
1035
|
+
});
|
|
996
1036
|
}
|
|
997
|
-
|
|
998
|
-
|
|
1037
|
+
if (type === "user") {
|
|
1038
|
+
return defined({
|
|
1039
|
+
type: "user",
|
|
1040
|
+
id: externalId,
|
|
1041
|
+
externalId,
|
|
1042
|
+
name: displayName,
|
|
1043
|
+
avatarUrl: clean(options.user?.avatarUrl),
|
|
1044
|
+
participantId: participantId ?? storedId
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
return defined({
|
|
1048
|
+
type: "system",
|
|
1049
|
+
id: externalId,
|
|
1050
|
+
name: displayName,
|
|
1051
|
+
participantId: participantId ?? storedId,
|
|
1052
|
+
externalId
|
|
1053
|
+
});
|
|
999
1054
|
};
|
|
1000
|
-
var
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1055
|
+
var resolveLiveEventSender = (event, options = {}) => {
|
|
1056
|
+
const raw = expectRecord(event, "stream event");
|
|
1057
|
+
const payload = raw.payload === void 0 ? raw : expectRecord(raw.payload, "stream event.payload");
|
|
1058
|
+
const agent = payload.agent ?? raw.agent;
|
|
1059
|
+
if (isRecord(agent)) {
|
|
1060
|
+
return resolveAgentSender({
|
|
1061
|
+
id: expectString(agent.id, "stream event.payload.agent.id"),
|
|
1062
|
+
name: expectString(agent.name, "stream event.payload.agent.name")
|
|
1063
|
+
}, options);
|
|
1064
|
+
}
|
|
1065
|
+
const sender = payload.sender ?? raw.sender;
|
|
1066
|
+
if (!isRecord(sender)) {
|
|
1067
|
+
throw new ContractViolation("stream event sender contract requires payload.agent or payload.sender");
|
|
1068
|
+
}
|
|
1069
|
+
const type = expectSenderType(sender.type ?? payload.senderType, "stream event.payload.sender.type");
|
|
1070
|
+
if (type !== "user") {
|
|
1071
|
+
return resolveAgentSender({
|
|
1072
|
+
id: expectString(sender.id ?? sender.externalId, "stream event.payload.sender.id"),
|
|
1073
|
+
name: expectString(sender.name, "stream event.payload.sender.name")
|
|
1074
|
+
}, options, { type });
|
|
1075
|
+
}
|
|
1076
|
+
if (!options.user) {
|
|
1077
|
+
throw new ContractViolation("user stream sender requires current user context");
|
|
1078
|
+
}
|
|
1079
|
+
return resolveUserSender(options.user);
|
|
1080
|
+
};
|
|
1081
|
+
|
|
1082
|
+
// src/assetsService.ts
|
|
1083
|
+
var ContractViolation2 = class extends Error {
|
|
1084
|
+
name = "ContractViolation";
|
|
1085
|
+
};
|
|
1086
|
+
var expectRecord2 = (value, path) => {
|
|
1087
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) return value;
|
|
1088
|
+
throw new ContractViolation2(`${path} must be an object`);
|
|
1089
|
+
};
|
|
1090
|
+
var expectString2 = (value, path) => {
|
|
1091
|
+
if (typeof value === "string" && value.trim().length > 0) return value;
|
|
1092
|
+
throw new ContractViolation2(`${path} must be a non-empty string`);
|
|
1093
|
+
};
|
|
1094
|
+
var rawBaseValue2 = import.meta.env?.VITE_API_URL;
|
|
1095
|
+
var rawBase2 = typeof rawBaseValue2 === "string" && rawBaseValue2.length > 0 ? rawBaseValue2 : "/api";
|
|
1096
|
+
var normalizedBase2 = rawBase2.replace(/\/$/, "");
|
|
1097
|
+
var API_BASE2 = normalizedBase2.startsWith("http") || normalizedBase2.startsWith("/") ? normalizedBase2 : `/${normalizedBase2}`;
|
|
1098
|
+
var apiUrl2 = (path) => `${API_BASE2}${path}`;
|
|
1099
|
+
var extractAssetId = (refOrId) => refOrId.startsWith("asset://") ? refOrId.slice("asset://".length) : refOrId;
|
|
1100
|
+
async function getAssetDataUrl(refOrId) {
|
|
1101
|
+
const id = extractAssetId(refOrId);
|
|
1102
|
+
const res = await fetch(apiUrl2(`/v1/assets/${encodeURIComponent(id)}?format=dataUrl`), {
|
|
1103
|
+
method: "GET",
|
|
1104
|
+
headers: { Accept: "application/json" }
|
|
1105
|
+
});
|
|
1106
|
+
if (!res.ok) {
|
|
1107
|
+
const text = await res.text().catch(() => res.statusText);
|
|
1108
|
+
throw new Error(text || `Failed to fetch asset ${refOrId}`);
|
|
1109
|
+
}
|
|
1110
|
+
const body = await res.json();
|
|
1111
|
+
const envelope = expectRecord2(body, "asset response");
|
|
1112
|
+
const data = expectRecord2(envelope.data, "asset response.data");
|
|
1113
|
+
if (typeof data.error === "string" && data.error.length > 0) {
|
|
1114
|
+
throw new Error(data.error);
|
|
1115
|
+
}
|
|
1116
|
+
if (typeof data.dataUrl !== "string" || data.dataUrl.length === 0) {
|
|
1117
|
+
throw new ContractViolation2(`asset response.data.dataUrl is required for ${refOrId}`);
|
|
1118
|
+
}
|
|
1119
|
+
return {
|
|
1120
|
+
dataUrl: data.dataUrl,
|
|
1121
|
+
mime: typeof data.mime === "string" ? data.mime : void 0,
|
|
1122
|
+
assetId: expectString2(data.assetId, "asset response.data.assetId")
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
async function resolveAssetsInMessages(messages) {
|
|
1126
|
+
const inFlightByRef = /* @__PURE__ */ new Map();
|
|
1127
|
+
const resolveAssetRef = (assetRef) => {
|
|
1128
|
+
if (!inFlightByRef.has(assetRef)) {
|
|
1129
|
+
inFlightByRef.set(assetRef, getAssetDataUrl(assetRef));
|
|
1130
|
+
}
|
|
1131
|
+
return inFlightByRef.get(assetRef);
|
|
1132
|
+
};
|
|
1133
|
+
return Promise.all(messages.map(async (msg) => {
|
|
1134
|
+
const meta = msg.metadata === null || msg.metadata === void 0 ? void 0 : expectRecord2(msg.metadata, "message.metadata");
|
|
1135
|
+
const attachments = meta?.attachments === void 0 ? void 0 : Array.isArray(meta.attachments) ? meta.attachments.map(
|
|
1136
|
+
(att, index) => expectRecord2(att, `message.metadata.attachments[${index}]`)
|
|
1137
|
+
) : (() => {
|
|
1138
|
+
throw new ContractViolation2("message.metadata.attachments must be an array");
|
|
1139
|
+
})();
|
|
1140
|
+
if (!attachments || attachments.length === 0) {
|
|
1141
|
+
return msg;
|
|
1142
|
+
}
|
|
1143
|
+
const newAttachments = await Promise.all(attachments.map(async (att, index) => {
|
|
1144
|
+
const assetRef = typeof att.assetRef === "string" ? att.assetRef : void 0;
|
|
1145
|
+
if (!assetRef) return att;
|
|
1146
|
+
const { dataUrl, mime } = await resolveAssetRef(assetRef);
|
|
1147
|
+
const kind = expectString2(att.kind, `message.metadata.attachments[${index}].kind`);
|
|
1148
|
+
const mimeType = typeof att.mimeType === "string" ? att.mimeType : expectString2(mime, `asset ${assetRef}.mime`);
|
|
1149
|
+
return {
|
|
1150
|
+
...att,
|
|
1151
|
+
kind,
|
|
1152
|
+
dataUrl,
|
|
1153
|
+
mimeType
|
|
1154
|
+
};
|
|
1155
|
+
}));
|
|
1156
|
+
const newMeta = { ...meta, attachments: newAttachments };
|
|
1157
|
+
return { ...msg, metadata: newMeta };
|
|
1158
|
+
}));
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
// src/toolActivity.ts
|
|
1162
|
+
var fail = (message) => {
|
|
1163
|
+
throw new ContractViolation(message);
|
|
1164
|
+
};
|
|
1165
|
+
var expectToolStatus = (status, path) => {
|
|
1007
1166
|
if (status === "pending") return "pending";
|
|
1008
1167
|
if (status === "running" || status === "processing") return "running";
|
|
1009
1168
|
if (status === "failed") return "failed";
|
|
1010
|
-
return "completed";
|
|
1169
|
+
if (status === "completed") return "completed";
|
|
1170
|
+
return fail(`${path} must be pending, running, processing, completed, or failed`);
|
|
1011
1171
|
};
|
|
1012
|
-
var
|
|
1013
|
-
if (
|
|
1014
|
-
return value;
|
|
1015
|
-
}
|
|
1172
|
+
var expectToolArguments = (value, path) => {
|
|
1173
|
+
if (isRecord(value)) return value;
|
|
1016
1174
|
if (typeof value === "string") {
|
|
1017
1175
|
try {
|
|
1018
1176
|
const parsed = JSON.parse(value);
|
|
1019
|
-
|
|
1020
|
-
return parsed;
|
|
1021
|
-
}
|
|
1177
|
+
return expectRecord(parsed, path);
|
|
1022
1178
|
} catch {
|
|
1179
|
+
return fail(`${path} must be an object or JSON object string`);
|
|
1023
1180
|
}
|
|
1024
1181
|
}
|
|
1025
|
-
return {};
|
|
1182
|
+
return fail(`${path} must be an object or JSON object string`);
|
|
1183
|
+
};
|
|
1184
|
+
var expectToolName = (tool, path) => {
|
|
1185
|
+
const name = typeof tool.name === "string" && tool.name.trim().length > 0 ? tool.name : tool.id;
|
|
1186
|
+
return expectString(name, path);
|
|
1026
1187
|
};
|
|
1027
1188
|
var matchesToolResultUpdate = (target, update) => {
|
|
1028
1189
|
if (update.id && target.id) {
|
|
@@ -1030,92 +1191,84 @@ var matchesToolResultUpdate = (target, update) => {
|
|
|
1030
1191
|
}
|
|
1031
1192
|
return Boolean(update.name && target.name && update.name === target.name);
|
|
1032
1193
|
};
|
|
1033
|
-
var
|
|
1034
|
-
{ id:
|
|
1194
|
+
var findMatchingToolItem = (toolItems, update) => toolItems.find((item) => matchesToolResultUpdate(
|
|
1195
|
+
{ id: item.id, name: item.toolName },
|
|
1035
1196
|
update
|
|
1036
|
-
) && (
|
|
1197
|
+
) && (item.status === "active" || item.details?.result === void 0));
|
|
1037
1198
|
var applyToolResultUpdateToMessages = (messages, update, assistantPatch) => {
|
|
1038
1199
|
const nextMessages = [...messages];
|
|
1039
1200
|
for (let i = nextMessages.length - 1; i >= 0; i--) {
|
|
1040
1201
|
const message = nextMessages[i];
|
|
1041
|
-
|
|
1202
|
+
const toolItems = message.activity?.items.filter((item) => item.kind === "tool") ?? [];
|
|
1203
|
+
if (message.role !== "assistant" || toolItems.length === 0) {
|
|
1042
1204
|
continue;
|
|
1043
1205
|
}
|
|
1044
|
-
const
|
|
1045
|
-
if (
|
|
1046
|
-
nextMessages[i] =
|
|
1206
|
+
const toolItem = findMatchingToolItem(toolItems, update);
|
|
1207
|
+
if (!toolItem) continue;
|
|
1208
|
+
nextMessages[i] = {
|
|
1047
1209
|
...applyAssistantToolResult(message, {
|
|
1048
1210
|
...update.id ? { id: update.id } : {},
|
|
1049
|
-
name: update.name ??
|
|
1211
|
+
name: update.name ?? toolItem.toolName ?? toolItem.id,
|
|
1050
1212
|
status: update.status,
|
|
1051
1213
|
...update.result !== void 0 ? { result: update.result } : {},
|
|
1052
1214
|
endTime: update.endTime
|
|
1053
1215
|
}),
|
|
1054
1216
|
...assistantPatch ?? {}
|
|
1055
|
-
}
|
|
1217
|
+
};
|
|
1056
1218
|
return { messages: nextMessages, matched: true };
|
|
1057
1219
|
}
|
|
1058
1220
|
return { messages, matched: false };
|
|
1059
1221
|
};
|
|
1060
1222
|
var extractLiveToolCall = (payload) => {
|
|
1061
|
-
const
|
|
1062
|
-
|
|
1063
|
-
const tool = toolCall.tool;
|
|
1064
|
-
const name = typeof tool?.name === "string" ? tool.name : typeof tool?.id === "string" ? tool.id : "tool";
|
|
1065
|
-
const result = toolCall.output !== void 0 ? toolCall.output : void 0;
|
|
1223
|
+
const payloadRecord = expectRecord(payload, "TOOL_CALL payload");
|
|
1224
|
+
const toolCall = expectRecord(payloadRecord.toolCall, "TOOL_CALL payload.toolCall");
|
|
1225
|
+
const tool = expectRecord(toolCall.tool, "TOOL_CALL payload.toolCall.tool");
|
|
1066
1226
|
return {
|
|
1067
|
-
|
|
1068
|
-
name,
|
|
1069
|
-
arguments:
|
|
1070
|
-
status:
|
|
1071
|
-
...
|
|
1227
|
+
id: expectString(toolCall.id, "TOOL_CALL payload.toolCall.id"),
|
|
1228
|
+
name: expectToolName(tool, "TOOL_CALL payload.toolCall.tool.id"),
|
|
1229
|
+
arguments: expectToolArguments(toolCall.args, "TOOL_CALL payload.toolCall.args"),
|
|
1230
|
+
status: toolCall.status === void 0 ? "running" : expectToolStatus(toolCall.status, "TOOL_CALL payload.toolCall.status"),
|
|
1231
|
+
...toolCall.output !== void 0 ? { result: toolCall.output } : {}
|
|
1072
1232
|
};
|
|
1073
1233
|
};
|
|
1074
|
-
var extractLiveToolResultUpdate = (payload) => {
|
|
1075
|
-
const
|
|
1076
|
-
const
|
|
1234
|
+
var extractLiveToolResultUpdate = (payload, now = () => Date.now()) => {
|
|
1235
|
+
const payloadRecord = expectRecord(payload, "TOOL_RESULT payload");
|
|
1236
|
+
const tool = expectRecord(payloadRecord.tool, "TOOL_RESULT payload.tool");
|
|
1237
|
+
const result = payloadRecord.projectedOutput !== void 0 ? payloadRecord.projectedOutput : payloadRecord.output;
|
|
1238
|
+
if (result === void 0) fail("TOOL_RESULT payload requires output or projectedOutput");
|
|
1077
1239
|
return {
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
status:
|
|
1081
|
-
|
|
1082
|
-
endTime:
|
|
1240
|
+
id: expectString(payloadRecord.toolCallId, "TOOL_RESULT payload.toolCallId"),
|
|
1241
|
+
name: expectToolName(tool, "TOOL_RESULT payload.tool.id"),
|
|
1242
|
+
status: expectToolStatus(payloadRecord.status, "TOOL_RESULT payload.status"),
|
|
1243
|
+
result,
|
|
1244
|
+
endTime: now()
|
|
1083
1245
|
};
|
|
1084
1246
|
};
|
|
1085
1247
|
var extractToolCallsFromServerMessage = (msg) => {
|
|
1086
|
-
const metadata = msg.metadata
|
|
1087
|
-
const topLevelToolCalls =
|
|
1088
|
-
const metadataToolCalls =
|
|
1248
|
+
const metadata = msg.metadata === null || msg.metadata === void 0 ? void 0 : expectRecord(msg.metadata, "message.metadata");
|
|
1249
|
+
const topLevelToolCalls = readToolCallArray(msg.toolCalls, "message.toolCalls");
|
|
1250
|
+
const metadataToolCalls = readToolCallArray(metadata?.toolCalls, "message.metadata.toolCalls");
|
|
1089
1251
|
const usedMetadataIndexes = /* @__PURE__ */ new Set();
|
|
1090
1252
|
const parsed = [];
|
|
1091
|
-
const extractToolName = (obj) => {
|
|
1092
|
-
if (typeof obj.name === "string") return obj.name;
|
|
1093
|
-
const t = obj.tool;
|
|
1094
|
-
if (typeof t?.name === "string") return t.name;
|
|
1095
|
-
if (typeof t?.id === "string") return t.id;
|
|
1096
|
-
return void 0;
|
|
1097
|
-
};
|
|
1098
1253
|
const findMatchingMetadataIndex = (toolCall) => {
|
|
1099
|
-
const id =
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
return name ? metadataToolCalls.findIndex((candidate, idx) => !usedMetadataIndexes.has(idx) && extractToolName(candidate) === name) : -1;
|
|
1254
|
+
const id = expectString(toolCall.id, "message.toolCalls[].id");
|
|
1255
|
+
return metadataToolCalls.findIndex(
|
|
1256
|
+
(candidate, idx) => !usedMetadataIndexes.has(idx) && candidate.id === id
|
|
1257
|
+
);
|
|
1104
1258
|
};
|
|
1105
1259
|
const parseToolCall = (primary, secondary) => {
|
|
1106
|
-
const id =
|
|
1107
|
-
const
|
|
1108
|
-
const
|
|
1109
|
-
const
|
|
1110
|
-
const
|
|
1111
|
-
const
|
|
1112
|
-
const status = normalizeToolStatus(primary.status ?? secondary?.status);
|
|
1260
|
+
const id = expectString(primary.id ?? secondary?.id, "toolCall.id");
|
|
1261
|
+
const tool = expectRecord(primary.tool ?? secondary?.tool, "toolCall.tool");
|
|
1262
|
+
const name = expectToolName(tool, "toolCall.tool.id");
|
|
1263
|
+
const argsRaw = primary.args ?? secondary?.args;
|
|
1264
|
+
const result = primary.output !== void 0 ? primary.output : secondary?.output !== void 0 ? secondary.output : primary.projectedOutput !== void 0 ? primary.projectedOutput : secondary?.projectedOutput;
|
|
1265
|
+
const rawStatus = primary.status ?? secondary?.status;
|
|
1113
1266
|
return {
|
|
1114
|
-
|
|
1267
|
+
id,
|
|
1115
1268
|
name,
|
|
1116
|
-
arguments:
|
|
1269
|
+
arguments: expectToolArguments(argsRaw, "toolCall.args"),
|
|
1117
1270
|
...result !== void 0 ? { result } : {},
|
|
1118
|
-
status
|
|
1271
|
+
status: rawStatus === void 0 ? "running" : expectToolStatus(rawStatus, "toolCall.status")
|
|
1119
1272
|
};
|
|
1120
1273
|
};
|
|
1121
1274
|
topLevelToolCalls.forEach((toolCall) => {
|
|
@@ -1130,20 +1283,24 @@ var extractToolCallsFromServerMessage = (msg) => {
|
|
|
1130
1283
|
});
|
|
1131
1284
|
return parsed;
|
|
1132
1285
|
};
|
|
1133
|
-
var
|
|
1286
|
+
var readToolCallArray = (value, path) => {
|
|
1287
|
+
if (value === null || value === void 0) return [];
|
|
1288
|
+
if (!Array.isArray(value)) fail(`${path} must be an array`);
|
|
1289
|
+
return value.map((toolCall, index) => expectRecord(toolCall, `${path}[${index}]`));
|
|
1290
|
+
};
|
|
1291
|
+
var extractToolResultUpdateFromMessage = (msg, now = () => Date.now()) => {
|
|
1134
1292
|
if (msg.senderType !== "tool") return null;
|
|
1135
1293
|
const toolCalls = extractToolCallsFromServerMessage(msg);
|
|
1136
|
-
if (
|
|
1294
|
+
if (toolCalls.length === 0) fail("tool message requires metadata.toolCalls");
|
|
1137
1295
|
const firstToolCall = toolCalls[0];
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
const result = firstToolCall.result !== void 0 ? firstToolCall.result : fallbackResult;
|
|
1296
|
+
if (firstToolCall.result === void 0) fail("tool result message requires tool call output");
|
|
1297
|
+
expectStringValue(msg.createdAt, "tool result message.createdAt");
|
|
1141
1298
|
return {
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1299
|
+
id: firstToolCall.id,
|
|
1300
|
+
name: firstToolCall.name,
|
|
1301
|
+
result: firstToolCall.result,
|
|
1145
1302
|
status: firstToolCall.status,
|
|
1146
|
-
endTime:
|
|
1303
|
+
endTime: new Date(msg.createdAt).getTime()
|
|
1147
1304
|
};
|
|
1148
1305
|
};
|
|
1149
1306
|
var mergePersistedToolResults = (messages, updates) => {
|
|
@@ -1166,42 +1323,95 @@ var prependUniqueMessages = (olderMessages, currentMessages) => {
|
|
|
1166
1323
|
}
|
|
1167
1324
|
return combined;
|
|
1168
1325
|
};
|
|
1169
|
-
var
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1326
|
+
var messageAgentKey = (message) => {
|
|
1327
|
+
if (message.role !== "assistant") return null;
|
|
1328
|
+
if (message.sender?.type === "agent" || message.sender?.type === "tool") {
|
|
1329
|
+
return message.sender.agentId ?? message.sender.id;
|
|
1330
|
+
}
|
|
1331
|
+
return null;
|
|
1332
|
+
};
|
|
1333
|
+
var canAttachToStreamingAssistant = (message, incomingAgentKey) => {
|
|
1334
|
+
if (!message || message.role !== "assistant" || !message.isStreaming) {
|
|
1335
|
+
return false;
|
|
1336
|
+
}
|
|
1337
|
+
const currentAgentKey = messageAgentKey(message);
|
|
1338
|
+
return !incomingAgentKey || !currentAgentKey || currentAgentKey === incomingAgentKey;
|
|
1339
|
+
};
|
|
1340
|
+
|
|
1341
|
+
// src/messageContract.ts
|
|
1342
|
+
var isInternalMessageMetadata = (metadata) => metadata?.visibility === "internal";
|
|
1343
|
+
var defaultCreateId = () => globalThis.crypto?.randomUUID?.() ?? `id-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1344
|
+
var defaultNow = () => Date.now();
|
|
1345
|
+
var roleBySender = {
|
|
1346
|
+
user: "user",
|
|
1347
|
+
agent: "assistant",
|
|
1348
|
+
tool: "assistant",
|
|
1349
|
+
system: "system"
|
|
1350
|
+
};
|
|
1351
|
+
var expectNumber = (value, path) => {
|
|
1352
|
+
if (typeof value !== "number" || Number.isNaN(value)) throw new ContractViolation(`${path} must be a number`);
|
|
1353
|
+
return value;
|
|
1354
|
+
};
|
|
1355
|
+
var extractAttachments = (metadata) => {
|
|
1356
|
+
if (metadata?.attachments === void 0) return [];
|
|
1357
|
+
if (!Array.isArray(metadata.attachments)) {
|
|
1358
|
+
throw new ContractViolation("message.metadata.attachments must be an array");
|
|
1359
|
+
}
|
|
1360
|
+
return metadata.attachments.map((value, index) => {
|
|
1361
|
+
const path = `message.metadata.attachments[${index}]`;
|
|
1362
|
+
const att = expectRecord(value, path);
|
|
1363
|
+
const base = {
|
|
1364
|
+
kind: expectString(att.kind, `${path}.kind`),
|
|
1365
|
+
dataUrl: expectString(att.dataUrl, `${path}.dataUrl`),
|
|
1366
|
+
mimeType: expectString(att.mimeType, `${path}.mimeType`)
|
|
1367
|
+
};
|
|
1368
|
+
if (base.kind === "image") return base;
|
|
1369
|
+
if (base.kind === "audio") return {
|
|
1370
|
+
...base,
|
|
1371
|
+
...att.durationMs !== void 0 ? { durationMs: expectNumber(att.durationMs, `${path}.durationMs`) } : {}
|
|
1372
|
+
};
|
|
1373
|
+
if (base.kind === "video") return {
|
|
1374
|
+
...base,
|
|
1375
|
+
...att.durationMs !== void 0 ? { durationMs: expectNumber(att.durationMs, `${path}.durationMs`) } : {},
|
|
1376
|
+
...att.poster !== void 0 ? { poster: expectString(att.poster, `${path}.poster`) } : {}
|
|
1377
|
+
};
|
|
1378
|
+
throw new ContractViolation(`${path}.kind must be image, audio, or video`);
|
|
1199
1379
|
});
|
|
1200
|
-
|
|
1380
|
+
};
|
|
1381
|
+
var assertRestMessageContract = (msg) => {
|
|
1382
|
+
expectString(msg.id, "message.id");
|
|
1383
|
+
expectString(msg.threadId, "message.threadId");
|
|
1384
|
+
if (!(msg.senderType in roleBySender)) throw new ContractViolation("message.senderType must be user, agent, tool, or system");
|
|
1385
|
+
expectStringValue(msg.content, "message.content");
|
|
1386
|
+
if (msg.metadata !== void 0 && msg.metadata !== null) expectRecord(msg.metadata, "message.metadata");
|
|
1387
|
+
if (msg.createdAt !== void 0) expectString(msg.createdAt, "message.createdAt");
|
|
1388
|
+
};
|
|
1389
|
+
var shouldRenderHydratedMessage = (msg) => {
|
|
1390
|
+
assertRestMessageContract(msg);
|
|
1391
|
+
const meta = msg.metadata ?? {};
|
|
1392
|
+
if (isInternalMessageMetadata(meta)) {
|
|
1393
|
+
return false;
|
|
1394
|
+
}
|
|
1395
|
+
const text = expectStringValue(msg.content, "message.content").trim();
|
|
1396
|
+
const hasText = text.length > 0;
|
|
1397
|
+
const hasToolCalls = extractToolCallsFromServerMessage(msg).length > 0;
|
|
1398
|
+
const hasAttachments = extractAttachments(meta).length > 0;
|
|
1399
|
+
if (msg.senderType === "tool") {
|
|
1400
|
+
return hasAttachments;
|
|
1401
|
+
}
|
|
1402
|
+
return hasText || hasToolCalls || hasAttachments;
|
|
1403
|
+
};
|
|
1404
|
+
var convertServerMessage = (msg, options = {}) => {
|
|
1405
|
+
assertRestMessageContract(msg);
|
|
1406
|
+
const timestamp = msg.createdAt ? new Date(msg.createdAt).getTime() : (options.now ?? defaultNow)();
|
|
1407
|
+
const metadata = msg.metadata ?? void 0;
|
|
1408
|
+
const attachments = extractAttachments(metadata);
|
|
1409
|
+
const messageContent = expectStringValue(msg.content, "message.content");
|
|
1410
|
+
const role = roleBySender[msg.senderType];
|
|
1201
1411
|
const parsedToolCalls = extractToolCallsFromServerMessage(msg);
|
|
1202
1412
|
const shouldRenderToolCalls = msg.senderType !== "tool";
|
|
1203
1413
|
const mappedToolCalls = parsedToolCalls.map((toolCall) => ({
|
|
1204
|
-
id: toolCall.id ??
|
|
1414
|
+
id: toolCall.id ?? (options.createId ?? defaultCreateId)(),
|
|
1205
1415
|
name: toolCall.name,
|
|
1206
1416
|
arguments: toolCall.arguments,
|
|
1207
1417
|
status: toolCall.status,
|
|
@@ -1209,11 +1419,31 @@ var convertServerMessage = (msg) => {
|
|
|
1209
1419
|
}));
|
|
1210
1420
|
const hasToolCalls = shouldRenderToolCalls && mappedToolCalls.length > 0;
|
|
1211
1421
|
const isToolSender = msg.senderType === "tool";
|
|
1212
|
-
const content = isToolSender ? "" :
|
|
1422
|
+
const content = isToolSender ? "" : messageContent;
|
|
1213
1423
|
const reasoning = typeof msg.reasoning === "string" && msg.reasoning.length > 0 ? msg.reasoning : void 0;
|
|
1214
|
-
const
|
|
1215
|
-
|
|
1216
|
-
|
|
1424
|
+
const activityItems = [
|
|
1425
|
+
...reasoning ? [{
|
|
1426
|
+
id: `${msg.id}:thinking`,
|
|
1427
|
+
kind: "thinking",
|
|
1428
|
+
status: "complete",
|
|
1429
|
+
completedAt: timestamp,
|
|
1430
|
+
details: { reasoning }
|
|
1431
|
+
}] : [],
|
|
1432
|
+
...hasToolCalls ? mappedToolCalls.map((toolCall) => ({
|
|
1433
|
+
id: toolCall.id,
|
|
1434
|
+
kind: "tool",
|
|
1435
|
+
status: toolCall.status === "failed" ? "failed" : toolCall.status === "completed" ? "complete" : "active",
|
|
1436
|
+
toolName: toolCall.name,
|
|
1437
|
+
startedAt: toolCall.startTime,
|
|
1438
|
+
completedAt: toolCall.endTime,
|
|
1439
|
+
details: {
|
|
1440
|
+
toolCall,
|
|
1441
|
+
...toolCall.result !== void 0 ? { result: toolCall.result } : {}
|
|
1442
|
+
}
|
|
1443
|
+
})) : []
|
|
1444
|
+
];
|
|
1445
|
+
const sender = resolveHydratedMessageSender(msg, options.senderOptions);
|
|
1446
|
+
return {
|
|
1217
1447
|
id: msg.id,
|
|
1218
1448
|
role,
|
|
1219
1449
|
content,
|
|
@@ -1222,14 +1452,49 @@ var convertServerMessage = (msg) => {
|
|
|
1222
1452
|
isStreaming: false,
|
|
1223
1453
|
isComplete: true,
|
|
1224
1454
|
metadata,
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1455
|
+
activity: activityItems.length > 0 ? { items: activityItems } : void 0,
|
|
1456
|
+
sender
|
|
1457
|
+
};
|
|
1458
|
+
};
|
|
1459
|
+
var prepareHydratedMessages = async (rawMessages, options = {}) => {
|
|
1460
|
+
rawMessages.forEach(assertRestMessageContract);
|
|
1461
|
+
const resolvedMessages = await resolveAssetsInMessages(rawMessages);
|
|
1462
|
+
resolvedMessages.forEach((msg) => {
|
|
1463
|
+
if (msg.senderType === "tool") {
|
|
1464
|
+
const metadata = msg.metadata ?? void 0;
|
|
1465
|
+
if (!metadata) {
|
|
1466
|
+
throw new ContractViolation("tool message requires metadata");
|
|
1467
|
+
}
|
|
1468
|
+
options.onToolOutput?.(metadata.output === void 0 ? metadata : { output: metadata.output });
|
|
1469
|
+
}
|
|
1229
1470
|
});
|
|
1471
|
+
const now = options.now ?? defaultNow;
|
|
1472
|
+
const toolResultUpdates = resolvedMessages.map((msg) => extractToolResultUpdateFromMessage(msg, now)).filter((update) => update !== null);
|
|
1473
|
+
const viewMessages = resolvedMessages.filter(shouldRenderHydratedMessage).map((msg) => convertServerMessage(msg, options));
|
|
1474
|
+
return {
|
|
1475
|
+
viewMessages,
|
|
1476
|
+
toolResultUpdates
|
|
1477
|
+
};
|
|
1230
1478
|
};
|
|
1479
|
+
|
|
1480
|
+
// src/useCopilotzChat.ts
|
|
1481
|
+
var nowTs = () => Date.now();
|
|
1482
|
+
var generateId = () => globalThis.crypto?.randomUUID?.() ?? `id-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1483
|
+
var isAbortError = (error) => error instanceof DOMException && error.name === "AbortError" || typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
|
|
1484
|
+
var getEventPayload = (event) => event?.payload ?? event;
|
|
1485
|
+
var getEventSenderType = (payload) => payload?.senderType || payload?.sender?.type;
|
|
1486
|
+
var THREAD_MESSAGES_PAGE_SIZE = 50;
|
|
1487
|
+
var createEmptyMessagePageInfo = () => ({
|
|
1488
|
+
hasMoreBefore: false,
|
|
1489
|
+
oldestMessageId: null,
|
|
1490
|
+
newestMessageId: null
|
|
1491
|
+
});
|
|
1231
1492
|
function useCopilotz({
|
|
1232
1493
|
userId,
|
|
1494
|
+
userName,
|
|
1495
|
+
userAvatar,
|
|
1496
|
+
assistantName,
|
|
1497
|
+
agentOptions = [],
|
|
1233
1498
|
initialContext,
|
|
1234
1499
|
bootstrap,
|
|
1235
1500
|
defaultThreadName,
|
|
@@ -1269,6 +1534,11 @@ function useCopilotz({
|
|
|
1269
1534
|
const userContextSeedRef = useRef2(userContextSeed);
|
|
1270
1535
|
const messagePageInfoRef = useRef2(messagePageInfo);
|
|
1271
1536
|
const isLoadingOlderMessagesRef = useRef2(isLoadingOlderMessages);
|
|
1537
|
+
const senderOptionsRef = useRef2({
|
|
1538
|
+
agents: agentOptions,
|
|
1539
|
+
user: userId ? { id: userId, name: userName, avatarUrl: userAvatar } : null,
|
|
1540
|
+
assistantName
|
|
1541
|
+
});
|
|
1272
1542
|
const persistedToolUpdatesRef = useRef2([]);
|
|
1273
1543
|
const liveToolUpdatesRef = useRef2([]);
|
|
1274
1544
|
threadsRef.current = threads;
|
|
@@ -1279,6 +1549,11 @@ function useCopilotz({
|
|
|
1279
1549
|
userContextSeedRef.current = userContextSeed;
|
|
1280
1550
|
messagePageInfoRef.current = messagePageInfo;
|
|
1281
1551
|
isLoadingOlderMessagesRef.current = isLoadingOlderMessages;
|
|
1552
|
+
senderOptionsRef.current = {
|
|
1553
|
+
agents: agentOptions,
|
|
1554
|
+
user: userId ? { id: userId, name: userName, avatarUrl: userAvatar } : null,
|
|
1555
|
+
assistantName
|
|
1556
|
+
};
|
|
1282
1557
|
preferredAgentRef.current = preferredAgentName ?? null;
|
|
1283
1558
|
participantsRef.current = participants ?? null;
|
|
1284
1559
|
targetAgentNameRef.current = targetAgentName ?? null;
|
|
@@ -1335,20 +1610,20 @@ function useCopilotz({
|
|
|
1335
1610
|
}
|
|
1336
1611
|
const senderType = getEventSenderType(payload);
|
|
1337
1612
|
if (senderType !== "agent" || typeof payload.content !== "string") return;
|
|
1338
|
-
const
|
|
1339
|
-
const incomingAgentKey =
|
|
1613
|
+
const sender = resolveLiveEventSender(event, senderOptionsRef.current);
|
|
1614
|
+
const incomingAgentKey = sender.agentId ?? sender.id;
|
|
1340
1615
|
setMessages((prev) => {
|
|
1341
1616
|
const next = [...prev];
|
|
1342
1617
|
for (let i = next.length - 1; i >= 0; i--) {
|
|
1343
1618
|
const m = next[i];
|
|
1344
1619
|
if (canAttachToStreamingAssistant(m, incomingAgentKey)) {
|
|
1345
|
-
next[i] =
|
|
1620
|
+
next[i] = {
|
|
1346
1621
|
...m,
|
|
1347
1622
|
content: payload.content,
|
|
1348
1623
|
isStreaming: false,
|
|
1349
1624
|
isComplete: true,
|
|
1350
|
-
|
|
1351
|
-
}
|
|
1625
|
+
sender
|
|
1626
|
+
};
|
|
1352
1627
|
return next;
|
|
1353
1628
|
}
|
|
1354
1629
|
}
|
|
@@ -1358,7 +1633,7 @@ function useCopilotz({
|
|
|
1358
1633
|
}
|
|
1359
1634
|
return [
|
|
1360
1635
|
...next,
|
|
1361
|
-
|
|
1636
|
+
{
|
|
1362
1637
|
id: generateId(),
|
|
1363
1638
|
role: "assistant",
|
|
1364
1639
|
content: payload.content,
|
|
@@ -1366,8 +1641,8 @@ function useCopilotz({
|
|
|
1366
1641
|
isStreaming: false,
|
|
1367
1642
|
isComplete: true,
|
|
1368
1643
|
metadata: liveMetadata,
|
|
1369
|
-
|
|
1370
|
-
}
|
|
1644
|
+
sender
|
|
1645
|
+
}
|
|
1371
1646
|
];
|
|
1372
1647
|
});
|
|
1373
1648
|
}, []);
|
|
@@ -1424,33 +1699,12 @@ function useCopilotz({
|
|
|
1424
1699
|
}
|
|
1425
1700
|
}, [updateThreadsState, getRequestHeaders]);
|
|
1426
1701
|
const prepareThreadMessages = useCallback2(async (rawMessages) => {
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
if (output) processToolOutput(output);
|
|
1433
|
-
}
|
|
1702
|
+
return prepareHydratedMessages(rawMessages, {
|
|
1703
|
+
senderOptions: senderOptionsRef.current,
|
|
1704
|
+
createId: generateId,
|
|
1705
|
+
now: nowTs,
|
|
1706
|
+
onToolOutput: processToolOutput
|
|
1434
1707
|
});
|
|
1435
|
-
const toolResultUpdates = resolvedMessages.map((msg) => extractToolResultUpdateFromMessage(msg)).filter((update) => update !== null);
|
|
1436
|
-
const viewMessages = resolvedMessages.filter((msg) => {
|
|
1437
|
-
const meta = msg.metadata ?? {};
|
|
1438
|
-
if (isInternalMessageMetadata(meta)) {
|
|
1439
|
-
return false;
|
|
1440
|
-
}
|
|
1441
|
-
const text = (typeof msg.content === "string" ? msg.content : "").trim();
|
|
1442
|
-
const hasText = text.length > 0;
|
|
1443
|
-
const hasToolCalls = extractToolCallsFromServerMessage(msg).length > 0;
|
|
1444
|
-
const hasAttachments = Array.isArray(meta.attachments) && meta.attachments.length > 0;
|
|
1445
|
-
if (msg.senderType === "tool") {
|
|
1446
|
-
return hasAttachments;
|
|
1447
|
-
}
|
|
1448
|
-
return hasText || hasToolCalls || hasAttachments;
|
|
1449
|
-
}).map(convertServerMessage);
|
|
1450
|
-
return {
|
|
1451
|
-
viewMessages,
|
|
1452
|
-
toolResultUpdates
|
|
1453
|
-
};
|
|
1454
1708
|
}, [processToolOutput]);
|
|
1455
1709
|
const loadThreadMessages = useCallback2(async (threadId) => {
|
|
1456
1710
|
const requestId = messagesRequestRef.current + 1;
|
|
@@ -1658,14 +1912,14 @@ function useCopilotz({
|
|
|
1658
1912
|
dataUrl,
|
|
1659
1913
|
mimeType
|
|
1660
1914
|
};
|
|
1661
|
-
setMessages((prev) => prev.map((msg) => msg.id === assistantMessageId ?
|
|
1915
|
+
setMessages((prev) => prev.map((msg) => msg.id === assistantMessageId ? {
|
|
1662
1916
|
...msg,
|
|
1663
1917
|
attachments: [...msg.attachments || [], mediaAttachment]
|
|
1664
|
-
}
|
|
1918
|
+
} : msg));
|
|
1665
1919
|
}, []);
|
|
1666
1920
|
const sendCopilotzMessage = useCallback2(async (params) => {
|
|
1667
|
-
let currentAssistantId = generateId();
|
|
1668
|
-
let
|
|
1921
|
+
let currentAssistantId = params.assistantMessageId ?? generateId();
|
|
1922
|
+
let currentAssistantSender = params.assistantSender;
|
|
1669
1923
|
params.onBeforeStart?.(currentAssistantId);
|
|
1670
1924
|
let hasStreamProgress = false;
|
|
1671
1925
|
const updateStreamingMessage = (partial, opts) => {
|
|
@@ -1673,28 +1927,26 @@ function useCopilotz({
|
|
|
1673
1927
|
hasStreamProgress = true;
|
|
1674
1928
|
}
|
|
1675
1929
|
const isReasoning = opts?.isReasoning ?? false;
|
|
1676
|
-
const
|
|
1677
|
-
if (
|
|
1678
|
-
|
|
1679
|
-
...currentAssistantIdentity,
|
|
1680
|
-
...nextIdentity
|
|
1681
|
-
};
|
|
1930
|
+
const nextSender = opts?.agent ? resolveAgentSender(opts.agent, senderOptionsRef.current) : currentAssistantSender;
|
|
1931
|
+
if (nextSender) {
|
|
1932
|
+
currentAssistantSender = nextSender;
|
|
1682
1933
|
}
|
|
1683
|
-
const
|
|
1684
|
-
const nextAgentKey = agentIdentity.senderAgentId ?? agentIdentity.senderName ?? null;
|
|
1934
|
+
const nextAgentKey = currentAssistantSender?.agentId ?? currentAssistantSender?.id ?? null;
|
|
1685
1935
|
const applyUpdate = (msg) => {
|
|
1686
|
-
return
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1936
|
+
return {
|
|
1937
|
+
...updateAssistantMessageToken(msg, {
|
|
1938
|
+
partial,
|
|
1939
|
+
isReasoning
|
|
1940
|
+
}),
|
|
1941
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
1942
|
+
};
|
|
1691
1943
|
};
|
|
1692
1944
|
setMessages((prev) => {
|
|
1693
1945
|
const idx = prev.findIndex((m) => m.id === currentAssistantId);
|
|
1694
1946
|
if (idx >= 0 && canAttachToStreamingAssistant(prev[idx], nextAgentKey)) {
|
|
1695
1947
|
const msg = prev[idx];
|
|
1696
1948
|
const next = applyUpdate(msg);
|
|
1697
|
-
if (msg.content === next.content && msg.
|
|
1949
|
+
if (msg.content === next.content && msg.activity === next.activity && msg.isStreaming === next.isStreaming && msg.isComplete === next.isComplete) {
|
|
1698
1950
|
return prev;
|
|
1699
1951
|
}
|
|
1700
1952
|
const updated = [...prev];
|
|
@@ -1705,7 +1957,7 @@ function useCopilotz({
|
|
|
1705
1957
|
if (canAttachToStreamingAssistant(last, nextAgentKey)) {
|
|
1706
1958
|
currentAssistantId = last.id;
|
|
1707
1959
|
const next = applyUpdate(last);
|
|
1708
|
-
if (last.content === next.content && last.
|
|
1960
|
+
if (last.content === next.content && last.activity === next.activity && last.isStreaming === next.isStreaming && last.isComplete === next.isComplete) {
|
|
1709
1961
|
return prev;
|
|
1710
1962
|
}
|
|
1711
1963
|
const updated = [...prev];
|
|
@@ -1723,7 +1975,7 @@ function useCopilotz({
|
|
|
1723
1975
|
timestamp: nowTs(),
|
|
1724
1976
|
isStreaming: true,
|
|
1725
1977
|
isComplete: false,
|
|
1726
|
-
...
|
|
1978
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
1727
1979
|
};
|
|
1728
1980
|
return [...prev, applyUpdate(base)];
|
|
1729
1981
|
}
|
|
@@ -1770,7 +2022,7 @@ function useCopilotz({
|
|
|
1770
2022
|
if (fallbackIdx < 0) return prev;
|
|
1771
2023
|
const message = prev[fallbackIdx];
|
|
1772
2024
|
const nextMessage = finalizeAssistantMessage(message, finalAnswer);
|
|
1773
|
-
if (message.content === nextMessage.content && message.isStreaming === nextMessage.isStreaming && message.isComplete === nextMessage.isComplete && message.
|
|
2025
|
+
if (message.content === nextMessage.content && message.isStreaming === nextMessage.isStreaming && message.isComplete === nextMessage.isComplete && message.activity === nextMessage.activity) {
|
|
1774
2026
|
return prev;
|
|
1775
2027
|
}
|
|
1776
2028
|
const updated = [...prev];
|
|
@@ -1785,7 +2037,6 @@ function useCopilotz({
|
|
|
1785
2037
|
const payload = event?.payload ?? event;
|
|
1786
2038
|
if (type === "TOOL_CALL") {
|
|
1787
2039
|
const parsedToolCall = extractLiveToolCall(payload);
|
|
1788
|
-
if (!parsedToolCall) return null;
|
|
1789
2040
|
return {
|
|
1790
2041
|
id: generateId(),
|
|
1791
2042
|
threadId: curThreadId ?? "",
|
|
@@ -1871,14 +2122,9 @@ function useCopilotz({
|
|
|
1871
2122
|
const parsedToolCall = extractLiveToolCall(
|
|
1872
2123
|
payload ?? {}
|
|
1873
2124
|
);
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
currentAssistantIdentity = {
|
|
1878
|
-
...currentAssistantIdentity,
|
|
1879
|
-
...eventAgentIdentity
|
|
1880
|
-
};
|
|
1881
|
-
}
|
|
2125
|
+
const eventSender = resolveLiveEventSender(event, senderOptionsRef.current);
|
|
2126
|
+
currentAssistantSender = eventSender;
|
|
2127
|
+
const eventAgentKey = currentAssistantSender.agentId ?? currentAssistantSender.id;
|
|
1882
2128
|
const callId = parsedToolCall.id ?? generateId();
|
|
1883
2129
|
const toolName = parsedToolCall.name;
|
|
1884
2130
|
const bufferedUpdates = liveToolUpdatesRef.current;
|
|
@@ -1892,6 +2138,10 @@ function useCopilotz({
|
|
|
1892
2138
|
const endTime = bufferedUpdate?.endTime;
|
|
1893
2139
|
setMessages(
|
|
1894
2140
|
(prev) => (() => {
|
|
2141
|
+
const canHostActivity = (message) => {
|
|
2142
|
+
if (!message) return false;
|
|
2143
|
+
return message.role === "assistant" && message.isStreaming && message.content.trim().length === 0 && !message.attachments?.length;
|
|
2144
|
+
};
|
|
1895
2145
|
const appendToolCall = (msg) => ({
|
|
1896
2146
|
...appendAssistantToolCall(msg, {
|
|
1897
2147
|
id: callId,
|
|
@@ -1903,21 +2153,21 @@ function useCopilotz({
|
|
|
1903
2153
|
...endTime !== void 0 ? { endTime } : {}
|
|
1904
2154
|
})
|
|
1905
2155
|
});
|
|
1906
|
-
const currentIdx = prev.findIndex((message) => message.id === currentAssistantId && message.role === "assistant" && message.isStreaming);
|
|
2156
|
+
const currentIdx = prev.findIndex((message) => message.id === currentAssistantId && message.role === "assistant" && message.isStreaming && canHostActivity(message));
|
|
1907
2157
|
if (currentIdx >= 0) {
|
|
1908
2158
|
const next = [...prev];
|
|
1909
2159
|
next[currentIdx] = appendToolCall({
|
|
1910
2160
|
...next[currentIdx],
|
|
1911
2161
|
isStreaming: true,
|
|
1912
2162
|
isComplete: false,
|
|
1913
|
-
...
|
|
2163
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
1914
2164
|
});
|
|
1915
2165
|
return next;
|
|
1916
2166
|
}
|
|
1917
2167
|
const last = prev[prev.length - 1];
|
|
1918
|
-
if (canAttachToStreamingAssistant(
|
|
2168
|
+
if (canHostActivity(last) && canAttachToStreamingAssistant(
|
|
1919
2169
|
last,
|
|
1920
|
-
|
|
2170
|
+
eventAgentKey
|
|
1921
2171
|
)) {
|
|
1922
2172
|
currentAssistantId = last.id;
|
|
1923
2173
|
const next = [...prev];
|
|
@@ -1925,7 +2175,7 @@ function useCopilotz({
|
|
|
1925
2175
|
...last,
|
|
1926
2176
|
isStreaming: true,
|
|
1927
2177
|
isComplete: false,
|
|
1928
|
-
...
|
|
2178
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
1929
2179
|
});
|
|
1930
2180
|
return next;
|
|
1931
2181
|
}
|
|
@@ -1940,7 +2190,7 @@ function useCopilotz({
|
|
|
1940
2190
|
timestamp: nowTs(),
|
|
1941
2191
|
isStreaming: true,
|
|
1942
2192
|
isComplete: false,
|
|
1943
|
-
...
|
|
2193
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
1944
2194
|
})
|
|
1945
2195
|
];
|
|
1946
2196
|
})()
|
|
@@ -1950,7 +2200,11 @@ function useCopilotz({
|
|
|
1950
2200
|
}
|
|
1951
2201
|
const sm = await toServerMessageFromEvent(event);
|
|
1952
2202
|
if (sm) {
|
|
1953
|
-
const viewMsg = convertServerMessage(sm
|
|
2203
|
+
const viewMsg = convertServerMessage(sm, {
|
|
2204
|
+
senderOptions: senderOptionsRef.current,
|
|
2205
|
+
createId: generateId,
|
|
2206
|
+
now: nowTs
|
|
2207
|
+
});
|
|
1954
2208
|
finalizeCurrentAssistantBubble();
|
|
1955
2209
|
setMessages((prev) => [...prev, viewMsg]);
|
|
1956
2210
|
return;
|
|
@@ -2008,8 +2262,19 @@ function useCopilotz({
|
|
|
2008
2262
|
content,
|
|
2009
2263
|
timestamp,
|
|
2010
2264
|
attachments: attachments.length > 0 ? attachments : void 0,
|
|
2011
|
-
isComplete: true
|
|
2265
|
+
isComplete: true,
|
|
2266
|
+
sender: resolveUserSender({
|
|
2267
|
+
id: userId,
|
|
2268
|
+
name: userContextSeedRef.current?.profile?.full_name ?? userId
|
|
2269
|
+
})
|
|
2012
2270
|
};
|
|
2271
|
+
const assistantSender = targetAgentNameRef.current ? resolveAgentSender(
|
|
2272
|
+
{ id: targetAgentNameRef.current, name: targetAgentNameRef.current },
|
|
2273
|
+
senderOptionsRef.current
|
|
2274
|
+
) : preferredAgentRef.current ? resolveAgentSender(
|
|
2275
|
+
{ id: preferredAgentRef.current, name: preferredAgentRef.current },
|
|
2276
|
+
senderOptionsRef.current
|
|
2277
|
+
) : resolveAssistantFallbackSender(senderOptionsRef.current);
|
|
2013
2278
|
const assistantPlaceholder = {
|
|
2014
2279
|
id: generateId(),
|
|
2015
2280
|
role: "assistant",
|
|
@@ -2017,9 +2282,9 @@ function useCopilotz({
|
|
|
2017
2282
|
timestamp: timestamp + 1,
|
|
2018
2283
|
isStreaming: true,
|
|
2019
2284
|
isComplete: false,
|
|
2020
|
-
|
|
2285
|
+
sender: assistantSender
|
|
2021
2286
|
};
|
|
2022
|
-
setMessages((prev) => [...prev, userMessage,
|
|
2287
|
+
setMessages((prev) => [...prev, userMessage, assistantPlaceholder]);
|
|
2023
2288
|
setSpecialState(null);
|
|
2024
2289
|
if (!threadsRef.current.some((t) => t.id === conversationKey)) {
|
|
2025
2290
|
const newThread = {
|
|
@@ -2043,6 +2308,8 @@ function useCopilotz({
|
|
|
2043
2308
|
// userName can be anything, but let's try to find it in context or just fallback
|
|
2044
2309
|
userName: userContextSeedRef.current?.profile?.full_name ?? userId,
|
|
2045
2310
|
agentName: preferredAgentRef.current,
|
|
2311
|
+
assistantMessageId: assistantPlaceholder.id,
|
|
2312
|
+
assistantSender,
|
|
2046
2313
|
// Include pending title for new threads
|
|
2047
2314
|
threadMetadata: pendingTitle ? { name: pendingTitle } : void 0
|
|
2048
2315
|
});
|
|
@@ -2066,24 +2333,26 @@ function useCopilotz({
|
|
|
2066
2333
|
const message = finalized[i];
|
|
2067
2334
|
if (message.role !== "assistant") continue;
|
|
2068
2335
|
const updated = [...finalized];
|
|
2069
|
-
updated[i] =
|
|
2336
|
+
updated[i] = {
|
|
2070
2337
|
...message,
|
|
2071
2338
|
content: "Desculpe, ocorreu um erro ao gerar a resposta. Por favor, tente novamente.",
|
|
2072
2339
|
isStreaming: false,
|
|
2073
|
-
isComplete: true
|
|
2074
|
-
|
|
2340
|
+
isComplete: true,
|
|
2341
|
+
sender: message.sender ?? resolveAssistantFallbackSender(senderOptionsRef.current)
|
|
2342
|
+
};
|
|
2075
2343
|
return updated;
|
|
2076
2344
|
}
|
|
2077
2345
|
return [
|
|
2078
2346
|
...finalized,
|
|
2079
|
-
|
|
2347
|
+
{
|
|
2080
2348
|
id: generateId(),
|
|
2081
2349
|
role: "assistant",
|
|
2082
2350
|
content: "Desculpe, ocorreu um erro ao gerar a resposta. Por favor, tente novamente.",
|
|
2083
2351
|
timestamp: nowTs(),
|
|
2084
2352
|
isStreaming: false,
|
|
2085
|
-
isComplete: true
|
|
2086
|
-
|
|
2353
|
+
isComplete: true,
|
|
2354
|
+
sender: resolveAssistantFallbackSender(senderOptionsRef.current)
|
|
2355
|
+
}
|
|
2087
2356
|
];
|
|
2088
2357
|
});
|
|
2089
2358
|
}
|
|
@@ -2122,14 +2391,15 @@ function useCopilotz({
|
|
|
2122
2391
|
return;
|
|
2123
2392
|
}
|
|
2124
2393
|
setMessages([
|
|
2125
|
-
|
|
2394
|
+
{
|
|
2126
2395
|
id: generateId(),
|
|
2127
2396
|
role: "assistant",
|
|
2128
2397
|
content: "N\xE3o foi poss\xEDvel iniciar a conversa. Tente novamente mais tarde.",
|
|
2129
2398
|
timestamp: nowTs(),
|
|
2130
2399
|
isStreaming: false,
|
|
2131
|
-
isComplete: true
|
|
2132
|
-
|
|
2400
|
+
isComplete: true,
|
|
2401
|
+
sender: resolveAssistantFallbackSender(senderOptionsRef.current)
|
|
2402
|
+
}
|
|
2133
2403
|
]);
|
|
2134
2404
|
}
|
|
2135
2405
|
}, [fetchAndSetThreadsState, loadThreadMessages, sendCopilotzMessage, bootstrap, defaultThreadName, getSpecialStateFromError]);
|
|
@@ -2275,6 +2545,10 @@ var CopilotzChat = ({
|
|
|
2275
2545
|
loadOlderMessages
|
|
2276
2546
|
} = useCopilotz({
|
|
2277
2547
|
userId,
|
|
2548
|
+
userName,
|
|
2549
|
+
userAvatar,
|
|
2550
|
+
assistantName: userConfig?.branding?.title,
|
|
2551
|
+
agentOptions,
|
|
2278
2552
|
initialContext,
|
|
2279
2553
|
bootstrap,
|
|
2280
2554
|
defaultThreadName: userConfig?.labels?.defaultThreadName,
|