@copilotz/chat-adapter 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -2
- package/dist/index.js +633 -375
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -672,64 +672,6 @@ async function deleteThread(threadId, getRequestHeaders) {
|
|
|
672
672
|
return true;
|
|
673
673
|
}
|
|
674
674
|
|
|
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
675
|
// src/useUrlState.ts
|
|
734
676
|
import { useState, useEffect, useCallback, useRef } from "react";
|
|
735
677
|
var DEFAULT_PARAMS = {
|
|
@@ -835,194 +777,397 @@ function useUrlState(config = {}) {
|
|
|
835
777
|
}
|
|
836
778
|
|
|
837
779
|
// src/activity.ts
|
|
838
|
-
var
|
|
780
|
+
var thinkingId = "thinking";
|
|
781
|
+
var answeringId = "answering";
|
|
782
|
+
var getItems = (message) => Array.isArray(message.activity?.items) ? message.activity.items : [];
|
|
783
|
+
var setItems = (message, items) => ({
|
|
784
|
+
...message,
|
|
785
|
+
activity: items.length > 0 ? { items } : void 0
|
|
786
|
+
});
|
|
787
|
+
var toolStatusToActivityStatus = (status) => {
|
|
788
|
+
if (status === "failed") return "failed";
|
|
789
|
+
if (status === "completed") return "complete";
|
|
790
|
+
return "active";
|
|
791
|
+
};
|
|
792
|
+
var upsertItem = (message, item) => {
|
|
793
|
+
const items = getItems(message);
|
|
794
|
+
const index = items.findIndex((current) => current.id === item.id);
|
|
795
|
+
if (index === -1) return setItems(message, [...items, item]);
|
|
796
|
+
const next = [...items];
|
|
797
|
+
next[index] = {
|
|
798
|
+
...next[index],
|
|
799
|
+
...item,
|
|
800
|
+
details: {
|
|
801
|
+
...next[index].details ?? {},
|
|
802
|
+
...item.details ?? {}
|
|
803
|
+
}
|
|
804
|
+
};
|
|
805
|
+
return setItems(message, next);
|
|
806
|
+
};
|
|
807
|
+
var completeItems = (message, shouldComplete) => setItems(message, getItems(message).map((item) => item.status === "active" && shouldComplete(item) ? { ...item, status: "complete", completedAt: Date.now() } : item));
|
|
839
808
|
var hasVisibleAssistantOutput = (message) => {
|
|
840
809
|
if (message.role !== "assistant") return false;
|
|
841
810
|
if (typeof message.content === "string" && message.content.trim().length > 0) return true;
|
|
842
811
|
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
|
-
};
|
|
812
|
+
return getItems(message).length > 0;
|
|
889
813
|
};
|
|
890
814
|
var toPublicChatMessage = (message) => {
|
|
891
|
-
|
|
815
|
+
if (message.role === "assistant") return message;
|
|
816
|
+
const { activity, ...rest } = message;
|
|
892
817
|
return rest;
|
|
893
818
|
};
|
|
894
819
|
var updateAssistantMessageToken = (message, params) => {
|
|
895
820
|
if (message.role !== "assistant") return message;
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
821
|
+
if (params.isReasoning) {
|
|
822
|
+
return upsertItem({
|
|
823
|
+
...message,
|
|
824
|
+
isStreaming: true,
|
|
825
|
+
isComplete: false
|
|
826
|
+
}, {
|
|
827
|
+
id: thinkingId,
|
|
828
|
+
kind: "thinking",
|
|
829
|
+
status: "active",
|
|
830
|
+
startedAt: getItems(message).find((item) => item.id === thinkingId)?.startedAt ?? Date.now(),
|
|
831
|
+
details: { reasoning: params.partial }
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
return upsertItem(completeItems({
|
|
904
835
|
...message,
|
|
905
|
-
...params.agentIdentity,
|
|
906
836
|
content: params.partial,
|
|
907
|
-
_activityReasoningStreaming: false,
|
|
908
837
|
isStreaming: true,
|
|
909
838
|
isComplete: false
|
|
910
|
-
}
|
|
911
|
-
|
|
839
|
+
}, (item) => item.kind === "thinking" || item.kind === "tool"), {
|
|
840
|
+
id: answeringId,
|
|
841
|
+
kind: "answering",
|
|
842
|
+
status: "active",
|
|
843
|
+
startedAt: getItems(message).find((item) => item.id === answeringId)?.startedAt ?? Date.now()
|
|
844
|
+
});
|
|
912
845
|
};
|
|
913
846
|
var appendAssistantToolCall = (message, toolCall) => {
|
|
914
847
|
if (message.role !== "assistant") return message;
|
|
915
|
-
|
|
848
|
+
const status = toolStatusToActivityStatus(toolCall.status);
|
|
849
|
+
return upsertItem({
|
|
916
850
|
...message,
|
|
917
|
-
_activityToolCalls: [
|
|
918
|
-
...Array.isArray(message._activityToolCalls) ? message._activityToolCalls : [],
|
|
919
|
-
toolCall
|
|
920
|
-
],
|
|
921
851
|
isStreaming: true,
|
|
922
852
|
isComplete: false
|
|
853
|
+
}, {
|
|
854
|
+
id: toolCall.id,
|
|
855
|
+
kind: "tool",
|
|
856
|
+
status,
|
|
857
|
+
toolName: toolCall.name,
|
|
858
|
+
startedAt: toolCall.startTime ?? Date.now(),
|
|
859
|
+
...status !== "active" ? { completedAt: toolCall.endTime ?? Date.now() } : {},
|
|
860
|
+
details: {
|
|
861
|
+
toolCall,
|
|
862
|
+
...toolCall.result !== void 0 ? { result: toolCall.result } : {}
|
|
863
|
+
}
|
|
923
864
|
});
|
|
924
865
|
};
|
|
925
866
|
var applyAssistantToolResult = (message, update) => {
|
|
926
867
|
if (message.role !== "assistant") return message;
|
|
927
|
-
const
|
|
928
|
-
const
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
...
|
|
939
|
-
|
|
940
|
-
|
|
868
|
+
const items = getItems(message);
|
|
869
|
+
const index = items.findIndex((item2) => item2.kind === "tool" && (update.id && item2.id === update.id || !update.id && item2.toolName === update.name));
|
|
870
|
+
if (index === -1) return message;
|
|
871
|
+
const item = items[index];
|
|
872
|
+
const toolCall = item.details?.toolCall;
|
|
873
|
+
const nextToolCall = toolCall ? { ...toolCall, ...update } : {
|
|
874
|
+
id: update.id ?? item.id,
|
|
875
|
+
name: update.name,
|
|
876
|
+
arguments: {},
|
|
877
|
+
status: update.status,
|
|
878
|
+
...update.result !== void 0 ? { result: update.result } : {},
|
|
879
|
+
...update.endTime !== void 0 ? { endTime: update.endTime } : {}
|
|
880
|
+
};
|
|
881
|
+
const status = toolStatusToActivityStatus(update.status);
|
|
882
|
+
const next = [...items];
|
|
883
|
+
next[index] = {
|
|
884
|
+
...item,
|
|
885
|
+
status,
|
|
886
|
+
toolName: update.name,
|
|
887
|
+
...status !== "active" ? { completedAt: update.endTime ?? Date.now() } : {},
|
|
888
|
+
details: {
|
|
889
|
+
...item.details ?? {},
|
|
890
|
+
toolCall: nextToolCall,
|
|
891
|
+
...update.result !== void 0 ? { result: update.result } : {}
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
return setItems(message, next);
|
|
941
895
|
};
|
|
942
896
|
var finalizeAssistantMessage = (message, finalAnswer) => {
|
|
943
897
|
if (message.role !== "assistant") return message;
|
|
944
|
-
|
|
898
|
+
const completed = completeItems({
|
|
945
899
|
...message,
|
|
946
900
|
...typeof finalAnswer === "string" && finalAnswer.length > 0 ? { content: finalAnswer } : {},
|
|
947
901
|
isStreaming: false,
|
|
948
|
-
isComplete: true
|
|
949
|
-
|
|
950
|
-
|
|
902
|
+
isComplete: true
|
|
903
|
+
}, (item) => item.kind === "thinking" || item.kind === "answering");
|
|
904
|
+
return setItems(completed, getItems(completed).filter((item) => item.kind !== "answering"));
|
|
951
905
|
};
|
|
952
906
|
var closeAssistantMessage = (message) => {
|
|
953
907
|
if (message.role !== "assistant") return message;
|
|
954
|
-
return
|
|
908
|
+
return completeItems({
|
|
955
909
|
...message,
|
|
956
910
|
isStreaming: false,
|
|
957
|
-
isComplete: true
|
|
958
|
-
|
|
959
|
-
});
|
|
911
|
+
isComplete: true
|
|
912
|
+
}, () => true);
|
|
960
913
|
};
|
|
961
914
|
|
|
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
|
-
};
|
|
915
|
+
// src/contract.ts
|
|
916
|
+
var ContractViolation = class extends Error {
|
|
917
|
+
constructor(message) {
|
|
918
|
+
super(message);
|
|
919
|
+
this.name = "ContractViolation";
|
|
920
|
+
}
|
|
976
921
|
};
|
|
977
|
-
var
|
|
978
|
-
|
|
979
|
-
|
|
922
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
923
|
+
var expectRecord = (value, path) => {
|
|
924
|
+
if (!isRecord(value)) throw new ContractViolation(`${path} must be an object`);
|
|
925
|
+
return value;
|
|
926
|
+
};
|
|
927
|
+
var expectString = (value, path) => {
|
|
928
|
+
if (typeof value !== "string" || value.trim().length === 0) throw new ContractViolation(`${path} must be a non-empty string`);
|
|
929
|
+
return value;
|
|
930
|
+
};
|
|
931
|
+
var expectOptionalString = (value, path) => {
|
|
932
|
+
if (value === void 0 || value === null) return void 0;
|
|
933
|
+
return expectString(value, path);
|
|
980
934
|
};
|
|
981
|
-
var
|
|
982
|
-
|
|
983
|
-
|
|
935
|
+
var expectStringValue = (value, path) => {
|
|
936
|
+
if (typeof value !== "string") throw new ContractViolation(`${path} must be a string`);
|
|
937
|
+
return value;
|
|
938
|
+
};
|
|
939
|
+
|
|
940
|
+
// src/senders.ts
|
|
941
|
+
var clean = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
942
|
+
var expectSenderType = (value, path) => {
|
|
943
|
+
if (value === "user" || value === "agent" || value === "tool" || value === "system") return value;
|
|
944
|
+
throw new ContractViolation(`${path} must be user, agent, tool, or system`);
|
|
945
|
+
};
|
|
946
|
+
var defined = (value) => Object.fromEntries(
|
|
947
|
+
Object.entries(value).filter(([, entry]) => entry !== void 0)
|
|
948
|
+
);
|
|
949
|
+
var findAgent = (agents, ...candidates) => {
|
|
950
|
+
const values = candidates.filter(Boolean).map((value) => value.toLowerCase());
|
|
951
|
+
if (!agents || values.length === 0) return void 0;
|
|
952
|
+
return agents.find(
|
|
953
|
+
(agent) => values.includes(agent.id.toLowerCase()) || values.includes(agent.name.toLowerCase())
|
|
954
|
+
);
|
|
955
|
+
};
|
|
956
|
+
var fromAgent = (agent, overrides = {}) => defined({
|
|
957
|
+
type: overrides.type ?? "agent",
|
|
958
|
+
id: agent.id,
|
|
959
|
+
name: agent.name,
|
|
960
|
+
agentId: agent.id,
|
|
961
|
+
avatarUrl: agent.avatarUrl,
|
|
962
|
+
color: agent.color,
|
|
963
|
+
...overrides
|
|
964
|
+
});
|
|
965
|
+
var resolveUserSender = (user) => defined({
|
|
966
|
+
type: "user",
|
|
967
|
+
id: user.id,
|
|
968
|
+
externalId: user.id,
|
|
969
|
+
name: clean(user.name) ?? user.id,
|
|
970
|
+
avatarUrl: clean(user.avatarUrl)
|
|
971
|
+
});
|
|
972
|
+
var resolveAssistantFallbackSender = (options = {}) => ({
|
|
973
|
+
type: "agent",
|
|
974
|
+
id: "assistant",
|
|
975
|
+
name: clean(options.assistantName) ?? "Assistant",
|
|
976
|
+
agentId: "assistant"
|
|
977
|
+
});
|
|
978
|
+
var resolveAgentSender = (identity, options = {}, overrides = {}) => {
|
|
979
|
+
const id = expectString(identity.id, "agent.id");
|
|
980
|
+
const name = expectString(identity.name, "agent.name");
|
|
981
|
+
const agent = findAgent(options.agents, id, name);
|
|
984
982
|
if (agent) {
|
|
985
|
-
return
|
|
983
|
+
return fromAgent(agent, defined({
|
|
984
|
+
...overrides,
|
|
985
|
+
externalId: id && id !== agent.id ? id : void 0
|
|
986
|
+
}));
|
|
986
987
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
id
|
|
990
|
-
name
|
|
988
|
+
return defined({
|
|
989
|
+
type: overrides.type ?? "agent",
|
|
990
|
+
id,
|
|
991
|
+
name,
|
|
992
|
+
agentId: id,
|
|
993
|
+
...overrides
|
|
991
994
|
});
|
|
992
995
|
};
|
|
993
|
-
var
|
|
994
|
-
|
|
995
|
-
|
|
996
|
+
var resolveHydratedMessageSender = (message, options = {}) => {
|
|
997
|
+
const metadata = message.metadata ? expectRecord(message.metadata, "message.metadata") : {};
|
|
998
|
+
const type = expectSenderType(message.senderType, "message.senderType");
|
|
999
|
+
const storedId = expectOptionalString(message.senderId, "message.senderId");
|
|
1000
|
+
const participantId = expectOptionalString(metadata.senderParticipantId, "message.metadata.senderParticipantId") ?? expectOptionalString(message.senderUserId, "message.senderUserId");
|
|
1001
|
+
const externalId = expectString(metadata.senderExternalId, "message.metadata.senderExternalId");
|
|
1002
|
+
const displayName = expectString(metadata.senderDisplayName, "message.metadata.senderDisplayName");
|
|
1003
|
+
if (type === "agent" || type === "tool") {
|
|
1004
|
+
const agent = findAgent(options.agents, externalId, displayName, storedId);
|
|
1005
|
+
if (agent) {
|
|
1006
|
+
return fromAgent(agent, defined({
|
|
1007
|
+
type,
|
|
1008
|
+
participantId: participantId ?? storedId,
|
|
1009
|
+
externalId: externalId && externalId !== agent.id ? externalId : void 0
|
|
1010
|
+
}));
|
|
1011
|
+
}
|
|
1012
|
+
return defined({
|
|
1013
|
+
type,
|
|
1014
|
+
id: externalId,
|
|
1015
|
+
name: displayName,
|
|
1016
|
+
agentId: externalId,
|
|
1017
|
+
participantId: participantId ?? storedId,
|
|
1018
|
+
externalId
|
|
1019
|
+
});
|
|
996
1020
|
}
|
|
997
|
-
|
|
998
|
-
|
|
1021
|
+
if (type === "user") {
|
|
1022
|
+
return defined({
|
|
1023
|
+
type: "user",
|
|
1024
|
+
id: externalId,
|
|
1025
|
+
externalId,
|
|
1026
|
+
name: displayName,
|
|
1027
|
+
avatarUrl: clean(options.user?.avatarUrl),
|
|
1028
|
+
participantId: participantId ?? storedId
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
return defined({
|
|
1032
|
+
type: "system",
|
|
1033
|
+
id: externalId,
|
|
1034
|
+
name: displayName,
|
|
1035
|
+
participantId: participantId ?? storedId,
|
|
1036
|
+
externalId
|
|
1037
|
+
});
|
|
999
1038
|
};
|
|
1000
|
-
var
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1039
|
+
var resolveLiveEventSender = (event, options = {}) => {
|
|
1040
|
+
const raw = expectRecord(event, "stream event");
|
|
1041
|
+
const payload = raw.payload === void 0 ? raw : expectRecord(raw.payload, "stream event.payload");
|
|
1042
|
+
const agent = payload.agent ?? raw.agent;
|
|
1043
|
+
if (isRecord(agent)) {
|
|
1044
|
+
return resolveAgentSender({
|
|
1045
|
+
id: expectString(agent.id, "stream event.payload.agent.id"),
|
|
1046
|
+
name: expectString(agent.name, "stream event.payload.agent.name")
|
|
1047
|
+
}, options);
|
|
1048
|
+
}
|
|
1049
|
+
const sender = payload.sender ?? raw.sender;
|
|
1050
|
+
if (!isRecord(sender)) {
|
|
1051
|
+
throw new ContractViolation("stream event sender contract requires payload.agent or payload.sender");
|
|
1052
|
+
}
|
|
1053
|
+
const type = expectSenderType(sender.type ?? payload.senderType, "stream event.payload.sender.type");
|
|
1054
|
+
if (type !== "user") {
|
|
1055
|
+
return resolveAgentSender({
|
|
1056
|
+
id: expectString(sender.id ?? sender.externalId, "stream event.payload.sender.id"),
|
|
1057
|
+
name: expectString(sender.name, "stream event.payload.sender.name")
|
|
1058
|
+
}, options, { type });
|
|
1059
|
+
}
|
|
1060
|
+
if (!options.user) {
|
|
1061
|
+
throw new ContractViolation("user stream sender requires current user context");
|
|
1062
|
+
}
|
|
1063
|
+
return resolveUserSender(options.user);
|
|
1064
|
+
};
|
|
1065
|
+
|
|
1066
|
+
// src/assetsService.ts
|
|
1067
|
+
var ContractViolation2 = class extends Error {
|
|
1068
|
+
name = "ContractViolation";
|
|
1069
|
+
};
|
|
1070
|
+
var expectRecord2 = (value, path) => {
|
|
1071
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) return value;
|
|
1072
|
+
throw new ContractViolation2(`${path} must be an object`);
|
|
1073
|
+
};
|
|
1074
|
+
var expectString2 = (value, path) => {
|
|
1075
|
+
if (typeof value === "string" && value.trim().length > 0) return value;
|
|
1076
|
+
throw new ContractViolation2(`${path} must be a non-empty string`);
|
|
1077
|
+
};
|
|
1078
|
+
var rawBaseValue2 = import.meta.env?.VITE_API_URL;
|
|
1079
|
+
var rawBase2 = typeof rawBaseValue2 === "string" && rawBaseValue2.length > 0 ? rawBaseValue2 : "/api";
|
|
1080
|
+
var normalizedBase2 = rawBase2.replace(/\/$/, "");
|
|
1081
|
+
var API_BASE2 = normalizedBase2.startsWith("http") || normalizedBase2.startsWith("/") ? normalizedBase2 : `/${normalizedBase2}`;
|
|
1082
|
+
var apiUrl2 = (path) => `${API_BASE2}${path}`;
|
|
1083
|
+
var extractAssetId = (refOrId) => refOrId.startsWith("asset://") ? refOrId.slice("asset://".length) : refOrId;
|
|
1084
|
+
async function getAssetDataUrl(refOrId) {
|
|
1085
|
+
const id = extractAssetId(refOrId);
|
|
1086
|
+
const res = await fetch(apiUrl2(`/v1/assets/${encodeURIComponent(id)}?format=dataUrl`), {
|
|
1087
|
+
method: "GET",
|
|
1088
|
+
headers: { Accept: "application/json" }
|
|
1089
|
+
});
|
|
1090
|
+
if (!res.ok) {
|
|
1091
|
+
const text = await res.text().catch(() => res.statusText);
|
|
1092
|
+
throw new Error(text || `Failed to fetch asset ${refOrId}`);
|
|
1093
|
+
}
|
|
1094
|
+
const body = await res.json();
|
|
1095
|
+
const envelope = expectRecord2(body, "asset response");
|
|
1096
|
+
const data = expectRecord2(envelope.data, "asset response.data");
|
|
1097
|
+
if (typeof data.error === "string" && data.error.length > 0) {
|
|
1098
|
+
throw new Error(data.error);
|
|
1099
|
+
}
|
|
1100
|
+
if (typeof data.dataUrl !== "string" || data.dataUrl.length === 0) {
|
|
1101
|
+
throw new ContractViolation2(`asset response.data.dataUrl is required for ${refOrId}`);
|
|
1102
|
+
}
|
|
1103
|
+
return {
|
|
1104
|
+
dataUrl: data.dataUrl,
|
|
1105
|
+
mime: typeof data.mime === "string" ? data.mime : void 0,
|
|
1106
|
+
assetId: expectString2(data.assetId, "asset response.data.assetId")
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
async function resolveAssetsInMessages(messages) {
|
|
1110
|
+
const inFlightByRef = /* @__PURE__ */ new Map();
|
|
1111
|
+
const resolveAssetRef = (assetRef) => {
|
|
1112
|
+
if (!inFlightByRef.has(assetRef)) {
|
|
1113
|
+
inFlightByRef.set(assetRef, getAssetDataUrl(assetRef));
|
|
1114
|
+
}
|
|
1115
|
+
return inFlightByRef.get(assetRef);
|
|
1116
|
+
};
|
|
1117
|
+
return Promise.all(messages.map(async (msg) => {
|
|
1118
|
+
const meta = msg.metadata === null || msg.metadata === void 0 ? void 0 : expectRecord2(msg.metadata, "message.metadata");
|
|
1119
|
+
const attachments = meta?.attachments === void 0 ? void 0 : Array.isArray(meta.attachments) ? meta.attachments.map(
|
|
1120
|
+
(att, index) => expectRecord2(att, `message.metadata.attachments[${index}]`)
|
|
1121
|
+
) : (() => {
|
|
1122
|
+
throw new ContractViolation2("message.metadata.attachments must be an array");
|
|
1123
|
+
})();
|
|
1124
|
+
if (!attachments || attachments.length === 0) {
|
|
1125
|
+
return msg;
|
|
1126
|
+
}
|
|
1127
|
+
const newAttachments = await Promise.all(attachments.map(async (att, index) => {
|
|
1128
|
+
const assetRef = typeof att.assetRef === "string" ? att.assetRef : void 0;
|
|
1129
|
+
if (!assetRef) return att;
|
|
1130
|
+
const { dataUrl, mime } = await resolveAssetRef(assetRef);
|
|
1131
|
+
const kind = expectString2(att.kind, `message.metadata.attachments[${index}].kind`);
|
|
1132
|
+
const mimeType = typeof att.mimeType === "string" ? att.mimeType : expectString2(mime, `asset ${assetRef}.mime`);
|
|
1133
|
+
return {
|
|
1134
|
+
...att,
|
|
1135
|
+
kind,
|
|
1136
|
+
dataUrl,
|
|
1137
|
+
mimeType
|
|
1138
|
+
};
|
|
1139
|
+
}));
|
|
1140
|
+
const newMeta = { ...meta, attachments: newAttachments };
|
|
1141
|
+
return { ...msg, metadata: newMeta };
|
|
1142
|
+
}));
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// src/toolActivity.ts
|
|
1146
|
+
var fail = (message) => {
|
|
1147
|
+
throw new ContractViolation(message);
|
|
1148
|
+
};
|
|
1149
|
+
var expectToolStatus = (status, path) => {
|
|
1007
1150
|
if (status === "pending") return "pending";
|
|
1008
1151
|
if (status === "running" || status === "processing") return "running";
|
|
1009
1152
|
if (status === "failed") return "failed";
|
|
1010
|
-
return "completed";
|
|
1153
|
+
if (status === "completed") return "completed";
|
|
1154
|
+
return fail(`${path} must be pending, running, processing, completed, or failed`);
|
|
1011
1155
|
};
|
|
1012
|
-
var
|
|
1013
|
-
if (
|
|
1014
|
-
return value;
|
|
1015
|
-
}
|
|
1156
|
+
var expectToolArguments = (value, path) => {
|
|
1157
|
+
if (isRecord(value)) return value;
|
|
1016
1158
|
if (typeof value === "string") {
|
|
1017
1159
|
try {
|
|
1018
1160
|
const parsed = JSON.parse(value);
|
|
1019
|
-
|
|
1020
|
-
return parsed;
|
|
1021
|
-
}
|
|
1161
|
+
return expectRecord(parsed, path);
|
|
1022
1162
|
} catch {
|
|
1163
|
+
return fail(`${path} must be an object or JSON object string`);
|
|
1023
1164
|
}
|
|
1024
1165
|
}
|
|
1025
|
-
return {};
|
|
1166
|
+
return fail(`${path} must be an object or JSON object string`);
|
|
1167
|
+
};
|
|
1168
|
+
var expectToolName = (tool, path) => {
|
|
1169
|
+
const name = typeof tool.name === "string" && tool.name.trim().length > 0 ? tool.name : tool.id;
|
|
1170
|
+
return expectString(name, path);
|
|
1026
1171
|
};
|
|
1027
1172
|
var matchesToolResultUpdate = (target, update) => {
|
|
1028
1173
|
if (update.id && target.id) {
|
|
@@ -1030,92 +1175,84 @@ var matchesToolResultUpdate = (target, update) => {
|
|
|
1030
1175
|
}
|
|
1031
1176
|
return Boolean(update.name && target.name && update.name === target.name);
|
|
1032
1177
|
};
|
|
1033
|
-
var
|
|
1034
|
-
{ id:
|
|
1178
|
+
var findMatchingToolItem = (toolItems, update) => toolItems.find((item) => matchesToolResultUpdate(
|
|
1179
|
+
{ id: item.id, name: item.toolName },
|
|
1035
1180
|
update
|
|
1036
|
-
) && (
|
|
1181
|
+
) && (item.status === "active" || item.details?.result === void 0));
|
|
1037
1182
|
var applyToolResultUpdateToMessages = (messages, update, assistantPatch) => {
|
|
1038
1183
|
const nextMessages = [...messages];
|
|
1039
1184
|
for (let i = nextMessages.length - 1; i >= 0; i--) {
|
|
1040
1185
|
const message = nextMessages[i];
|
|
1041
|
-
|
|
1186
|
+
const toolItems = message.activity?.items.filter((item) => item.kind === "tool") ?? [];
|
|
1187
|
+
if (message.role !== "assistant" || toolItems.length === 0) {
|
|
1042
1188
|
continue;
|
|
1043
1189
|
}
|
|
1044
|
-
const
|
|
1045
|
-
if (
|
|
1046
|
-
nextMessages[i] =
|
|
1190
|
+
const toolItem = findMatchingToolItem(toolItems, update);
|
|
1191
|
+
if (!toolItem) continue;
|
|
1192
|
+
nextMessages[i] = {
|
|
1047
1193
|
...applyAssistantToolResult(message, {
|
|
1048
1194
|
...update.id ? { id: update.id } : {},
|
|
1049
|
-
name: update.name ??
|
|
1195
|
+
name: update.name ?? toolItem.toolName ?? toolItem.id,
|
|
1050
1196
|
status: update.status,
|
|
1051
1197
|
...update.result !== void 0 ? { result: update.result } : {},
|
|
1052
1198
|
endTime: update.endTime
|
|
1053
1199
|
}),
|
|
1054
1200
|
...assistantPatch ?? {}
|
|
1055
|
-
}
|
|
1201
|
+
};
|
|
1056
1202
|
return { messages: nextMessages, matched: true };
|
|
1057
1203
|
}
|
|
1058
1204
|
return { messages, matched: false };
|
|
1059
1205
|
};
|
|
1060
1206
|
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;
|
|
1207
|
+
const payloadRecord = expectRecord(payload, "TOOL_CALL payload");
|
|
1208
|
+
const toolCall = expectRecord(payloadRecord.toolCall, "TOOL_CALL payload.toolCall");
|
|
1209
|
+
const tool = expectRecord(toolCall.tool, "TOOL_CALL payload.toolCall.tool");
|
|
1066
1210
|
return {
|
|
1067
|
-
|
|
1068
|
-
name,
|
|
1069
|
-
arguments:
|
|
1070
|
-
status:
|
|
1071
|
-
...
|
|
1211
|
+
id: expectString(toolCall.id, "TOOL_CALL payload.toolCall.id"),
|
|
1212
|
+
name: expectToolName(tool, "TOOL_CALL payload.toolCall.tool.id"),
|
|
1213
|
+
arguments: expectToolArguments(toolCall.args, "TOOL_CALL payload.toolCall.args"),
|
|
1214
|
+
status: toolCall.status === void 0 ? "running" : expectToolStatus(toolCall.status, "TOOL_CALL payload.toolCall.status"),
|
|
1215
|
+
...toolCall.output !== void 0 ? { result: toolCall.output } : {}
|
|
1072
1216
|
};
|
|
1073
1217
|
};
|
|
1074
|
-
var extractLiveToolResultUpdate = (payload) => {
|
|
1075
|
-
const
|
|
1076
|
-
const
|
|
1218
|
+
var extractLiveToolResultUpdate = (payload, now = () => Date.now()) => {
|
|
1219
|
+
const payloadRecord = expectRecord(payload, "TOOL_RESULT payload");
|
|
1220
|
+
const tool = expectRecord(payloadRecord.tool, "TOOL_RESULT payload.tool");
|
|
1221
|
+
const result = payloadRecord.projectedOutput !== void 0 ? payloadRecord.projectedOutput : payloadRecord.output;
|
|
1222
|
+
if (result === void 0) fail("TOOL_RESULT payload requires output or projectedOutput");
|
|
1077
1223
|
return {
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
status:
|
|
1081
|
-
|
|
1082
|
-
endTime:
|
|
1224
|
+
id: expectString(payloadRecord.toolCallId, "TOOL_RESULT payload.toolCallId"),
|
|
1225
|
+
name: expectToolName(tool, "TOOL_RESULT payload.tool.id"),
|
|
1226
|
+
status: expectToolStatus(payloadRecord.status, "TOOL_RESULT payload.status"),
|
|
1227
|
+
result,
|
|
1228
|
+
endTime: now()
|
|
1083
1229
|
};
|
|
1084
1230
|
};
|
|
1085
1231
|
var extractToolCallsFromServerMessage = (msg) => {
|
|
1086
|
-
const metadata = msg.metadata
|
|
1087
|
-
const topLevelToolCalls =
|
|
1088
|
-
const metadataToolCalls =
|
|
1232
|
+
const metadata = msg.metadata === null || msg.metadata === void 0 ? void 0 : expectRecord(msg.metadata, "message.metadata");
|
|
1233
|
+
const topLevelToolCalls = readToolCallArray(msg.toolCalls, "message.toolCalls");
|
|
1234
|
+
const metadataToolCalls = readToolCallArray(metadata?.toolCalls, "message.metadata.toolCalls");
|
|
1089
1235
|
const usedMetadataIndexes = /* @__PURE__ */ new Set();
|
|
1090
1236
|
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
1237
|
const findMatchingMetadataIndex = (toolCall) => {
|
|
1099
|
-
const id =
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
return name ? metadataToolCalls.findIndex((candidate, idx) => !usedMetadataIndexes.has(idx) && extractToolName(candidate) === name) : -1;
|
|
1238
|
+
const id = expectString(toolCall.id, "message.toolCalls[].id");
|
|
1239
|
+
return metadataToolCalls.findIndex(
|
|
1240
|
+
(candidate, idx) => !usedMetadataIndexes.has(idx) && candidate.id === id
|
|
1241
|
+
);
|
|
1104
1242
|
};
|
|
1105
1243
|
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);
|
|
1244
|
+
const id = expectString(primary.id ?? secondary?.id, "toolCall.id");
|
|
1245
|
+
const tool = expectRecord(primary.tool ?? secondary?.tool, "toolCall.tool");
|
|
1246
|
+
const name = expectToolName(tool, "toolCall.tool.id");
|
|
1247
|
+
const argsRaw = primary.args ?? secondary?.args;
|
|
1248
|
+
const result = primary.output !== void 0 ? primary.output : secondary?.output !== void 0 ? secondary.output : primary.projectedOutput !== void 0 ? primary.projectedOutput : secondary?.projectedOutput;
|
|
1249
|
+
const rawStatus = primary.status ?? secondary?.status;
|
|
1113
1250
|
return {
|
|
1114
|
-
|
|
1251
|
+
id,
|
|
1115
1252
|
name,
|
|
1116
|
-
arguments:
|
|
1253
|
+
arguments: expectToolArguments(argsRaw, "toolCall.args"),
|
|
1117
1254
|
...result !== void 0 ? { result } : {},
|
|
1118
|
-
status
|
|
1255
|
+
status: rawStatus === void 0 ? "running" : expectToolStatus(rawStatus, "toolCall.status")
|
|
1119
1256
|
};
|
|
1120
1257
|
};
|
|
1121
1258
|
topLevelToolCalls.forEach((toolCall) => {
|
|
@@ -1130,20 +1267,24 @@ var extractToolCallsFromServerMessage = (msg) => {
|
|
|
1130
1267
|
});
|
|
1131
1268
|
return parsed;
|
|
1132
1269
|
};
|
|
1133
|
-
var
|
|
1270
|
+
var readToolCallArray = (value, path) => {
|
|
1271
|
+
if (value === null || value === void 0) return [];
|
|
1272
|
+
if (!Array.isArray(value)) fail(`${path} must be an array`);
|
|
1273
|
+
return value.map((toolCall, index) => expectRecord(toolCall, `${path}[${index}]`));
|
|
1274
|
+
};
|
|
1275
|
+
var extractToolResultUpdateFromMessage = (msg, now = () => Date.now()) => {
|
|
1134
1276
|
if (msg.senderType !== "tool") return null;
|
|
1135
1277
|
const toolCalls = extractToolCallsFromServerMessage(msg);
|
|
1136
|
-
if (
|
|
1278
|
+
if (toolCalls.length === 0) fail("tool message requires metadata.toolCalls");
|
|
1137
1279
|
const firstToolCall = toolCalls[0];
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
const result = firstToolCall.result !== void 0 ? firstToolCall.result : fallbackResult;
|
|
1280
|
+
if (firstToolCall.result === void 0) fail("tool result message requires tool call output");
|
|
1281
|
+
expectStringValue(msg.createdAt, "tool result message.createdAt");
|
|
1141
1282
|
return {
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1283
|
+
id: firstToolCall.id,
|
|
1284
|
+
name: firstToolCall.name,
|
|
1285
|
+
result: firstToolCall.result,
|
|
1145
1286
|
status: firstToolCall.status,
|
|
1146
|
-
endTime:
|
|
1287
|
+
endTime: new Date(msg.createdAt).getTime()
|
|
1147
1288
|
};
|
|
1148
1289
|
};
|
|
1149
1290
|
var mergePersistedToolResults = (messages, updates) => {
|
|
@@ -1166,42 +1307,95 @@ var prependUniqueMessages = (olderMessages, currentMessages) => {
|
|
|
1166
1307
|
}
|
|
1167
1308
|
return combined;
|
|
1168
1309
|
};
|
|
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
|
-
|
|
1310
|
+
var messageAgentKey = (message) => {
|
|
1311
|
+
if (message.role !== "assistant") return null;
|
|
1312
|
+
if (message.sender?.type === "agent" || message.sender?.type === "tool") {
|
|
1313
|
+
return message.sender.agentId ?? message.sender.id;
|
|
1314
|
+
}
|
|
1315
|
+
return null;
|
|
1316
|
+
};
|
|
1317
|
+
var canAttachToStreamingAssistant = (message, incomingAgentKey) => {
|
|
1318
|
+
if (!message || message.role !== "assistant" || !message.isStreaming) {
|
|
1319
|
+
return false;
|
|
1320
|
+
}
|
|
1321
|
+
const currentAgentKey = messageAgentKey(message);
|
|
1322
|
+
return !incomingAgentKey || !currentAgentKey || currentAgentKey === incomingAgentKey;
|
|
1323
|
+
};
|
|
1324
|
+
|
|
1325
|
+
// src/messageContract.ts
|
|
1326
|
+
var isInternalMessageMetadata = (metadata) => metadata?.visibility === "internal";
|
|
1327
|
+
var defaultCreateId = () => globalThis.crypto?.randomUUID?.() ?? `id-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1328
|
+
var defaultNow = () => Date.now();
|
|
1329
|
+
var roleBySender = {
|
|
1330
|
+
user: "user",
|
|
1331
|
+
agent: "assistant",
|
|
1332
|
+
tool: "assistant",
|
|
1333
|
+
system: "system"
|
|
1334
|
+
};
|
|
1335
|
+
var expectNumber = (value, path) => {
|
|
1336
|
+
if (typeof value !== "number" || Number.isNaN(value)) throw new ContractViolation(`${path} must be a number`);
|
|
1337
|
+
return value;
|
|
1338
|
+
};
|
|
1339
|
+
var extractAttachments = (metadata) => {
|
|
1340
|
+
if (metadata?.attachments === void 0) return [];
|
|
1341
|
+
if (!Array.isArray(metadata.attachments)) {
|
|
1342
|
+
throw new ContractViolation("message.metadata.attachments must be an array");
|
|
1343
|
+
}
|
|
1344
|
+
return metadata.attachments.map((value, index) => {
|
|
1345
|
+
const path = `message.metadata.attachments[${index}]`;
|
|
1346
|
+
const att = expectRecord(value, path);
|
|
1347
|
+
const base = {
|
|
1348
|
+
kind: expectString(att.kind, `${path}.kind`),
|
|
1349
|
+
dataUrl: expectString(att.dataUrl, `${path}.dataUrl`),
|
|
1350
|
+
mimeType: expectString(att.mimeType, `${path}.mimeType`)
|
|
1351
|
+
};
|
|
1352
|
+
if (base.kind === "image") return base;
|
|
1353
|
+
if (base.kind === "audio") return {
|
|
1354
|
+
...base,
|
|
1355
|
+
...att.durationMs !== void 0 ? { durationMs: expectNumber(att.durationMs, `${path}.durationMs`) } : {}
|
|
1356
|
+
};
|
|
1357
|
+
if (base.kind === "video") return {
|
|
1358
|
+
...base,
|
|
1359
|
+
...att.durationMs !== void 0 ? { durationMs: expectNumber(att.durationMs, `${path}.durationMs`) } : {},
|
|
1360
|
+
...att.poster !== void 0 ? { poster: expectString(att.poster, `${path}.poster`) } : {}
|
|
1361
|
+
};
|
|
1362
|
+
throw new ContractViolation(`${path}.kind must be image, audio, or video`);
|
|
1199
1363
|
});
|
|
1200
|
-
|
|
1364
|
+
};
|
|
1365
|
+
var assertRestMessageContract = (msg) => {
|
|
1366
|
+
expectString(msg.id, "message.id");
|
|
1367
|
+
expectString(msg.threadId, "message.threadId");
|
|
1368
|
+
if (!(msg.senderType in roleBySender)) throw new ContractViolation("message.senderType must be user, agent, tool, or system");
|
|
1369
|
+
expectStringValue(msg.content, "message.content");
|
|
1370
|
+
if (msg.metadata !== void 0 && msg.metadata !== null) expectRecord(msg.metadata, "message.metadata");
|
|
1371
|
+
if (msg.createdAt !== void 0) expectString(msg.createdAt, "message.createdAt");
|
|
1372
|
+
};
|
|
1373
|
+
var shouldRenderHydratedMessage = (msg) => {
|
|
1374
|
+
assertRestMessageContract(msg);
|
|
1375
|
+
const meta = msg.metadata ?? {};
|
|
1376
|
+
if (isInternalMessageMetadata(meta)) {
|
|
1377
|
+
return false;
|
|
1378
|
+
}
|
|
1379
|
+
const text = expectStringValue(msg.content, "message.content").trim();
|
|
1380
|
+
const hasText = text.length > 0;
|
|
1381
|
+
const hasToolCalls = extractToolCallsFromServerMessage(msg).length > 0;
|
|
1382
|
+
const hasAttachments = extractAttachments(meta).length > 0;
|
|
1383
|
+
if (msg.senderType === "tool") {
|
|
1384
|
+
return hasAttachments;
|
|
1385
|
+
}
|
|
1386
|
+
return hasText || hasToolCalls || hasAttachments;
|
|
1387
|
+
};
|
|
1388
|
+
var convertServerMessage = (msg, options = {}) => {
|
|
1389
|
+
assertRestMessageContract(msg);
|
|
1390
|
+
const timestamp = msg.createdAt ? new Date(msg.createdAt).getTime() : (options.now ?? defaultNow)();
|
|
1391
|
+
const metadata = msg.metadata ?? void 0;
|
|
1392
|
+
const attachments = extractAttachments(metadata);
|
|
1393
|
+
const messageContent = expectStringValue(msg.content, "message.content");
|
|
1394
|
+
const role = roleBySender[msg.senderType];
|
|
1201
1395
|
const parsedToolCalls = extractToolCallsFromServerMessage(msg);
|
|
1202
1396
|
const shouldRenderToolCalls = msg.senderType !== "tool";
|
|
1203
1397
|
const mappedToolCalls = parsedToolCalls.map((toolCall) => ({
|
|
1204
|
-
id: toolCall.id ??
|
|
1398
|
+
id: toolCall.id ?? (options.createId ?? defaultCreateId)(),
|
|
1205
1399
|
name: toolCall.name,
|
|
1206
1400
|
arguments: toolCall.arguments,
|
|
1207
1401
|
status: toolCall.status,
|
|
@@ -1209,11 +1403,31 @@ var convertServerMessage = (msg) => {
|
|
|
1209
1403
|
}));
|
|
1210
1404
|
const hasToolCalls = shouldRenderToolCalls && mappedToolCalls.length > 0;
|
|
1211
1405
|
const isToolSender = msg.senderType === "tool";
|
|
1212
|
-
const content = isToolSender ? "" :
|
|
1406
|
+
const content = isToolSender ? "" : messageContent;
|
|
1213
1407
|
const reasoning = typeof msg.reasoning === "string" && msg.reasoning.length > 0 ? msg.reasoning : void 0;
|
|
1214
|
-
const
|
|
1215
|
-
|
|
1216
|
-
|
|
1408
|
+
const activityItems = [
|
|
1409
|
+
...reasoning ? [{
|
|
1410
|
+
id: `${msg.id}:thinking`,
|
|
1411
|
+
kind: "thinking",
|
|
1412
|
+
status: "complete",
|
|
1413
|
+
completedAt: timestamp,
|
|
1414
|
+
details: { reasoning }
|
|
1415
|
+
}] : [],
|
|
1416
|
+
...hasToolCalls ? mappedToolCalls.map((toolCall) => ({
|
|
1417
|
+
id: toolCall.id,
|
|
1418
|
+
kind: "tool",
|
|
1419
|
+
status: toolCall.status === "failed" ? "failed" : toolCall.status === "completed" ? "complete" : "active",
|
|
1420
|
+
toolName: toolCall.name,
|
|
1421
|
+
startedAt: toolCall.startTime,
|
|
1422
|
+
completedAt: toolCall.endTime,
|
|
1423
|
+
details: {
|
|
1424
|
+
toolCall,
|
|
1425
|
+
...toolCall.result !== void 0 ? { result: toolCall.result } : {}
|
|
1426
|
+
}
|
|
1427
|
+
})) : []
|
|
1428
|
+
];
|
|
1429
|
+
const sender = resolveHydratedMessageSender(msg, options.senderOptions);
|
|
1430
|
+
return {
|
|
1217
1431
|
id: msg.id,
|
|
1218
1432
|
role,
|
|
1219
1433
|
content,
|
|
@@ -1222,14 +1436,49 @@ var convertServerMessage = (msg) => {
|
|
|
1222
1436
|
isStreaming: false,
|
|
1223
1437
|
isComplete: true,
|
|
1224
1438
|
metadata,
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1439
|
+
activity: activityItems.length > 0 ? { items: activityItems } : void 0,
|
|
1440
|
+
sender
|
|
1441
|
+
};
|
|
1442
|
+
};
|
|
1443
|
+
var prepareHydratedMessages = async (rawMessages, options = {}) => {
|
|
1444
|
+
rawMessages.forEach(assertRestMessageContract);
|
|
1445
|
+
const resolvedMessages = await resolveAssetsInMessages(rawMessages);
|
|
1446
|
+
resolvedMessages.forEach((msg) => {
|
|
1447
|
+
if (msg.senderType === "tool") {
|
|
1448
|
+
const metadata = msg.metadata ?? void 0;
|
|
1449
|
+
if (!metadata) {
|
|
1450
|
+
throw new ContractViolation("tool message requires metadata");
|
|
1451
|
+
}
|
|
1452
|
+
options.onToolOutput?.(metadata.output === void 0 ? metadata : { output: metadata.output });
|
|
1453
|
+
}
|
|
1229
1454
|
});
|
|
1455
|
+
const now = options.now ?? defaultNow;
|
|
1456
|
+
const toolResultUpdates = resolvedMessages.map((msg) => extractToolResultUpdateFromMessage(msg, now)).filter((update) => update !== null);
|
|
1457
|
+
const viewMessages = resolvedMessages.filter(shouldRenderHydratedMessage).map((msg) => convertServerMessage(msg, options));
|
|
1458
|
+
return {
|
|
1459
|
+
viewMessages,
|
|
1460
|
+
toolResultUpdates
|
|
1461
|
+
};
|
|
1230
1462
|
};
|
|
1463
|
+
|
|
1464
|
+
// src/useCopilotzChat.ts
|
|
1465
|
+
var nowTs = () => Date.now();
|
|
1466
|
+
var generateId = () => globalThis.crypto?.randomUUID?.() ?? `id-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1467
|
+
var isAbortError = (error) => error instanceof DOMException && error.name === "AbortError" || typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
|
|
1468
|
+
var getEventPayload = (event) => event?.payload ?? event;
|
|
1469
|
+
var getEventSenderType = (payload) => payload?.senderType || payload?.sender?.type;
|
|
1470
|
+
var THREAD_MESSAGES_PAGE_SIZE = 50;
|
|
1471
|
+
var createEmptyMessagePageInfo = () => ({
|
|
1472
|
+
hasMoreBefore: false,
|
|
1473
|
+
oldestMessageId: null,
|
|
1474
|
+
newestMessageId: null
|
|
1475
|
+
});
|
|
1231
1476
|
function useCopilotz({
|
|
1232
1477
|
userId,
|
|
1478
|
+
userName,
|
|
1479
|
+
userAvatar,
|
|
1480
|
+
assistantName,
|
|
1481
|
+
agentOptions = [],
|
|
1233
1482
|
initialContext,
|
|
1234
1483
|
bootstrap,
|
|
1235
1484
|
defaultThreadName,
|
|
@@ -1269,6 +1518,11 @@ function useCopilotz({
|
|
|
1269
1518
|
const userContextSeedRef = useRef2(userContextSeed);
|
|
1270
1519
|
const messagePageInfoRef = useRef2(messagePageInfo);
|
|
1271
1520
|
const isLoadingOlderMessagesRef = useRef2(isLoadingOlderMessages);
|
|
1521
|
+
const senderOptionsRef = useRef2({
|
|
1522
|
+
agents: agentOptions,
|
|
1523
|
+
user: userId ? { id: userId, name: userName, avatarUrl: userAvatar } : null,
|
|
1524
|
+
assistantName
|
|
1525
|
+
});
|
|
1272
1526
|
const persistedToolUpdatesRef = useRef2([]);
|
|
1273
1527
|
const liveToolUpdatesRef = useRef2([]);
|
|
1274
1528
|
threadsRef.current = threads;
|
|
@@ -1279,6 +1533,11 @@ function useCopilotz({
|
|
|
1279
1533
|
userContextSeedRef.current = userContextSeed;
|
|
1280
1534
|
messagePageInfoRef.current = messagePageInfo;
|
|
1281
1535
|
isLoadingOlderMessagesRef.current = isLoadingOlderMessages;
|
|
1536
|
+
senderOptionsRef.current = {
|
|
1537
|
+
agents: agentOptions,
|
|
1538
|
+
user: userId ? { id: userId, name: userName, avatarUrl: userAvatar } : null,
|
|
1539
|
+
assistantName
|
|
1540
|
+
};
|
|
1282
1541
|
preferredAgentRef.current = preferredAgentName ?? null;
|
|
1283
1542
|
participantsRef.current = participants ?? null;
|
|
1284
1543
|
targetAgentNameRef.current = targetAgentName ?? null;
|
|
@@ -1335,20 +1594,20 @@ function useCopilotz({
|
|
|
1335
1594
|
}
|
|
1336
1595
|
const senderType = getEventSenderType(payload);
|
|
1337
1596
|
if (senderType !== "agent" || typeof payload.content !== "string") return;
|
|
1338
|
-
const
|
|
1339
|
-
const incomingAgentKey =
|
|
1597
|
+
const sender = resolveLiveEventSender(event, senderOptionsRef.current);
|
|
1598
|
+
const incomingAgentKey = sender.agentId ?? sender.id;
|
|
1340
1599
|
setMessages((prev) => {
|
|
1341
1600
|
const next = [...prev];
|
|
1342
1601
|
for (let i = next.length - 1; i >= 0; i--) {
|
|
1343
1602
|
const m = next[i];
|
|
1344
1603
|
if (canAttachToStreamingAssistant(m, incomingAgentKey)) {
|
|
1345
|
-
next[i] =
|
|
1604
|
+
next[i] = {
|
|
1346
1605
|
...m,
|
|
1347
1606
|
content: payload.content,
|
|
1348
1607
|
isStreaming: false,
|
|
1349
1608
|
isComplete: true,
|
|
1350
|
-
|
|
1351
|
-
}
|
|
1609
|
+
sender
|
|
1610
|
+
};
|
|
1352
1611
|
return next;
|
|
1353
1612
|
}
|
|
1354
1613
|
}
|
|
@@ -1358,7 +1617,7 @@ function useCopilotz({
|
|
|
1358
1617
|
}
|
|
1359
1618
|
return [
|
|
1360
1619
|
...next,
|
|
1361
|
-
|
|
1620
|
+
{
|
|
1362
1621
|
id: generateId(),
|
|
1363
1622
|
role: "assistant",
|
|
1364
1623
|
content: payload.content,
|
|
@@ -1366,8 +1625,8 @@ function useCopilotz({
|
|
|
1366
1625
|
isStreaming: false,
|
|
1367
1626
|
isComplete: true,
|
|
1368
1627
|
metadata: liveMetadata,
|
|
1369
|
-
|
|
1370
|
-
}
|
|
1628
|
+
sender
|
|
1629
|
+
}
|
|
1371
1630
|
];
|
|
1372
1631
|
});
|
|
1373
1632
|
}, []);
|
|
@@ -1424,33 +1683,12 @@ function useCopilotz({
|
|
|
1424
1683
|
}
|
|
1425
1684
|
}, [updateThreadsState, getRequestHeaders]);
|
|
1426
1685
|
const prepareThreadMessages = useCallback2(async (rawMessages) => {
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
if (output) processToolOutput(output);
|
|
1433
|
-
}
|
|
1686
|
+
return prepareHydratedMessages(rawMessages, {
|
|
1687
|
+
senderOptions: senderOptionsRef.current,
|
|
1688
|
+
createId: generateId,
|
|
1689
|
+
now: nowTs,
|
|
1690
|
+
onToolOutput: processToolOutput
|
|
1434
1691
|
});
|
|
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
1692
|
}, [processToolOutput]);
|
|
1455
1693
|
const loadThreadMessages = useCallback2(async (threadId) => {
|
|
1456
1694
|
const requestId = messagesRequestRef.current + 1;
|
|
@@ -1658,14 +1896,14 @@ function useCopilotz({
|
|
|
1658
1896
|
dataUrl,
|
|
1659
1897
|
mimeType
|
|
1660
1898
|
};
|
|
1661
|
-
setMessages((prev) => prev.map((msg) => msg.id === assistantMessageId ?
|
|
1899
|
+
setMessages((prev) => prev.map((msg) => msg.id === assistantMessageId ? {
|
|
1662
1900
|
...msg,
|
|
1663
1901
|
attachments: [...msg.attachments || [], mediaAttachment]
|
|
1664
|
-
}
|
|
1902
|
+
} : msg));
|
|
1665
1903
|
}, []);
|
|
1666
1904
|
const sendCopilotzMessage = useCallback2(async (params) => {
|
|
1667
|
-
let currentAssistantId = generateId();
|
|
1668
|
-
let
|
|
1905
|
+
let currentAssistantId = params.assistantMessageId ?? generateId();
|
|
1906
|
+
let currentAssistantSender = params.assistantSender;
|
|
1669
1907
|
params.onBeforeStart?.(currentAssistantId);
|
|
1670
1908
|
let hasStreamProgress = false;
|
|
1671
1909
|
const updateStreamingMessage = (partial, opts) => {
|
|
@@ -1673,28 +1911,26 @@ function useCopilotz({
|
|
|
1673
1911
|
hasStreamProgress = true;
|
|
1674
1912
|
}
|
|
1675
1913
|
const isReasoning = opts?.isReasoning ?? false;
|
|
1676
|
-
const
|
|
1677
|
-
if (
|
|
1678
|
-
|
|
1679
|
-
...currentAssistantIdentity,
|
|
1680
|
-
...nextIdentity
|
|
1681
|
-
};
|
|
1914
|
+
const nextSender = opts?.agent ? resolveAgentSender(opts.agent, senderOptionsRef.current) : currentAssistantSender;
|
|
1915
|
+
if (nextSender) {
|
|
1916
|
+
currentAssistantSender = nextSender;
|
|
1682
1917
|
}
|
|
1683
|
-
const
|
|
1684
|
-
const nextAgentKey = agentIdentity.senderAgentId ?? agentIdentity.senderName ?? null;
|
|
1918
|
+
const nextAgentKey = currentAssistantSender?.agentId ?? currentAssistantSender?.id ?? null;
|
|
1685
1919
|
const applyUpdate = (msg) => {
|
|
1686
|
-
return
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1920
|
+
return {
|
|
1921
|
+
...updateAssistantMessageToken(msg, {
|
|
1922
|
+
partial,
|
|
1923
|
+
isReasoning
|
|
1924
|
+
}),
|
|
1925
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
1926
|
+
};
|
|
1691
1927
|
};
|
|
1692
1928
|
setMessages((prev) => {
|
|
1693
1929
|
const idx = prev.findIndex((m) => m.id === currentAssistantId);
|
|
1694
1930
|
if (idx >= 0 && canAttachToStreamingAssistant(prev[idx], nextAgentKey)) {
|
|
1695
1931
|
const msg = prev[idx];
|
|
1696
1932
|
const next = applyUpdate(msg);
|
|
1697
|
-
if (msg.content === next.content && msg.
|
|
1933
|
+
if (msg.content === next.content && msg.activity === next.activity && msg.isStreaming === next.isStreaming && msg.isComplete === next.isComplete) {
|
|
1698
1934
|
return prev;
|
|
1699
1935
|
}
|
|
1700
1936
|
const updated = [...prev];
|
|
@@ -1705,7 +1941,7 @@ function useCopilotz({
|
|
|
1705
1941
|
if (canAttachToStreamingAssistant(last, nextAgentKey)) {
|
|
1706
1942
|
currentAssistantId = last.id;
|
|
1707
1943
|
const next = applyUpdate(last);
|
|
1708
|
-
if (last.content === next.content && last.
|
|
1944
|
+
if (last.content === next.content && last.activity === next.activity && last.isStreaming === next.isStreaming && last.isComplete === next.isComplete) {
|
|
1709
1945
|
return prev;
|
|
1710
1946
|
}
|
|
1711
1947
|
const updated = [...prev];
|
|
@@ -1723,7 +1959,7 @@ function useCopilotz({
|
|
|
1723
1959
|
timestamp: nowTs(),
|
|
1724
1960
|
isStreaming: true,
|
|
1725
1961
|
isComplete: false,
|
|
1726
|
-
...
|
|
1962
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
1727
1963
|
};
|
|
1728
1964
|
return [...prev, applyUpdate(base)];
|
|
1729
1965
|
}
|
|
@@ -1770,7 +2006,7 @@ function useCopilotz({
|
|
|
1770
2006
|
if (fallbackIdx < 0) return prev;
|
|
1771
2007
|
const message = prev[fallbackIdx];
|
|
1772
2008
|
const nextMessage = finalizeAssistantMessage(message, finalAnswer);
|
|
1773
|
-
if (message.content === nextMessage.content && message.isStreaming === nextMessage.isStreaming && message.isComplete === nextMessage.isComplete && message.
|
|
2009
|
+
if (message.content === nextMessage.content && message.isStreaming === nextMessage.isStreaming && message.isComplete === nextMessage.isComplete && message.activity === nextMessage.activity) {
|
|
1774
2010
|
return prev;
|
|
1775
2011
|
}
|
|
1776
2012
|
const updated = [...prev];
|
|
@@ -1785,7 +2021,6 @@ function useCopilotz({
|
|
|
1785
2021
|
const payload = event?.payload ?? event;
|
|
1786
2022
|
if (type === "TOOL_CALL") {
|
|
1787
2023
|
const parsedToolCall = extractLiveToolCall(payload);
|
|
1788
|
-
if (!parsedToolCall) return null;
|
|
1789
2024
|
return {
|
|
1790
2025
|
id: generateId(),
|
|
1791
2026
|
threadId: curThreadId ?? "",
|
|
@@ -1871,14 +2106,9 @@ function useCopilotz({
|
|
|
1871
2106
|
const parsedToolCall = extractLiveToolCall(
|
|
1872
2107
|
payload ?? {}
|
|
1873
2108
|
);
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
currentAssistantIdentity = {
|
|
1878
|
-
...currentAssistantIdentity,
|
|
1879
|
-
...eventAgentIdentity
|
|
1880
|
-
};
|
|
1881
|
-
}
|
|
2109
|
+
const eventSender = resolveLiveEventSender(event, senderOptionsRef.current);
|
|
2110
|
+
currentAssistantSender = eventSender;
|
|
2111
|
+
const eventAgentKey = currentAssistantSender.agentId ?? currentAssistantSender.id;
|
|
1882
2112
|
const callId = parsedToolCall.id ?? generateId();
|
|
1883
2113
|
const toolName = parsedToolCall.name;
|
|
1884
2114
|
const bufferedUpdates = liveToolUpdatesRef.current;
|
|
@@ -1892,6 +2122,10 @@ function useCopilotz({
|
|
|
1892
2122
|
const endTime = bufferedUpdate?.endTime;
|
|
1893
2123
|
setMessages(
|
|
1894
2124
|
(prev) => (() => {
|
|
2125
|
+
const canHostActivity = (message) => {
|
|
2126
|
+
if (!message) return false;
|
|
2127
|
+
return message.role === "assistant" && message.isStreaming && message.content.trim().length === 0 && !message.attachments?.length;
|
|
2128
|
+
};
|
|
1895
2129
|
const appendToolCall = (msg) => ({
|
|
1896
2130
|
...appendAssistantToolCall(msg, {
|
|
1897
2131
|
id: callId,
|
|
@@ -1903,21 +2137,21 @@ function useCopilotz({
|
|
|
1903
2137
|
...endTime !== void 0 ? { endTime } : {}
|
|
1904
2138
|
})
|
|
1905
2139
|
});
|
|
1906
|
-
const currentIdx = prev.findIndex((message) => message.id === currentAssistantId && message.role === "assistant" && message.isStreaming);
|
|
2140
|
+
const currentIdx = prev.findIndex((message) => message.id === currentAssistantId && message.role === "assistant" && message.isStreaming && canHostActivity(message));
|
|
1907
2141
|
if (currentIdx >= 0) {
|
|
1908
2142
|
const next = [...prev];
|
|
1909
2143
|
next[currentIdx] = appendToolCall({
|
|
1910
2144
|
...next[currentIdx],
|
|
1911
2145
|
isStreaming: true,
|
|
1912
2146
|
isComplete: false,
|
|
1913
|
-
...
|
|
2147
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
1914
2148
|
});
|
|
1915
2149
|
return next;
|
|
1916
2150
|
}
|
|
1917
2151
|
const last = prev[prev.length - 1];
|
|
1918
|
-
if (canAttachToStreamingAssistant(
|
|
2152
|
+
if (canHostActivity(last) && canAttachToStreamingAssistant(
|
|
1919
2153
|
last,
|
|
1920
|
-
|
|
2154
|
+
eventAgentKey
|
|
1921
2155
|
)) {
|
|
1922
2156
|
currentAssistantId = last.id;
|
|
1923
2157
|
const next = [...prev];
|
|
@@ -1925,7 +2159,7 @@ function useCopilotz({
|
|
|
1925
2159
|
...last,
|
|
1926
2160
|
isStreaming: true,
|
|
1927
2161
|
isComplete: false,
|
|
1928
|
-
...
|
|
2162
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
1929
2163
|
});
|
|
1930
2164
|
return next;
|
|
1931
2165
|
}
|
|
@@ -1940,7 +2174,7 @@ function useCopilotz({
|
|
|
1940
2174
|
timestamp: nowTs(),
|
|
1941
2175
|
isStreaming: true,
|
|
1942
2176
|
isComplete: false,
|
|
1943
|
-
...
|
|
2177
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
1944
2178
|
})
|
|
1945
2179
|
];
|
|
1946
2180
|
})()
|
|
@@ -1950,7 +2184,11 @@ function useCopilotz({
|
|
|
1950
2184
|
}
|
|
1951
2185
|
const sm = await toServerMessageFromEvent(event);
|
|
1952
2186
|
if (sm) {
|
|
1953
|
-
const viewMsg = convertServerMessage(sm
|
|
2187
|
+
const viewMsg = convertServerMessage(sm, {
|
|
2188
|
+
senderOptions: senderOptionsRef.current,
|
|
2189
|
+
createId: generateId,
|
|
2190
|
+
now: nowTs
|
|
2191
|
+
});
|
|
1954
2192
|
finalizeCurrentAssistantBubble();
|
|
1955
2193
|
setMessages((prev) => [...prev, viewMsg]);
|
|
1956
2194
|
return;
|
|
@@ -2008,8 +2246,19 @@ function useCopilotz({
|
|
|
2008
2246
|
content,
|
|
2009
2247
|
timestamp,
|
|
2010
2248
|
attachments: attachments.length > 0 ? attachments : void 0,
|
|
2011
|
-
isComplete: true
|
|
2249
|
+
isComplete: true,
|
|
2250
|
+
sender: resolveUserSender({
|
|
2251
|
+
id: userId,
|
|
2252
|
+
name: userContextSeedRef.current?.profile?.full_name ?? userId
|
|
2253
|
+
})
|
|
2012
2254
|
};
|
|
2255
|
+
const assistantSender = targetAgentNameRef.current ? resolveAgentSender(
|
|
2256
|
+
{ id: targetAgentNameRef.current, name: targetAgentNameRef.current },
|
|
2257
|
+
senderOptionsRef.current
|
|
2258
|
+
) : preferredAgentRef.current ? resolveAgentSender(
|
|
2259
|
+
{ id: preferredAgentRef.current, name: preferredAgentRef.current },
|
|
2260
|
+
senderOptionsRef.current
|
|
2261
|
+
) : resolveAssistantFallbackSender(senderOptionsRef.current);
|
|
2013
2262
|
const assistantPlaceholder = {
|
|
2014
2263
|
id: generateId(),
|
|
2015
2264
|
role: "assistant",
|
|
@@ -2017,9 +2266,9 @@ function useCopilotz({
|
|
|
2017
2266
|
timestamp: timestamp + 1,
|
|
2018
2267
|
isStreaming: true,
|
|
2019
2268
|
isComplete: false,
|
|
2020
|
-
|
|
2269
|
+
sender: assistantSender
|
|
2021
2270
|
};
|
|
2022
|
-
setMessages((prev) => [...prev, userMessage,
|
|
2271
|
+
setMessages((prev) => [...prev, userMessage, assistantPlaceholder]);
|
|
2023
2272
|
setSpecialState(null);
|
|
2024
2273
|
if (!threadsRef.current.some((t) => t.id === conversationKey)) {
|
|
2025
2274
|
const newThread = {
|
|
@@ -2043,6 +2292,8 @@ function useCopilotz({
|
|
|
2043
2292
|
// userName can be anything, but let's try to find it in context or just fallback
|
|
2044
2293
|
userName: userContextSeedRef.current?.profile?.full_name ?? userId,
|
|
2045
2294
|
agentName: preferredAgentRef.current,
|
|
2295
|
+
assistantMessageId: assistantPlaceholder.id,
|
|
2296
|
+
assistantSender,
|
|
2046
2297
|
// Include pending title for new threads
|
|
2047
2298
|
threadMetadata: pendingTitle ? { name: pendingTitle } : void 0
|
|
2048
2299
|
});
|
|
@@ -2066,24 +2317,26 @@ function useCopilotz({
|
|
|
2066
2317
|
const message = finalized[i];
|
|
2067
2318
|
if (message.role !== "assistant") continue;
|
|
2068
2319
|
const updated = [...finalized];
|
|
2069
|
-
updated[i] =
|
|
2320
|
+
updated[i] = {
|
|
2070
2321
|
...message,
|
|
2071
2322
|
content: "Desculpe, ocorreu um erro ao gerar a resposta. Por favor, tente novamente.",
|
|
2072
2323
|
isStreaming: false,
|
|
2073
|
-
isComplete: true
|
|
2074
|
-
|
|
2324
|
+
isComplete: true,
|
|
2325
|
+
sender: message.sender ?? resolveAssistantFallbackSender(senderOptionsRef.current)
|
|
2326
|
+
};
|
|
2075
2327
|
return updated;
|
|
2076
2328
|
}
|
|
2077
2329
|
return [
|
|
2078
2330
|
...finalized,
|
|
2079
|
-
|
|
2331
|
+
{
|
|
2080
2332
|
id: generateId(),
|
|
2081
2333
|
role: "assistant",
|
|
2082
2334
|
content: "Desculpe, ocorreu um erro ao gerar a resposta. Por favor, tente novamente.",
|
|
2083
2335
|
timestamp: nowTs(),
|
|
2084
2336
|
isStreaming: false,
|
|
2085
|
-
isComplete: true
|
|
2086
|
-
|
|
2337
|
+
isComplete: true,
|
|
2338
|
+
sender: resolveAssistantFallbackSender(senderOptionsRef.current)
|
|
2339
|
+
}
|
|
2087
2340
|
];
|
|
2088
2341
|
});
|
|
2089
2342
|
}
|
|
@@ -2122,14 +2375,15 @@ function useCopilotz({
|
|
|
2122
2375
|
return;
|
|
2123
2376
|
}
|
|
2124
2377
|
setMessages([
|
|
2125
|
-
|
|
2378
|
+
{
|
|
2126
2379
|
id: generateId(),
|
|
2127
2380
|
role: "assistant",
|
|
2128
2381
|
content: "N\xE3o foi poss\xEDvel iniciar a conversa. Tente novamente mais tarde.",
|
|
2129
2382
|
timestamp: nowTs(),
|
|
2130
2383
|
isStreaming: false,
|
|
2131
|
-
isComplete: true
|
|
2132
|
-
|
|
2384
|
+
isComplete: true,
|
|
2385
|
+
sender: resolveAssistantFallbackSender(senderOptionsRef.current)
|
|
2386
|
+
}
|
|
2133
2387
|
]);
|
|
2134
2388
|
}
|
|
2135
2389
|
}, [fetchAndSetThreadsState, loadThreadMessages, sendCopilotzMessage, bootstrap, defaultThreadName, getSpecialStateFromError]);
|
|
@@ -2275,6 +2529,10 @@ var CopilotzChat = ({
|
|
|
2275
2529
|
loadOlderMessages
|
|
2276
2530
|
} = useCopilotz({
|
|
2277
2531
|
userId,
|
|
2532
|
+
userName,
|
|
2533
|
+
userAvatar,
|
|
2534
|
+
assistantName: userConfig?.branding?.title,
|
|
2535
|
+
agentOptions,
|
|
2278
2536
|
initialContext,
|
|
2279
2537
|
bootstrap,
|
|
2280
2538
|
defaultThreadName: userConfig?.labels?.defaultThreadName,
|