@copilotz/chat-adapter 0.8.5 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -3
- package/dist/index.js +766 -796
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1572,6 +1572,28 @@ var generateId = () => globalThis.crypto?.randomUUID?.() ?? `id-${Date.now()}-${
|
|
|
1572
1572
|
var isAbortError = (error) => error instanceof DOMException && error.name === "AbortError" || typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
|
|
1573
1573
|
var getEventPayload = (event) => event?.payload ?? event;
|
|
1574
1574
|
var getEventSenderType = (payload) => payload?.senderType || payload?.sender?.type;
|
|
1575
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1576
|
+
var normalizeThreadTag = (value) => {
|
|
1577
|
+
if (!isRecord2(value)) return null;
|
|
1578
|
+
const id = typeof value.id === "string" ? value.id.trim() : "";
|
|
1579
|
+
const name = typeof value.name === "string" ? value.name.trim() : "";
|
|
1580
|
+
const color = typeof value.color === "string" && value.color.trim() ? value.color.trim() : void 0;
|
|
1581
|
+
if (!id || !name) return null;
|
|
1582
|
+
return color ? { id, name, color } : { id, name };
|
|
1583
|
+
};
|
|
1584
|
+
var getThreadTagsFromMetadata = (metadata) => {
|
|
1585
|
+
if (!isRecord2(metadata) || !isRecord2(metadata.public)) return [];
|
|
1586
|
+
const tags = metadata.public.tags;
|
|
1587
|
+
if (!Array.isArray(tags)) return [];
|
|
1588
|
+
return tags.map(normalizeThreadTag).filter((tag) => !!tag);
|
|
1589
|
+
};
|
|
1590
|
+
var patchMetadataPublicTags = (metadata, tags) => ({
|
|
1591
|
+
...metadata ?? {},
|
|
1592
|
+
public: {
|
|
1593
|
+
...isRecord2(metadata?.public) ? metadata.public : {},
|
|
1594
|
+
tags
|
|
1595
|
+
}
|
|
1596
|
+
});
|
|
1575
1597
|
var THREAD_MESSAGES_PAGE_SIZE = 50;
|
|
1576
1598
|
var createEmptyMessagePageInfo = () => ({
|
|
1577
1599
|
hasMoreBefore: false,
|
|
@@ -1579,36 +1601,18 @@ var createEmptyMessagePageInfo = () => ({
|
|
|
1579
1601
|
newestMessageId: null
|
|
1580
1602
|
});
|
|
1581
1603
|
var createPendingAssistantActivity = () => ({
|
|
1582
|
-
items: [
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1604
|
+
items: [
|
|
1605
|
+
{
|
|
1606
|
+
id: "thinking",
|
|
1607
|
+
kind: "thinking",
|
|
1608
|
+
status: "active",
|
|
1609
|
+
startedAt: nowTs()
|
|
1610
|
+
}
|
|
1611
|
+
]
|
|
1588
1612
|
});
|
|
1589
1613
|
var getCurrentUserDisplayName = (explicitName, fallbackId) => explicitName?.trim() || fallbackId;
|
|
1590
|
-
function useCopilotz({
|
|
1591
|
-
|
|
1592
|
-
userName,
|
|
1593
|
-
userAvatar,
|
|
1594
|
-
assistantName,
|
|
1595
|
-
agentOptions = [],
|
|
1596
|
-
initialContext,
|
|
1597
|
-
bootstrap,
|
|
1598
|
-
defaultThreadName,
|
|
1599
|
-
onToolOutput,
|
|
1600
|
-
preferredAgentName,
|
|
1601
|
-
participants,
|
|
1602
|
-
targetAgentName,
|
|
1603
|
-
getRequestHeaders,
|
|
1604
|
-
eventInterceptor,
|
|
1605
|
-
runErrorInterceptor
|
|
1606
|
-
}) {
|
|
1607
|
-
const {
|
|
1608
|
-
state: urlState,
|
|
1609
|
-
setThreadId: setUrlThreadId,
|
|
1610
|
-
isEnabled: isUrlSyncEnabled
|
|
1611
|
-
} = useUrlState();
|
|
1614
|
+
function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions = [], initialContext, bootstrap, defaultThreadName, onToolOutput, preferredAgentName, participants, targetAgentName, getRequestHeaders, eventInterceptor, runErrorInterceptor }) {
|
|
1615
|
+
const { state: urlState, setThreadId: setUrlThreadId, isEnabled: isUrlSyncEnabled } = useUrlState();
|
|
1612
1616
|
const [threads, setThreads] = useState2([]);
|
|
1613
1617
|
const [threadMetadataMap, setThreadMetadataMap] = useState2({});
|
|
1614
1618
|
const [threadExternalIdMap, setThreadExternalIdMap] = useState2({});
|
|
@@ -1663,42 +1667,51 @@ function useCopilotz({
|
|
|
1663
1667
|
setUserContextSeed((prev) => ({ ...prev, ...initialContext }));
|
|
1664
1668
|
}
|
|
1665
1669
|
}, [initialContext]);
|
|
1666
|
-
const processToolOutput = useCallback2(
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1670
|
+
const processToolOutput = useCallback2(
|
|
1671
|
+
(output) => {
|
|
1672
|
+
if (!output) return;
|
|
1673
|
+
const contextPatch = {};
|
|
1674
|
+
if (output.userContext && typeof output.userContext === "object") {
|
|
1675
|
+
Object.assign(contextPatch, output.userContext);
|
|
1676
|
+
}
|
|
1677
|
+
if (Object.keys(contextPatch).length > 0) {
|
|
1678
|
+
setUserContextSeed((prev) => ({ ...prev, ...contextPatch }));
|
|
1679
|
+
}
|
|
1680
|
+
onToolOutput?.(output);
|
|
1681
|
+
},
|
|
1682
|
+
[onToolOutput]
|
|
1683
|
+
);
|
|
1677
1684
|
const clearSpecialState = useCallback2(() => {
|
|
1678
1685
|
setSpecialState(null);
|
|
1679
1686
|
}, []);
|
|
1680
|
-
const applyEventInterceptor = useCallback2(
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1687
|
+
const applyEventInterceptor = useCallback2(
|
|
1688
|
+
(event) => {
|
|
1689
|
+
if (!eventInterceptor) return void 0;
|
|
1690
|
+
try {
|
|
1691
|
+
const result = eventInterceptor(event);
|
|
1692
|
+
if (result?.specialState) {
|
|
1693
|
+
setSpecialState(result.specialState);
|
|
1694
|
+
}
|
|
1695
|
+
return result;
|
|
1696
|
+
} catch (error) {
|
|
1697
|
+
console.error("Error in Copilotz event interceptor", error);
|
|
1698
|
+
return void 0;
|
|
1686
1699
|
}
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1700
|
+
},
|
|
1701
|
+
[eventInterceptor]
|
|
1702
|
+
);
|
|
1703
|
+
const getSpecialStateFromError = useCallback2(
|
|
1704
|
+
(error) => {
|
|
1705
|
+
if (!runErrorInterceptor) return null;
|
|
1706
|
+
try {
|
|
1707
|
+
return runErrorInterceptor(error) ?? null;
|
|
1708
|
+
} catch (interceptorError) {
|
|
1709
|
+
console.error("Error in Copilotz run error interceptor", interceptorError);
|
|
1710
|
+
return null;
|
|
1711
|
+
}
|
|
1712
|
+
},
|
|
1713
|
+
[runErrorInterceptor]
|
|
1714
|
+
);
|
|
1702
1715
|
const handleStreamMessageEvent = useCallback2((event) => {
|
|
1703
1716
|
const payload = getEventPayload(event);
|
|
1704
1717
|
if (!payload) return;
|
|
@@ -1759,6 +1772,7 @@ function useCopilotz({
|
|
|
1759
1772
|
updatedAt,
|
|
1760
1773
|
messageCount: typeof thread.metadata?.messageCount === "number" ? thread.metadata.messageCount : 0,
|
|
1761
1774
|
isArchived: thread.status === "archived",
|
|
1775
|
+
tags: getThreadTagsFromMetadata(thread.metadata),
|
|
1762
1776
|
metadata: thread.metadata ?? void 0
|
|
1763
1777
|
};
|
|
1764
1778
|
});
|
|
@@ -1786,56 +1800,61 @@ function useCopilotz({
|
|
|
1786
1800
|
setCurrentThreadExternalId(nextThreadId ? externalMap[nextThreadId] ?? null : null);
|
|
1787
1801
|
return nextThreadId;
|
|
1788
1802
|
}, []);
|
|
1789
|
-
const fetchAndSetThreadsState = useCallback2(
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
const requestId = messagesRequestRef.current + 1;
|
|
1810
|
-
messagesRequestRef.current = requestId;
|
|
1811
|
-
setIsMessagesLoading(true);
|
|
1812
|
-
setIsLoadingOlderMessages(false);
|
|
1813
|
-
setMessagePageInfo(createEmptyMessagePageInfo());
|
|
1814
|
-
persistedToolUpdatesRef.current = [];
|
|
1815
|
-
liveToolUpdatesRef.current = [];
|
|
1816
|
-
try {
|
|
1817
|
-
const page = await fetchThreadMessagesPage(
|
|
1818
|
-
threadId,
|
|
1819
|
-
{ limit: THREAD_MESSAGES_PAGE_SIZE },
|
|
1803
|
+
const fetchAndSetThreadsState = useCallback2(
|
|
1804
|
+
async (uid, preferredExternalId) => {
|
|
1805
|
+
try {
|
|
1806
|
+
const rawThreads = await fetchThreads(uid, getRequestHeaders);
|
|
1807
|
+
return updateThreadsState(rawThreads, preferredExternalId);
|
|
1808
|
+
} catch (error) {
|
|
1809
|
+
if (isAbortError(error)) return;
|
|
1810
|
+
console.error("Error loading threads", error);
|
|
1811
|
+
return null;
|
|
1812
|
+
}
|
|
1813
|
+
},
|
|
1814
|
+
[updateThreadsState, getRequestHeaders]
|
|
1815
|
+
);
|
|
1816
|
+
const prepareThreadMessages = useCallback2(
|
|
1817
|
+
async (rawMessages) => {
|
|
1818
|
+
return prepareHydratedMessages(rawMessages, {
|
|
1819
|
+
senderOptions: senderOptionsRef.current,
|
|
1820
|
+
createId: generateId,
|
|
1821
|
+
now: nowTs,
|
|
1822
|
+
onToolOutput: processToolOutput,
|
|
1820
1823
|
getRequestHeaders
|
|
1821
|
-
);
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
persistedToolUpdatesRef.current = [];
|
|
1824
|
+
});
|
|
1825
|
+
},
|
|
1826
|
+
[getRequestHeaders, processToolOutput]
|
|
1827
|
+
);
|
|
1828
|
+
const loadThreadMessages = useCallback2(
|
|
1829
|
+
async (threadId) => {
|
|
1830
|
+
const requestId = messagesRequestRef.current + 1;
|
|
1831
|
+
messagesRequestRef.current = requestId;
|
|
1832
|
+
setIsMessagesLoading(true);
|
|
1833
|
+
setIsLoadingOlderMessages(false);
|
|
1832
1834
|
setMessagePageInfo(createEmptyMessagePageInfo());
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1835
|
+
persistedToolUpdatesRef.current = [];
|
|
1836
|
+
liveToolUpdatesRef.current = [];
|
|
1837
|
+
try {
|
|
1838
|
+
const page = await fetchThreadMessagesPage(threadId, { limit: THREAD_MESSAGES_PAGE_SIZE }, getRequestHeaders);
|
|
1839
|
+
const { viewMessages, toolResultUpdates } = await prepareThreadMessages(page.data);
|
|
1840
|
+
if (messagesRequestRef.current !== requestId) return;
|
|
1841
|
+
persistedToolUpdatesRef.current = toolResultUpdates;
|
|
1842
|
+
const hydratedMessages = mergePersistedToolResults(viewMessages, persistedToolUpdatesRef.current);
|
|
1843
|
+
setMessages(hydratedMessages);
|
|
1844
|
+
setMessagePageInfo(page.pageInfo);
|
|
1845
|
+
} catch (error) {
|
|
1846
|
+
if (isAbortError(error)) return;
|
|
1847
|
+
console.error(`Error loading messages for thread ${threadId}`, error);
|
|
1848
|
+
persistedToolUpdatesRef.current = [];
|
|
1849
|
+
setMessagePageInfo(createEmptyMessagePageInfo());
|
|
1850
|
+
} finally {
|
|
1851
|
+
if (messagesRequestRef.current === requestId) {
|
|
1852
|
+
setIsMessagesLoading(false);
|
|
1853
|
+
}
|
|
1836
1854
|
}
|
|
1837
|
-
}
|
|
1838
|
-
|
|
1855
|
+
},
|
|
1856
|
+
[getRequestHeaders, prepareThreadMessages]
|
|
1857
|
+
);
|
|
1839
1858
|
const loadOlderMessages = useCallback2(async () => {
|
|
1840
1859
|
const threadId = currentThreadIdRef.current;
|
|
1841
1860
|
const pageInfo = messagePageInfoRef.current;
|
|
@@ -1846,21 +1865,11 @@ function useCopilotz({
|
|
|
1846
1865
|
const requestId = messagesRequestRef.current;
|
|
1847
1866
|
setIsLoadingOlderMessages(true);
|
|
1848
1867
|
try {
|
|
1849
|
-
const page = await fetchThreadMessagesPage(
|
|
1850
|
-
threadId,
|
|
1851
|
-
{ limit: THREAD_MESSAGES_PAGE_SIZE, before },
|
|
1852
|
-
getRequestHeaders
|
|
1853
|
-
);
|
|
1868
|
+
const page = await fetchThreadMessagesPage(threadId, { limit: THREAD_MESSAGES_PAGE_SIZE, before }, getRequestHeaders);
|
|
1854
1869
|
const { viewMessages, toolResultUpdates } = await prepareThreadMessages(page.data);
|
|
1855
1870
|
if (messagesRequestRef.current !== requestId) return;
|
|
1856
|
-
persistedToolUpdatesRef.current = [
|
|
1857
|
-
|
|
1858
|
-
...persistedToolUpdatesRef.current
|
|
1859
|
-
];
|
|
1860
|
-
setMessages((prev) => mergePersistedToolResults(
|
|
1861
|
-
prependUniqueMessages(viewMessages, prev),
|
|
1862
|
-
persistedToolUpdatesRef.current
|
|
1863
|
-
));
|
|
1871
|
+
persistedToolUpdatesRef.current = [...toolResultUpdates, ...persistedToolUpdatesRef.current];
|
|
1872
|
+
setMessages((prev) => mergePersistedToolResults(prependUniqueMessages(viewMessages, prev), persistedToolUpdatesRef.current));
|
|
1864
1873
|
setMessagePageInfo(page.pageInfo);
|
|
1865
1874
|
} catch (error) {
|
|
1866
1875
|
if (isAbortError(error)) return;
|
|
@@ -1871,15 +1880,18 @@ function useCopilotz({
|
|
|
1871
1880
|
}
|
|
1872
1881
|
}
|
|
1873
1882
|
}, [getRequestHeaders, prepareThreadMessages]);
|
|
1874
|
-
const handleSelectThread = useCallback2(
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
+
const handleSelectThread = useCallback2(
|
|
1884
|
+
async (threadId) => {
|
|
1885
|
+
setCurrentThreadId(threadId);
|
|
1886
|
+
setMessages([]);
|
|
1887
|
+
setMessagePageInfo(createEmptyMessagePageInfo());
|
|
1888
|
+
persistedToolUpdatesRef.current = [];
|
|
1889
|
+
const extMap = threadExternalIdMapRef.current;
|
|
1890
|
+
setCurrentThreadExternalId(extMap[threadId] ?? null);
|
|
1891
|
+
await loadThreadMessages(threadId);
|
|
1892
|
+
},
|
|
1893
|
+
[loadThreadMessages]
|
|
1894
|
+
);
|
|
1883
1895
|
const handleCreateThread = useCallback2((title) => {
|
|
1884
1896
|
messagesRequestRef.current += 1;
|
|
1885
1897
|
setIsMessagesLoading(false);
|
|
@@ -1895,7 +1907,10 @@ function useCopilotz({
|
|
|
1895
1907
|
metadata: { pendingTitle: title?.trim() || void 0 }
|
|
1896
1908
|
};
|
|
1897
1909
|
setThreads((prev) => [newThread, ...prev]);
|
|
1898
|
-
setThreadMetadataMap((prev) => ({
|
|
1910
|
+
setThreadMetadataMap((prev) => ({
|
|
1911
|
+
...prev,
|
|
1912
|
+
[id]: { pendingTitle: title?.trim() || void 0 }
|
|
1913
|
+
}));
|
|
1899
1914
|
setThreadExternalIdMap((prev) => ({ ...prev, [id]: id }));
|
|
1900
1915
|
setCurrentThreadId(id);
|
|
1901
1916
|
setCurrentThreadExternalId(id);
|
|
@@ -1903,89 +1918,117 @@ function useCopilotz({
|
|
|
1903
1918
|
setMessagePageInfo(createEmptyMessagePageInfo());
|
|
1904
1919
|
persistedToolUpdatesRef.current = [];
|
|
1905
1920
|
}, []);
|
|
1906
|
-
const handleRenameThread = useCallback2(
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
(prev) => prev.map((t) => t.id === threadId ? { ...t, title: trimmedTitle, updatedAt: nowTs() } : t)
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1921
|
+
const handleRenameThread = useCallback2(
|
|
1922
|
+
async (threadId, newTitle) => {
|
|
1923
|
+
const trimmedTitle = newTitle.trim();
|
|
1924
|
+
if (!trimmedTitle) return;
|
|
1925
|
+
setThreads((prev) => prev.map((t) => t.id === threadId ? { ...t, title: trimmedTitle, updatedAt: nowTs() } : t));
|
|
1926
|
+
const extMap = threadExternalIdMapRef.current;
|
|
1927
|
+
const isPlaceholder = extMap[threadId] === threadId;
|
|
1928
|
+
if (isPlaceholder) {
|
|
1929
|
+
setThreadMetadataMap((prev) => ({
|
|
1930
|
+
...prev,
|
|
1931
|
+
[threadId]: { ...prev[threadId], pendingTitle: trimmedTitle }
|
|
1932
|
+
}));
|
|
1933
|
+
} else {
|
|
1934
|
+
try {
|
|
1935
|
+
await updateThread(threadId, { name: trimmedTitle }, getRequestHeaders);
|
|
1936
|
+
} catch (error) {
|
|
1937
|
+
console.error("Failed to rename thread:", error);
|
|
1938
|
+
if (userId) {
|
|
1939
|
+
await fetchAndSetThreadsState(userId, currentThreadExternalIdRef.current);
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
},
|
|
1944
|
+
[userId, fetchAndSetThreadsState, getRequestHeaders]
|
|
1945
|
+
);
|
|
1946
|
+
const handleArchiveThread = useCallback2(
|
|
1947
|
+
async (threadId) => {
|
|
1948
|
+
const thread = threadsRef.current.find((t) => t.id === threadId);
|
|
1949
|
+
if (!thread) return;
|
|
1950
|
+
const newArchivedStatus = !thread.isArchived;
|
|
1951
|
+
setThreads((prev) => prev.map((t) => t.id === threadId ? { ...t, isArchived: newArchivedStatus, updatedAt: nowTs() } : t));
|
|
1952
|
+
const extMap = threadExternalIdMapRef.current;
|
|
1953
|
+
const isPlaceholder = extMap[threadId] === threadId;
|
|
1954
|
+
if (!isPlaceholder) {
|
|
1955
|
+
try {
|
|
1956
|
+
await updateThread(threadId, { status: newArchivedStatus ? "archived" : "active" }, getRequestHeaders);
|
|
1957
|
+
} catch (error) {
|
|
1958
|
+
console.error("Failed to archive thread:", error);
|
|
1959
|
+
if (userId) {
|
|
1960
|
+
await fetchAndSetThreadsState(userId, currentThreadExternalIdRef.current);
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
},
|
|
1965
|
+
[userId, fetchAndSetThreadsState, getRequestHeaders]
|
|
1966
|
+
);
|
|
1967
|
+
const handleUpdateThreadTags = useCallback2(
|
|
1968
|
+
async (threadId, tags) => {
|
|
1969
|
+
const extMap = threadExternalIdMapRef.current;
|
|
1970
|
+
const currentMetadata = threadMetadataMapRef.current[threadId];
|
|
1971
|
+
const nextMetadata = patchMetadataPublicTags(currentMetadata, tags);
|
|
1972
|
+
setThreads((prev) => prev.map((thread) => thread.id === threadId ? { ...thread, tags, metadata: nextMetadata, updatedAt: nowTs() } : thread));
|
|
1915
1973
|
setThreadMetadataMap((prev) => ({
|
|
1916
1974
|
...prev,
|
|
1917
|
-
[threadId]:
|
|
1975
|
+
[threadId]: nextMetadata
|
|
1918
1976
|
}));
|
|
1919
|
-
|
|
1977
|
+
const isPlaceholder = extMap[threadId] === threadId;
|
|
1978
|
+
if (isPlaceholder) return;
|
|
1920
1979
|
try {
|
|
1921
|
-
await updateThread(threadId, {
|
|
1980
|
+
await updateThread(threadId, { metadata: nextMetadata }, getRequestHeaders);
|
|
1922
1981
|
} catch (error) {
|
|
1923
|
-
console.error("Failed to
|
|
1982
|
+
console.error("Failed to update thread tags:", error);
|
|
1924
1983
|
if (userId) {
|
|
1925
1984
|
await fetchAndSetThreadsState(userId, currentThreadExternalIdRef.current);
|
|
1926
1985
|
}
|
|
1927
1986
|
}
|
|
1928
|
-
}
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
(prev) => prev.
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1987
|
+
},
|
|
1988
|
+
[userId, fetchAndSetThreadsState, getRequestHeaders]
|
|
1989
|
+
);
|
|
1990
|
+
const handleDeleteThread = useCallback2(
|
|
1991
|
+
async (threadId) => {
|
|
1992
|
+
const extMap = threadExternalIdMapRef.current;
|
|
1993
|
+
const isPlaceholder = extMap[threadId] === threadId;
|
|
1994
|
+
setThreads((prev) => prev.filter((t) => t.id !== threadId));
|
|
1995
|
+
setThreadMetadataMap((prev) => {
|
|
1996
|
+
const next = { ...prev };
|
|
1997
|
+
delete next[threadId];
|
|
1998
|
+
return next;
|
|
1999
|
+
});
|
|
2000
|
+
setThreadExternalIdMap((prev) => {
|
|
2001
|
+
const next = { ...prev };
|
|
2002
|
+
delete next[threadId];
|
|
2003
|
+
return next;
|
|
2004
|
+
});
|
|
2005
|
+
if (currentThreadIdRef.current === threadId) {
|
|
2006
|
+
const remaining = threadsRef.current.filter((t) => t.id !== threadId);
|
|
2007
|
+
if (remaining.length > 0) {
|
|
2008
|
+
setCurrentThreadId(remaining[0].id);
|
|
2009
|
+
setCurrentThreadExternalId(extMap[remaining[0].id] ?? null);
|
|
2010
|
+
await loadThreadMessages(remaining[0].id);
|
|
2011
|
+
} else {
|
|
2012
|
+
setCurrentThreadId(null);
|
|
2013
|
+
setCurrentThreadExternalId(null);
|
|
2014
|
+
setMessages([]);
|
|
2015
|
+
setMessagePageInfo(createEmptyMessagePageInfo());
|
|
2016
|
+
persistedToolUpdatesRef.current = [];
|
|
1946
2017
|
}
|
|
1947
2018
|
}
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
delete next[threadId];
|
|
1957
|
-
return next;
|
|
1958
|
-
});
|
|
1959
|
-
setThreadExternalIdMap((prev) => {
|
|
1960
|
-
const next = { ...prev };
|
|
1961
|
-
delete next[threadId];
|
|
1962
|
-
return next;
|
|
1963
|
-
});
|
|
1964
|
-
if (currentThreadIdRef.current === threadId) {
|
|
1965
|
-
const remaining = threadsRef.current.filter((t) => t.id !== threadId);
|
|
1966
|
-
if (remaining.length > 0) {
|
|
1967
|
-
setCurrentThreadId(remaining[0].id);
|
|
1968
|
-
setCurrentThreadExternalId(extMap[remaining[0].id] ?? null);
|
|
1969
|
-
await loadThreadMessages(remaining[0].id);
|
|
1970
|
-
} else {
|
|
1971
|
-
setCurrentThreadId(null);
|
|
1972
|
-
setCurrentThreadExternalId(null);
|
|
1973
|
-
setMessages([]);
|
|
1974
|
-
setMessagePageInfo(createEmptyMessagePageInfo());
|
|
1975
|
-
persistedToolUpdatesRef.current = [];
|
|
1976
|
-
}
|
|
1977
|
-
}
|
|
1978
|
-
if (!isPlaceholder) {
|
|
1979
|
-
try {
|
|
1980
|
-
await deleteThread(threadId, getRequestHeaders);
|
|
1981
|
-
} catch (error) {
|
|
1982
|
-
console.error("Failed to delete thread:", error);
|
|
1983
|
-
if (userId) {
|
|
1984
|
-
await fetchAndSetThreadsState(userId, currentThreadExternalIdRef.current);
|
|
2019
|
+
if (!isPlaceholder) {
|
|
2020
|
+
try {
|
|
2021
|
+
await deleteThread(threadId, getRequestHeaders);
|
|
2022
|
+
} catch (error) {
|
|
2023
|
+
console.error("Failed to delete thread:", error);
|
|
2024
|
+
if (userId) {
|
|
2025
|
+
await fetchAndSetThreadsState(userId, currentThreadExternalIdRef.current);
|
|
2026
|
+
}
|
|
1985
2027
|
}
|
|
1986
2028
|
}
|
|
1987
|
-
}
|
|
1988
|
-
|
|
2029
|
+
},
|
|
2030
|
+
[userId, fetchAndSetThreadsState, loadThreadMessages, getRequestHeaders]
|
|
2031
|
+
);
|
|
1989
2032
|
const handleStop = useCallback2(() => {
|
|
1990
2033
|
abortControllerRef.current?.abort();
|
|
1991
2034
|
abortControllerRef.current = null;
|
|
@@ -2008,514 +2051,533 @@ function useCopilotz({
|
|
|
2008
2051
|
...typeof payload.fileName === "string" ? { fileName: payload.fileName } : {},
|
|
2009
2052
|
...typeof payload.size === "number" ? { size: payload.size } : {}
|
|
2010
2053
|
};
|
|
2011
|
-
setMessages(
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2054
|
+
setMessages(
|
|
2055
|
+
(prev) => prev.map(
|
|
2056
|
+
(msg) => msg.id === assistantMessageId ? {
|
|
2057
|
+
...msg,
|
|
2058
|
+
attachments: [...msg.attachments || [], mediaAttachment]
|
|
2059
|
+
} : msg
|
|
2060
|
+
)
|
|
2061
|
+
);
|
|
2015
2062
|
}, []);
|
|
2016
|
-
const sendCopilotzMessage = useCallback2(
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2063
|
+
const sendCopilotzMessage = useCallback2(
|
|
2064
|
+
async (params) => {
|
|
2065
|
+
let currentAssistantId = params.assistantMessageId ?? generateId();
|
|
2066
|
+
let currentAssistantSender = params.assistantSender;
|
|
2067
|
+
params.onBeforeStart?.(currentAssistantId);
|
|
2068
|
+
let hasStreamProgress = false;
|
|
2069
|
+
const updateStreamingMessage = (partial, opts) => {
|
|
2070
|
+
if (partial && partial.length > 0) {
|
|
2071
|
+
hasStreamProgress = true;
|
|
2072
|
+
}
|
|
2073
|
+
const isReasoning = opts?.isReasoning ?? false;
|
|
2074
|
+
const nextSender = opts?.agent ? resolveAgentSender(opts.agent, senderOptionsRef.current) : currentAssistantSender;
|
|
2075
|
+
if (nextSender) {
|
|
2076
|
+
currentAssistantSender = nextSender;
|
|
2077
|
+
}
|
|
2078
|
+
const nextAgentKey = currentAssistantSender?.agentId ?? currentAssistantSender?.id ?? null;
|
|
2079
|
+
const applyUpdate = (msg) => {
|
|
2080
|
+
return {
|
|
2081
|
+
...updateAssistantMessageToken(msg, {
|
|
2082
|
+
partial,
|
|
2083
|
+
isReasoning
|
|
2084
|
+
}),
|
|
2085
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
2086
|
+
};
|
|
2038
2087
|
};
|
|
2088
|
+
setMessages((prev) => {
|
|
2089
|
+
const idx = prev.findIndex((m) => m.id === currentAssistantId);
|
|
2090
|
+
if (idx >= 0 && canAttachToStreamingAssistant(prev[idx], nextAgentKey)) {
|
|
2091
|
+
const msg = prev[idx];
|
|
2092
|
+
const next = applyUpdate(msg);
|
|
2093
|
+
if (msg.content === next.content && msg.activity === next.activity && msg.isStreaming === next.isStreaming && msg.isComplete === next.isComplete) {
|
|
2094
|
+
return prev;
|
|
2095
|
+
}
|
|
2096
|
+
const updated = [...prev];
|
|
2097
|
+
updated[idx] = next;
|
|
2098
|
+
return updated;
|
|
2099
|
+
}
|
|
2100
|
+
const last = prev[prev.length - 1];
|
|
2101
|
+
if (canAttachToStreamingAssistant(last, nextAgentKey)) {
|
|
2102
|
+
currentAssistantId = last.id;
|
|
2103
|
+
const next = applyUpdate(last);
|
|
2104
|
+
if (last.content === next.content && last.activity === next.activity && last.isStreaming === next.isStreaming && last.isComplete === next.isComplete) {
|
|
2105
|
+
return prev;
|
|
2106
|
+
}
|
|
2107
|
+
const updated = [...prev];
|
|
2108
|
+
updated[prev.length - 1] = next;
|
|
2109
|
+
return updated;
|
|
2110
|
+
}
|
|
2111
|
+
const lastStreamingBelongsToDifferentAgent = Boolean(nextAgentKey) && last?.role === "assistant" && last.isStreaming && Boolean(messageAgentKey(last)) && messageAgentKey(last) !== nextAgentKey;
|
|
2112
|
+
if (!prev.length || prev[prev.length - 1].role !== "assistant" || !prev[prev.length - 1].isStreaming || lastStreamingBelongsToDifferentAgent) {
|
|
2113
|
+
const newId = generateId();
|
|
2114
|
+
currentAssistantId = newId;
|
|
2115
|
+
const base = {
|
|
2116
|
+
id: newId,
|
|
2117
|
+
role: "assistant",
|
|
2118
|
+
content: "",
|
|
2119
|
+
timestamp: nowTs(),
|
|
2120
|
+
isStreaming: true,
|
|
2121
|
+
isComplete: false,
|
|
2122
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
2123
|
+
};
|
|
2124
|
+
return [...prev, applyUpdate(base)];
|
|
2125
|
+
}
|
|
2126
|
+
return prev;
|
|
2127
|
+
});
|
|
2039
2128
|
};
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2129
|
+
const finalizeCurrentAssistantBubble = () => {
|
|
2130
|
+
setMessages((prev) => {
|
|
2131
|
+
const idx = prev.findIndex((m) => m.id === currentAssistantId);
|
|
2132
|
+
if (idx < 0) return prev;
|
|
2043
2133
|
const msg = prev[idx];
|
|
2044
|
-
|
|
2045
|
-
if (msg.content === next.content && msg.activity === next.activity && msg.isStreaming === next.isStreaming && msg.isComplete === next.isComplete) {
|
|
2046
|
-
return prev;
|
|
2047
|
-
}
|
|
2134
|
+
if (!msg.isStreaming && msg.isComplete) return prev;
|
|
2048
2135
|
const updated = [...prev];
|
|
2049
|
-
updated[idx] =
|
|
2136
|
+
updated[idx] = closeAssistantMessage(msg);
|
|
2050
2137
|
return updated;
|
|
2138
|
+
});
|
|
2139
|
+
};
|
|
2140
|
+
const curThreadId = currentThreadIdRef.current;
|
|
2141
|
+
const applyLiveToolResultUpdate = (update) => {
|
|
2142
|
+
let matched = false;
|
|
2143
|
+
setMessages((prev) => {
|
|
2144
|
+
const next = applyToolResultUpdateToMessages(prev, update, {
|
|
2145
|
+
isStreaming: true,
|
|
2146
|
+
isComplete: false
|
|
2147
|
+
});
|
|
2148
|
+
matched = next.matched;
|
|
2149
|
+
return next.matched ? next.messages : prev;
|
|
2150
|
+
});
|
|
2151
|
+
if (!matched) {
|
|
2152
|
+
liveToolUpdatesRef.current.push(update);
|
|
2051
2153
|
}
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
const
|
|
2056
|
-
|
|
2154
|
+
};
|
|
2155
|
+
const finalizeActiveAssistantTurn = (finalAnswer) => {
|
|
2156
|
+
setMessages((prev) => {
|
|
2157
|
+
const currentIdx = prev.findIndex((message2) => message2.id === currentAssistantId && message2.role === "assistant");
|
|
2158
|
+
const fallbackIdx = currentIdx >= 0 ? currentIdx : (() => {
|
|
2159
|
+
for (let i = prev.length - 1; i >= 0; i--) {
|
|
2160
|
+
if (prev[i].role === "assistant" && prev[i].isStreaming) {
|
|
2161
|
+
return i;
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
return -1;
|
|
2165
|
+
})();
|
|
2166
|
+
if (fallbackIdx < 0) return prev;
|
|
2167
|
+
const message = prev[fallbackIdx];
|
|
2168
|
+
const nextMessage = finalizeAssistantMessage(message, finalAnswer);
|
|
2169
|
+
if (message.content === nextMessage.content && message.isStreaming === nextMessage.isStreaming && message.isComplete === nextMessage.isComplete && message.activity === nextMessage.activity) {
|
|
2057
2170
|
return prev;
|
|
2058
2171
|
}
|
|
2059
2172
|
const updated = [...prev];
|
|
2060
|
-
updated[
|
|
2173
|
+
updated[fallbackIdx] = nextMessage;
|
|
2174
|
+
currentAssistantId = nextMessage.id;
|
|
2061
2175
|
return updated;
|
|
2062
|
-
}
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2176
|
+
});
|
|
2177
|
+
};
|
|
2178
|
+
const toServerMessageFromEvent = async (event) => {
|
|
2179
|
+
if (!event) return null;
|
|
2180
|
+
const type = event?.type || "";
|
|
2181
|
+
const payload = event?.payload ?? event;
|
|
2182
|
+
if (type === "TOOL_CALL") {
|
|
2183
|
+
const parsedToolCall = extractLiveToolCall(payload);
|
|
2184
|
+
return {
|
|
2185
|
+
id: generateId(),
|
|
2186
|
+
threadId: curThreadId ?? "",
|
|
2187
|
+
senderType: "tool",
|
|
2070
2188
|
content: "",
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2189
|
+
toolCalls: [
|
|
2190
|
+
{
|
|
2191
|
+
id: parsedToolCall.id ?? generateId(),
|
|
2192
|
+
name: parsedToolCall.name,
|
|
2193
|
+
args: parsedToolCall.arguments,
|
|
2194
|
+
...parsedToolCall.result !== void 0 ? { output: parsedToolCall.result } : {},
|
|
2195
|
+
status: parsedToolCall.status
|
|
2196
|
+
}
|
|
2197
|
+
]
|
|
2075
2198
|
};
|
|
2076
|
-
return [...prev, applyUpdate(base)];
|
|
2077
2199
|
}
|
|
2078
|
-
return
|
|
2079
|
-
}
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
const
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2200
|
+
return null;
|
|
2201
|
+
};
|
|
2202
|
+
const abortController = new AbortController();
|
|
2203
|
+
abortControllerRef.current?.abort();
|
|
2204
|
+
abortControllerRef.current = abortController;
|
|
2205
|
+
setIsStreaming(true);
|
|
2206
|
+
liveToolUpdatesRef.current = [];
|
|
2207
|
+
try {
|
|
2208
|
+
const normalizedUserMetadata = params.userMetadata ? JSON.parse(JSON.stringify(params.userMetadata)) : void 0;
|
|
2209
|
+
const contextSeed = userContextSeedRef.current;
|
|
2210
|
+
const contextMetadata = contextSeed ? JSON.parse(JSON.stringify(contextSeed)) : void 0;
|
|
2211
|
+
const requestContent = params.content && params.content.length > 0 ? params.content : "";
|
|
2212
|
+
const metadataKey = params.threadId ?? params.threadExternalId ?? void 0;
|
|
2213
|
+
const currentThreadMetadataMap = threadMetadataMapRef.current;
|
|
2214
|
+
const messageMetadata = metadataKey ? currentThreadMetadataMap[metadataKey]?.userContext : void 0;
|
|
2215
|
+
const threadMetadata = metadataKey ? currentThreadMetadataMap[metadataKey] : void 0;
|
|
2216
|
+
const mergedMetadata = {
|
|
2217
|
+
...messageMetadata ?? {},
|
|
2218
|
+
...params.metadata ?? {}
|
|
2219
|
+
};
|
|
2220
|
+
const finalMetadata = Object.keys(mergedMetadata).length > 0 ? mergedMetadata : void 0;
|
|
2221
|
+
await runCopilotzStream({
|
|
2222
|
+
threadId: params.threadId ?? void 0,
|
|
2223
|
+
threadExternalId: params.threadExternalId ?? void 0,
|
|
2224
|
+
content: requestContent,
|
|
2225
|
+
user: {
|
|
2226
|
+
externalId: params.userId,
|
|
2227
|
+
name: params.userName ?? params.userId,
|
|
2228
|
+
metadata: {
|
|
2229
|
+
...contextMetadata ? contextMetadata : {},
|
|
2230
|
+
...normalizedUserMetadata ?? {}
|
|
2231
|
+
}
|
|
2232
|
+
},
|
|
2233
|
+
attachments: params.attachments,
|
|
2234
|
+
metadata: finalMetadata,
|
|
2235
|
+
threadMetadata: params.threadMetadata ?? threadMetadata,
|
|
2236
|
+
toolCalls: params.toolCalls,
|
|
2237
|
+
selectedAgent: params.agentName ?? preferredAgentRef.current ?? null,
|
|
2238
|
+
participants: participantsRef.current,
|
|
2239
|
+
targetAgent: targetAgentNameRef.current,
|
|
2240
|
+
getRequestHeaders,
|
|
2241
|
+
onToken: (token, _isComplete, raw, opts) => updateStreamingMessage(token, {
|
|
2242
|
+
...opts,
|
|
2243
|
+
agent: raw?.payload?.agent ?? raw?.agent ?? null
|
|
2244
|
+
}),
|
|
2245
|
+
onMessageEvent: async (event) => {
|
|
2246
|
+
const intercepted = applyEventInterceptor(event);
|
|
2247
|
+
if (intercepted?.handled) {
|
|
2248
|
+
return;
|
|
2249
|
+
}
|
|
2250
|
+
const type = event?.type || "";
|
|
2251
|
+
const payload = getEventPayload(event);
|
|
2252
|
+
if (type === "TOOL_RESULT") {
|
|
2253
|
+
processToolOutput(payload ?? {});
|
|
2254
|
+
applyLiveToolResultUpdate(extractLiveToolResultUpdate(payload ?? {}));
|
|
2255
|
+
return;
|
|
2256
|
+
}
|
|
2257
|
+
if (type === "LLM_RESULT") {
|
|
2258
|
+
const finalAnswer = typeof payload?.answer === "string" ? payload.answer : void 0;
|
|
2259
|
+
finalizeActiveAssistantTurn(finalAnswer);
|
|
2260
|
+
return;
|
|
2261
|
+
}
|
|
2262
|
+
if (type === "MESSAGE" || type === "NEW_MESSAGE") {
|
|
2263
|
+
return;
|
|
2264
|
+
}
|
|
2265
|
+
if (type === "TOOL_CALL") {
|
|
2266
|
+
const parsedToolCall = extractLiveToolCall(payload ?? {});
|
|
2267
|
+
const eventSender = resolveLiveEventSender(event, senderOptionsRef.current);
|
|
2268
|
+
currentAssistantSender = eventSender;
|
|
2269
|
+
const eventAgentKey = currentAssistantSender.agentId ?? currentAssistantSender.id;
|
|
2270
|
+
const callId = parsedToolCall.id ?? generateId();
|
|
2271
|
+
const toolName = parsedToolCall.name;
|
|
2272
|
+
const bufferedUpdates = liveToolUpdatesRef.current;
|
|
2273
|
+
const matchingUpdateIndex = bufferedUpdates.findIndex((upd) => matchesToolResultUpdate({ id: callId, name: toolName }, upd));
|
|
2274
|
+
const bufferedUpdate = matchingUpdateIndex >= 0 ? bufferedUpdates[matchingUpdateIndex] : void 0;
|
|
2275
|
+
if (matchingUpdateIndex >= 0) {
|
|
2276
|
+
bufferedUpdates.splice(matchingUpdateIndex, 1);
|
|
2277
|
+
}
|
|
2278
|
+
const initialStatus = bufferedUpdate ? bufferedUpdate.status : parsedToolCall.status;
|
|
2279
|
+
const initialResult = bufferedUpdate && bufferedUpdate.result !== void 0 ? bufferedUpdate.result : parsedToolCall.result;
|
|
2280
|
+
const endTime = bufferedUpdate?.endTime;
|
|
2281
|
+
setMessages(
|
|
2282
|
+
(prev) => (() => {
|
|
2283
|
+
const canHostActivity = (message) => {
|
|
2284
|
+
if (!message) return false;
|
|
2285
|
+
return message.role === "assistant" && message.isStreaming && message.content.trim().length === 0 && !message.attachments?.length;
|
|
2286
|
+
};
|
|
2287
|
+
const appendToolCall = (msg) => ({
|
|
2288
|
+
...appendAssistantToolCall(msg, {
|
|
2289
|
+
id: callId,
|
|
2290
|
+
name: toolName,
|
|
2291
|
+
arguments: parsedToolCall.arguments,
|
|
2292
|
+
...initialResult !== void 0 ? { result: initialResult } : {},
|
|
2293
|
+
status: initialStatus,
|
|
2294
|
+
startTime: Date.now(),
|
|
2295
|
+
...endTime !== void 0 ? { endTime } : {}
|
|
2296
|
+
})
|
|
2297
|
+
});
|
|
2298
|
+
const currentIdx = prev.findIndex((message) => message.id === currentAssistantId && message.role === "assistant" && message.isStreaming && canHostActivity(message));
|
|
2299
|
+
if (currentIdx >= 0) {
|
|
2300
|
+
const next = [...prev];
|
|
2301
|
+
next[currentIdx] = appendToolCall({
|
|
2302
|
+
...next[currentIdx],
|
|
2303
|
+
isStreaming: true,
|
|
2304
|
+
isComplete: false,
|
|
2305
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
2306
|
+
});
|
|
2307
|
+
return next;
|
|
2308
|
+
}
|
|
2309
|
+
const last = prev[prev.length - 1];
|
|
2310
|
+
if (canHostActivity(last) && canAttachToStreamingAssistant(last, eventAgentKey)) {
|
|
2311
|
+
currentAssistantId = last.id;
|
|
2312
|
+
const next = [...prev];
|
|
2313
|
+
next[prev.length - 1] = appendToolCall({
|
|
2314
|
+
...last,
|
|
2315
|
+
isStreaming: true,
|
|
2316
|
+
isComplete: false,
|
|
2317
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
2318
|
+
});
|
|
2319
|
+
return next;
|
|
2320
|
+
}
|
|
2321
|
+
const newId = generateId();
|
|
2322
|
+
currentAssistantId = newId;
|
|
2323
|
+
return [
|
|
2324
|
+
...prev,
|
|
2325
|
+
appendToolCall({
|
|
2326
|
+
id: newId,
|
|
2327
|
+
role: "assistant",
|
|
2328
|
+
content: "",
|
|
2329
|
+
timestamp: nowTs(),
|
|
2330
|
+
isStreaming: true,
|
|
2331
|
+
isComplete: false,
|
|
2332
|
+
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
2333
|
+
})
|
|
2334
|
+
];
|
|
2335
|
+
})()
|
|
2336
|
+
);
|
|
2337
|
+
hasStreamProgress = true;
|
|
2338
|
+
return;
|
|
2339
|
+
}
|
|
2340
|
+
const sm = await toServerMessageFromEvent(event);
|
|
2341
|
+
if (sm) {
|
|
2342
|
+
const viewMsg = convertServerMessage(sm, {
|
|
2343
|
+
senderOptions: senderOptionsRef.current,
|
|
2344
|
+
createId: generateId,
|
|
2345
|
+
now: nowTs
|
|
2346
|
+
});
|
|
2347
|
+
finalizeCurrentAssistantBubble();
|
|
2348
|
+
setMessages((prev) => [...prev, viewMsg]);
|
|
2349
|
+
return;
|
|
2350
|
+
}
|
|
2351
|
+
handleStreamMessageEvent(event);
|
|
2352
|
+
},
|
|
2353
|
+
onAssetEvent: async (payload) => {
|
|
2354
|
+
const intercepted = applyEventInterceptor({
|
|
2355
|
+
type: "ASSET_CREATED",
|
|
2356
|
+
payload
|
|
2357
|
+
});
|
|
2358
|
+
if (intercepted?.handled) {
|
|
2359
|
+
return;
|
|
2360
|
+
}
|
|
2361
|
+
await (async () => {
|
|
2362
|
+
if (!hasStreamProgress) return;
|
|
2363
|
+
handleStreamAssetEvent(payload, currentAssistantId);
|
|
2364
|
+
})();
|
|
2365
|
+
},
|
|
2366
|
+
signal: abortController.signal
|
|
2099
2367
|
});
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2368
|
+
} finally {
|
|
2369
|
+
setIsStreaming(false);
|
|
2370
|
+
setMessages((prev) => {
|
|
2371
|
+
const hasStreaming = prev.some((msg) => msg.isStreaming);
|
|
2372
|
+
if (!hasStreaming) return prev;
|
|
2373
|
+
return prev.map((msg) => msg.isStreaming ? closeAssistantMessage(msg) : msg);
|
|
2374
|
+
});
|
|
2375
|
+
abortControllerRef.current = null;
|
|
2105
2376
|
}
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2377
|
+
return currentAssistantId;
|
|
2378
|
+
},
|
|
2379
|
+
[applyEventInterceptor, handleStreamMessageEvent, handleStreamAssetEvent, getRequestHeaders]
|
|
2380
|
+
);
|
|
2381
|
+
const handleSendMessage = useCallback2(
|
|
2382
|
+
async (content, attachments = []) => {
|
|
2383
|
+
if (!content.trim() && attachments.length === 0) return;
|
|
2384
|
+
if (!userId) return;
|
|
2385
|
+
const timestamp = nowTs();
|
|
2386
|
+
const curThreadId = currentThreadIdRef.current;
|
|
2387
|
+
const curThreadExtId = currentThreadExternalIdRef.current;
|
|
2388
|
+
const existingThreadId = curThreadId ?? void 0;
|
|
2389
|
+
const extMap = threadExternalIdMapRef.current;
|
|
2390
|
+
const isPlaceholderThread = existingThreadId ? extMap[existingThreadId] === existingThreadId : false;
|
|
2391
|
+
const threadIdForSend = isPlaceholderThread ? void 0 : existingThreadId;
|
|
2392
|
+
let effectiveThreadExternalId = curThreadExtId ?? (isPlaceholderThread ? existingThreadId : void 0);
|
|
2393
|
+
if (!threadIdForSend) {
|
|
2394
|
+
if (!effectiveThreadExternalId) {
|
|
2395
|
+
effectiveThreadExternalId = generateId();
|
|
2123
2396
|
}
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
return updated;
|
|
2128
|
-
});
|
|
2129
|
-
};
|
|
2130
|
-
const toServerMessageFromEvent = async (event) => {
|
|
2131
|
-
if (!event) return null;
|
|
2132
|
-
const type = event?.type || "";
|
|
2133
|
-
const payload = event?.payload ?? event;
|
|
2134
|
-
if (type === "TOOL_CALL") {
|
|
2135
|
-
const parsedToolCall = extractLiveToolCall(payload);
|
|
2136
|
-
return {
|
|
2137
|
-
id: generateId(),
|
|
2138
|
-
threadId: curThreadId ?? "",
|
|
2139
|
-
senderType: "tool",
|
|
2140
|
-
content: "",
|
|
2141
|
-
toolCalls: [{
|
|
2142
|
-
id: parsedToolCall.id ?? generateId(),
|
|
2143
|
-
name: parsedToolCall.name,
|
|
2144
|
-
args: parsedToolCall.arguments,
|
|
2145
|
-
...parsedToolCall.result !== void 0 ? { output: parsedToolCall.result } : {},
|
|
2146
|
-
status: parsedToolCall.status
|
|
2147
|
-
}]
|
|
2148
|
-
};
|
|
2397
|
+
setCurrentThreadExternalId(effectiveThreadExternalId);
|
|
2398
|
+
} else if (curThreadExtId !== (effectiveThreadExternalId ?? null)) {
|
|
2399
|
+
setCurrentThreadExternalId(effectiveThreadExternalId ?? null);
|
|
2149
2400
|
}
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
const messageMetadata = metadataKey ? currentThreadMetadataMap[metadataKey]?.userContext : void 0;
|
|
2165
|
-
const threadMetadata = metadataKey ? currentThreadMetadataMap[metadataKey] : void 0;
|
|
2166
|
-
const mergedMetadata = {
|
|
2167
|
-
...messageMetadata ?? {},
|
|
2168
|
-
...params.metadata ?? {}
|
|
2401
|
+
const conversationKey = threadIdForSend ?? effectiveThreadExternalId;
|
|
2402
|
+
const currentMetadata = threadMetadataMapRef.current[conversationKey];
|
|
2403
|
+
const pendingTitle = currentMetadata?.pendingTitle;
|
|
2404
|
+
const userMessage = {
|
|
2405
|
+
id: generateId(),
|
|
2406
|
+
role: "user",
|
|
2407
|
+
content,
|
|
2408
|
+
timestamp,
|
|
2409
|
+
attachments: attachments.length > 0 ? attachments : void 0,
|
|
2410
|
+
isComplete: true,
|
|
2411
|
+
sender: resolveUserSender({
|
|
2412
|
+
id: userId,
|
|
2413
|
+
name: getCurrentUserDisplayName(userName, userId)
|
|
2414
|
+
})
|
|
2169
2415
|
};
|
|
2170
|
-
const
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
content: requestContent,
|
|
2175
|
-
user: {
|
|
2176
|
-
externalId: params.userId,
|
|
2177
|
-
name: params.userName ?? params.userId,
|
|
2178
|
-
metadata: {
|
|
2179
|
-
...contextMetadata ? contextMetadata : {},
|
|
2180
|
-
...normalizedUserMetadata ?? {}
|
|
2181
|
-
}
|
|
2416
|
+
const assistantSender = targetAgentNameRef.current ? resolveAgentSender(
|
|
2417
|
+
{
|
|
2418
|
+
id: targetAgentNameRef.current,
|
|
2419
|
+
name: targetAgentNameRef.current
|
|
2182
2420
|
},
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2421
|
+
senderOptionsRef.current
|
|
2422
|
+
) : preferredAgentRef.current ? resolveAgentSender({ id: preferredAgentRef.current, name: preferredAgentRef.current }, senderOptionsRef.current) : resolveAssistantFallbackSender(senderOptionsRef.current);
|
|
2423
|
+
const assistantPlaceholder = {
|
|
2424
|
+
id: generateId(),
|
|
2425
|
+
role: "assistant",
|
|
2426
|
+
content: "",
|
|
2427
|
+
timestamp: timestamp + 1,
|
|
2428
|
+
isStreaming: true,
|
|
2429
|
+
isComplete: false,
|
|
2430
|
+
sender: assistantSender,
|
|
2431
|
+
activity: createPendingAssistantActivity()
|
|
2432
|
+
};
|
|
2433
|
+
setMessages((prev) => [...prev, userMessage, assistantPlaceholder]);
|
|
2434
|
+
setSpecialState(null);
|
|
2435
|
+
if (!threadsRef.current.some((t) => t.id === conversationKey)) {
|
|
2436
|
+
const newThread = {
|
|
2437
|
+
id: conversationKey,
|
|
2438
|
+
title: content.slice(0, 40) || "Nova conversa",
|
|
2439
|
+
createdAt: timestamp,
|
|
2440
|
+
updatedAt: timestamp,
|
|
2441
|
+
messageCount: 0
|
|
2442
|
+
};
|
|
2443
|
+
setThreads((prev) => [newThread, ...prev]);
|
|
2444
|
+
setThreadMetadataMap((prev) => ({ ...prev, [conversationKey]: {} }));
|
|
2445
|
+
setThreadExternalIdMap((prev) => ({
|
|
2446
|
+
...prev,
|
|
2447
|
+
[conversationKey]: effectiveThreadExternalId ?? null
|
|
2448
|
+
}));
|
|
2449
|
+
}
|
|
2450
|
+
try {
|
|
2451
|
+
await sendCopilotzMessage({
|
|
2452
|
+
threadId: threadIdForSend,
|
|
2453
|
+
threadExternalId: effectiveThreadExternalId,
|
|
2454
|
+
content,
|
|
2455
|
+
attachments,
|
|
2456
|
+
userId,
|
|
2457
|
+
userName: getCurrentUserDisplayName(userName, userId),
|
|
2458
|
+
agentName: preferredAgentRef.current,
|
|
2459
|
+
assistantMessageId: assistantPlaceholder.id,
|
|
2460
|
+
assistantSender,
|
|
2461
|
+
// Include pending title for new threads
|
|
2462
|
+
threadMetadata: pendingTitle ? { name: pendingTitle } : void 0
|
|
2463
|
+
});
|
|
2464
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
2465
|
+
await fetchAndSetThreadsState(userId, effectiveThreadExternalId ?? existingThreadId ?? null);
|
|
2466
|
+
} catch (error) {
|
|
2467
|
+
if (isAbortError(error)) return;
|
|
2468
|
+
console.error("Error sending Copilotz message", error);
|
|
2469
|
+
const nextSpecialState = getSpecialStateFromError(error);
|
|
2470
|
+
if (nextSpecialState) {
|
|
2471
|
+
setSpecialState(nextSpecialState);
|
|
2472
|
+
setMessages((prev) => prev.filter((msg) => !msg.isStreaming));
|
|
2473
|
+
return;
|
|
2474
|
+
}
|
|
2475
|
+
setMessages((prev) => {
|
|
2476
|
+
const finalized = prev.map((msg) => msg.isStreaming ? closeAssistantMessage(msg) : msg);
|
|
2477
|
+
if (finalized.some(hasVisibleAssistantOutput)) {
|
|
2478
|
+
return finalized;
|
|
2213
2479
|
}
|
|
2214
|
-
|
|
2215
|
-
|
|
2480
|
+
for (let i = finalized.length - 1; i >= 0; i--) {
|
|
2481
|
+
const message = finalized[i];
|
|
2482
|
+
if (message.role !== "assistant") continue;
|
|
2483
|
+
const updated = [...finalized];
|
|
2484
|
+
updated[i] = {
|
|
2485
|
+
...message,
|
|
2486
|
+
content: "Desculpe, ocorreu um erro ao gerar a resposta. Por favor, tente novamente.",
|
|
2487
|
+
isStreaming: false,
|
|
2488
|
+
isComplete: true,
|
|
2489
|
+
sender: message.sender ?? resolveAssistantFallbackSender(senderOptionsRef.current)
|
|
2490
|
+
};
|
|
2491
|
+
return updated;
|
|
2216
2492
|
}
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
const matchingUpdateIndex = bufferedUpdates.findIndex((upd) => matchesToolResultUpdate({ id: callId, name: toolName }, upd));
|
|
2228
|
-
const bufferedUpdate = matchingUpdateIndex >= 0 ? bufferedUpdates[matchingUpdateIndex] : void 0;
|
|
2229
|
-
if (matchingUpdateIndex >= 0) {
|
|
2230
|
-
bufferedUpdates.splice(matchingUpdateIndex, 1);
|
|
2493
|
+
return [
|
|
2494
|
+
...finalized,
|
|
2495
|
+
{
|
|
2496
|
+
id: generateId(),
|
|
2497
|
+
role: "assistant",
|
|
2498
|
+
content: "Desculpe, ocorreu um erro ao gerar a resposta. Por favor, tente novamente.",
|
|
2499
|
+
timestamp: nowTs(),
|
|
2500
|
+
isStreaming: false,
|
|
2501
|
+
isComplete: true,
|
|
2502
|
+
sender: resolveAssistantFallbackSender(senderOptionsRef.current)
|
|
2231
2503
|
}
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
const endTime = bufferedUpdate?.endTime;
|
|
2235
|
-
setMessages(
|
|
2236
|
-
(prev) => (() => {
|
|
2237
|
-
const canHostActivity = (message) => {
|
|
2238
|
-
if (!message) return false;
|
|
2239
|
-
return message.role === "assistant" && message.isStreaming && message.content.trim().length === 0 && !message.attachments?.length;
|
|
2240
|
-
};
|
|
2241
|
-
const appendToolCall = (msg) => ({
|
|
2242
|
-
...appendAssistantToolCall(msg, {
|
|
2243
|
-
id: callId,
|
|
2244
|
-
name: toolName,
|
|
2245
|
-
arguments: parsedToolCall.arguments,
|
|
2246
|
-
...initialResult !== void 0 ? { result: initialResult } : {},
|
|
2247
|
-
status: initialStatus,
|
|
2248
|
-
startTime: Date.now(),
|
|
2249
|
-
...endTime !== void 0 ? { endTime } : {}
|
|
2250
|
-
})
|
|
2251
|
-
});
|
|
2252
|
-
const currentIdx = prev.findIndex((message) => message.id === currentAssistantId && message.role === "assistant" && message.isStreaming && canHostActivity(message));
|
|
2253
|
-
if (currentIdx >= 0) {
|
|
2254
|
-
const next = [...prev];
|
|
2255
|
-
next[currentIdx] = appendToolCall({
|
|
2256
|
-
...next[currentIdx],
|
|
2257
|
-
isStreaming: true,
|
|
2258
|
-
isComplete: false,
|
|
2259
|
-
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
2260
|
-
});
|
|
2261
|
-
return next;
|
|
2262
|
-
}
|
|
2263
|
-
const last = prev[prev.length - 1];
|
|
2264
|
-
if (canHostActivity(last) && canAttachToStreamingAssistant(
|
|
2265
|
-
last,
|
|
2266
|
-
eventAgentKey
|
|
2267
|
-
)) {
|
|
2268
|
-
currentAssistantId = last.id;
|
|
2269
|
-
const next = [...prev];
|
|
2270
|
-
next[prev.length - 1] = appendToolCall({
|
|
2271
|
-
...last,
|
|
2272
|
-
isStreaming: true,
|
|
2273
|
-
isComplete: false,
|
|
2274
|
-
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
2275
|
-
});
|
|
2276
|
-
return next;
|
|
2277
|
-
}
|
|
2278
|
-
const newId = generateId();
|
|
2279
|
-
currentAssistantId = newId;
|
|
2280
|
-
return [
|
|
2281
|
-
...prev,
|
|
2282
|
-
appendToolCall({
|
|
2283
|
-
id: newId,
|
|
2284
|
-
role: "assistant",
|
|
2285
|
-
content: "",
|
|
2286
|
-
timestamp: nowTs(),
|
|
2287
|
-
isStreaming: true,
|
|
2288
|
-
isComplete: false,
|
|
2289
|
-
...currentAssistantSender ? { sender: currentAssistantSender } : {}
|
|
2290
|
-
})
|
|
2291
|
-
];
|
|
2292
|
-
})()
|
|
2293
|
-
);
|
|
2294
|
-
hasStreamProgress = true;
|
|
2295
|
-
return;
|
|
2296
|
-
}
|
|
2297
|
-
const sm = await toServerMessageFromEvent(event);
|
|
2298
|
-
if (sm) {
|
|
2299
|
-
const viewMsg = convertServerMessage(sm, {
|
|
2300
|
-
senderOptions: senderOptionsRef.current,
|
|
2301
|
-
createId: generateId,
|
|
2302
|
-
now: nowTs
|
|
2303
|
-
});
|
|
2304
|
-
finalizeCurrentAssistantBubble();
|
|
2305
|
-
setMessages((prev) => [...prev, viewMsg]);
|
|
2306
|
-
return;
|
|
2307
|
-
}
|
|
2308
|
-
handleStreamMessageEvent(event);
|
|
2309
|
-
},
|
|
2310
|
-
onAssetEvent: async (payload) => {
|
|
2311
|
-
const intercepted = applyEventInterceptor({ type: "ASSET_CREATED", payload });
|
|
2312
|
-
if (intercepted?.handled) {
|
|
2313
|
-
return;
|
|
2314
|
-
}
|
|
2315
|
-
await (async () => {
|
|
2316
|
-
if (!hasStreamProgress) return;
|
|
2317
|
-
handleStreamAssetEvent(payload, currentAssistantId);
|
|
2318
|
-
})();
|
|
2319
|
-
},
|
|
2320
|
-
signal: abortController.signal
|
|
2321
|
-
});
|
|
2322
|
-
} finally {
|
|
2323
|
-
setIsStreaming(false);
|
|
2324
|
-
setMessages((prev) => {
|
|
2325
|
-
const hasStreaming = prev.some((msg) => msg.isStreaming);
|
|
2326
|
-
if (!hasStreaming) return prev;
|
|
2327
|
-
return prev.map((msg) => msg.isStreaming ? closeAssistantMessage(msg) : msg);
|
|
2328
|
-
});
|
|
2329
|
-
abortControllerRef.current = null;
|
|
2330
|
-
}
|
|
2331
|
-
return currentAssistantId;
|
|
2332
|
-
}, [applyEventInterceptor, handleStreamMessageEvent, handleStreamAssetEvent, getRequestHeaders]);
|
|
2333
|
-
const handleSendMessage = useCallback2(async (content, attachments = []) => {
|
|
2334
|
-
if (!content.trim() && attachments.length === 0) return;
|
|
2335
|
-
if (!userId) return;
|
|
2336
|
-
const timestamp = nowTs();
|
|
2337
|
-
const curThreadId = currentThreadIdRef.current;
|
|
2338
|
-
const curThreadExtId = currentThreadExternalIdRef.current;
|
|
2339
|
-
const existingThreadId = curThreadId ?? void 0;
|
|
2340
|
-
const extMap = threadExternalIdMapRef.current;
|
|
2341
|
-
const isPlaceholderThread = existingThreadId ? extMap[existingThreadId] === existingThreadId : false;
|
|
2342
|
-
const threadIdForSend = isPlaceholderThread ? void 0 : existingThreadId;
|
|
2343
|
-
let effectiveThreadExternalId = curThreadExtId ?? (isPlaceholderThread ? existingThreadId : void 0);
|
|
2344
|
-
if (!threadIdForSend) {
|
|
2345
|
-
if (!effectiveThreadExternalId) {
|
|
2346
|
-
effectiveThreadExternalId = generateId();
|
|
2347
|
-
}
|
|
2348
|
-
setCurrentThreadExternalId(effectiveThreadExternalId);
|
|
2349
|
-
} else if (curThreadExtId !== (effectiveThreadExternalId ?? null)) {
|
|
2350
|
-
setCurrentThreadExternalId(effectiveThreadExternalId ?? null);
|
|
2351
|
-
}
|
|
2352
|
-
const conversationKey = threadIdForSend ?? effectiveThreadExternalId;
|
|
2353
|
-
const currentMetadata = threadMetadataMapRef.current[conversationKey];
|
|
2354
|
-
const pendingTitle = currentMetadata?.pendingTitle;
|
|
2355
|
-
const userMessage = {
|
|
2356
|
-
id: generateId(),
|
|
2357
|
-
role: "user",
|
|
2358
|
-
content,
|
|
2359
|
-
timestamp,
|
|
2360
|
-
attachments: attachments.length > 0 ? attachments : void 0,
|
|
2361
|
-
isComplete: true,
|
|
2362
|
-
sender: resolveUserSender({
|
|
2363
|
-
id: userId,
|
|
2364
|
-
name: getCurrentUserDisplayName(userName, userId)
|
|
2365
|
-
})
|
|
2366
|
-
};
|
|
2367
|
-
const assistantSender = targetAgentNameRef.current ? resolveAgentSender(
|
|
2368
|
-
{ id: targetAgentNameRef.current, name: targetAgentNameRef.current },
|
|
2369
|
-
senderOptionsRef.current
|
|
2370
|
-
) : preferredAgentRef.current ? resolveAgentSender(
|
|
2371
|
-
{ id: preferredAgentRef.current, name: preferredAgentRef.current },
|
|
2372
|
-
senderOptionsRef.current
|
|
2373
|
-
) : resolveAssistantFallbackSender(senderOptionsRef.current);
|
|
2374
|
-
const assistantPlaceholder = {
|
|
2375
|
-
id: generateId(),
|
|
2376
|
-
role: "assistant",
|
|
2377
|
-
content: "",
|
|
2378
|
-
timestamp: timestamp + 1,
|
|
2379
|
-
isStreaming: true,
|
|
2380
|
-
isComplete: false,
|
|
2381
|
-
sender: assistantSender,
|
|
2382
|
-
activity: createPendingAssistantActivity()
|
|
2383
|
-
};
|
|
2384
|
-
setMessages((prev) => [...prev, userMessage, assistantPlaceholder]);
|
|
2385
|
-
setSpecialState(null);
|
|
2386
|
-
if (!threadsRef.current.some((t) => t.id === conversationKey)) {
|
|
2387
|
-
const newThread = {
|
|
2388
|
-
id: conversationKey,
|
|
2389
|
-
title: content.slice(0, 40) || "Nova conversa",
|
|
2390
|
-
createdAt: timestamp,
|
|
2391
|
-
updatedAt: timestamp,
|
|
2392
|
-
messageCount: 0
|
|
2393
|
-
};
|
|
2394
|
-
setThreads((prev) => [newThread, ...prev]);
|
|
2395
|
-
setThreadMetadataMap((prev) => ({ ...prev, [conversationKey]: {} }));
|
|
2396
|
-
setThreadExternalIdMap((prev) => ({ ...prev, [conversationKey]: effectiveThreadExternalId ?? null }));
|
|
2397
|
-
}
|
|
2398
|
-
try {
|
|
2399
|
-
await sendCopilotzMessage({
|
|
2400
|
-
threadId: threadIdForSend,
|
|
2401
|
-
threadExternalId: effectiveThreadExternalId,
|
|
2402
|
-
content,
|
|
2403
|
-
attachments,
|
|
2404
|
-
userId,
|
|
2405
|
-
userName: getCurrentUserDisplayName(userName, userId),
|
|
2406
|
-
agentName: preferredAgentRef.current,
|
|
2407
|
-
assistantMessageId: assistantPlaceholder.id,
|
|
2408
|
-
assistantSender,
|
|
2409
|
-
// Include pending title for new threads
|
|
2410
|
-
threadMetadata: pendingTitle ? { name: pendingTitle } : void 0
|
|
2411
|
-
});
|
|
2412
|
-
await new Promise((r) => setTimeout(r, 1e3));
|
|
2413
|
-
await fetchAndSetThreadsState(userId, effectiveThreadExternalId ?? existingThreadId ?? null);
|
|
2414
|
-
} catch (error) {
|
|
2415
|
-
if (isAbortError(error)) return;
|
|
2416
|
-
console.error("Error sending Copilotz message", error);
|
|
2417
|
-
const nextSpecialState = getSpecialStateFromError(error);
|
|
2418
|
-
if (nextSpecialState) {
|
|
2419
|
-
setSpecialState(nextSpecialState);
|
|
2420
|
-
setMessages((prev) => prev.filter((msg) => !msg.isStreaming));
|
|
2421
|
-
return;
|
|
2504
|
+
];
|
|
2505
|
+
});
|
|
2422
2506
|
}
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2507
|
+
},
|
|
2508
|
+
[userId, fetchAndSetThreadsState, loadThreadMessages, sendCopilotzMessage, getSpecialStateFromError]
|
|
2509
|
+
);
|
|
2510
|
+
const bootstrapConversation = useCallback2(
|
|
2511
|
+
async (uid) => {
|
|
2512
|
+
if (!bootstrap?.initialToolCalls && !bootstrap?.initialMessage) return;
|
|
2513
|
+
const bootstrapThreadExternalId = generateId();
|
|
2514
|
+
setCurrentThreadId(bootstrapThreadExternalId);
|
|
2515
|
+
setCurrentThreadExternalId(bootstrapThreadExternalId);
|
|
2516
|
+
setThreadExternalIdMap((prev) => ({
|
|
2517
|
+
...prev,
|
|
2518
|
+
[bootstrapThreadExternalId]: bootstrapThreadExternalId
|
|
2519
|
+
}));
|
|
2520
|
+
setThreadMetadataMap((prev) => ({
|
|
2521
|
+
...prev,
|
|
2522
|
+
[bootstrapThreadExternalId]: {}
|
|
2523
|
+
}));
|
|
2524
|
+
const assistantSender = preferredAgentRef.current ? resolveAgentSender({ id: preferredAgentRef.current, name: preferredAgentRef.current }, senderOptionsRef.current) : resolveAssistantFallbackSender(senderOptionsRef.current);
|
|
2525
|
+
const assistantMessageId = generateId();
|
|
2526
|
+
setMessages([
|
|
2527
|
+
{
|
|
2528
|
+
id: assistantMessageId,
|
|
2529
|
+
role: "assistant",
|
|
2530
|
+
content: "",
|
|
2531
|
+
timestamp: nowTs(),
|
|
2532
|
+
isStreaming: true,
|
|
2533
|
+
isComplete: false,
|
|
2534
|
+
sender: assistantSender,
|
|
2535
|
+
activity: createPendingAssistantActivity()
|
|
2427
2536
|
}
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2537
|
+
]);
|
|
2538
|
+
setMessagePageInfo(createEmptyMessagePageInfo());
|
|
2539
|
+
persistedToolUpdatesRef.current = [];
|
|
2540
|
+
setSpecialState(null);
|
|
2541
|
+
try {
|
|
2542
|
+
await sendCopilotzMessage({
|
|
2543
|
+
threadExternalId: bootstrapThreadExternalId,
|
|
2544
|
+
content: bootstrap.initialMessage || "",
|
|
2545
|
+
toolCalls: bootstrap.initialToolCalls,
|
|
2546
|
+
userId: uid,
|
|
2547
|
+
userName: getCurrentUserDisplayName(userName, uid),
|
|
2548
|
+
agentName: preferredAgentRef.current,
|
|
2549
|
+
assistantMessageId,
|
|
2550
|
+
assistantSender,
|
|
2551
|
+
threadMetadata: {
|
|
2552
|
+
name: defaultThreadName || "Main Thread"
|
|
2553
|
+
}
|
|
2554
|
+
});
|
|
2555
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
2556
|
+
await fetchAndSetThreadsState(uid, bootstrapThreadExternalId);
|
|
2557
|
+
} catch (error) {
|
|
2558
|
+
if (isAbortError(error)) return;
|
|
2559
|
+
console.error("Error bootstrapping conversation", error);
|
|
2560
|
+
const nextSpecialState = getSpecialStateFromError(error);
|
|
2561
|
+
if (nextSpecialState) {
|
|
2562
|
+
setSpecialState(nextSpecialState);
|
|
2563
|
+
setMessages([]);
|
|
2564
|
+
return;
|
|
2440
2565
|
}
|
|
2441
|
-
|
|
2442
|
-
...finalized,
|
|
2566
|
+
setMessages([
|
|
2443
2567
|
{
|
|
2444
2568
|
id: generateId(),
|
|
2445
2569
|
role: "assistant",
|
|
2446
|
-
content: "
|
|
2570
|
+
content: "N\xE3o foi poss\xEDvel iniciar a conversa. Tente novamente mais tarde.",
|
|
2447
2571
|
timestamp: nowTs(),
|
|
2448
2572
|
isStreaming: false,
|
|
2449
2573
|
isComplete: true,
|
|
2450
2574
|
sender: resolveAssistantFallbackSender(senderOptionsRef.current)
|
|
2451
2575
|
}
|
|
2452
|
-
];
|
|
2453
|
-
});
|
|
2454
|
-
}
|
|
2455
|
-
}, [userId, fetchAndSetThreadsState, loadThreadMessages, sendCopilotzMessage, getSpecialStateFromError]);
|
|
2456
|
-
const bootstrapConversation = useCallback2(async (uid) => {
|
|
2457
|
-
if (!bootstrap?.initialToolCalls && !bootstrap?.initialMessage) return;
|
|
2458
|
-
const bootstrapThreadExternalId = generateId();
|
|
2459
|
-
setCurrentThreadId(bootstrapThreadExternalId);
|
|
2460
|
-
setCurrentThreadExternalId(bootstrapThreadExternalId);
|
|
2461
|
-
setThreadExternalIdMap((prev) => ({ ...prev, [bootstrapThreadExternalId]: bootstrapThreadExternalId }));
|
|
2462
|
-
setThreadMetadataMap((prev) => ({ ...prev, [bootstrapThreadExternalId]: {} }));
|
|
2463
|
-
const assistantSender = preferredAgentRef.current ? resolveAgentSender(
|
|
2464
|
-
{ id: preferredAgentRef.current, name: preferredAgentRef.current },
|
|
2465
|
-
senderOptionsRef.current
|
|
2466
|
-
) : resolveAssistantFallbackSender(senderOptionsRef.current);
|
|
2467
|
-
const assistantMessageId = generateId();
|
|
2468
|
-
setMessages([{
|
|
2469
|
-
id: assistantMessageId,
|
|
2470
|
-
role: "assistant",
|
|
2471
|
-
content: "",
|
|
2472
|
-
timestamp: nowTs(),
|
|
2473
|
-
isStreaming: true,
|
|
2474
|
-
isComplete: false,
|
|
2475
|
-
sender: assistantSender,
|
|
2476
|
-
activity: createPendingAssistantActivity()
|
|
2477
|
-
}]);
|
|
2478
|
-
setMessagePageInfo(createEmptyMessagePageInfo());
|
|
2479
|
-
persistedToolUpdatesRef.current = [];
|
|
2480
|
-
setSpecialState(null);
|
|
2481
|
-
try {
|
|
2482
|
-
await sendCopilotzMessage({
|
|
2483
|
-
threadExternalId: bootstrapThreadExternalId,
|
|
2484
|
-
content: bootstrap.initialMessage || "",
|
|
2485
|
-
toolCalls: bootstrap.initialToolCalls,
|
|
2486
|
-
userId: uid,
|
|
2487
|
-
userName: getCurrentUserDisplayName(userName, uid),
|
|
2488
|
-
agentName: preferredAgentRef.current,
|
|
2489
|
-
assistantMessageId,
|
|
2490
|
-
assistantSender,
|
|
2491
|
-
threadMetadata: {
|
|
2492
|
-
name: defaultThreadName || "Main Thread"
|
|
2493
|
-
}
|
|
2494
|
-
});
|
|
2495
|
-
await new Promise((r) => setTimeout(r, 1e3));
|
|
2496
|
-
await fetchAndSetThreadsState(uid, bootstrapThreadExternalId);
|
|
2497
|
-
} catch (error) {
|
|
2498
|
-
if (isAbortError(error)) return;
|
|
2499
|
-
console.error("Error bootstrapping conversation", error);
|
|
2500
|
-
const nextSpecialState = getSpecialStateFromError(error);
|
|
2501
|
-
if (nextSpecialState) {
|
|
2502
|
-
setSpecialState(nextSpecialState);
|
|
2503
|
-
setMessages([]);
|
|
2504
|
-
return;
|
|
2576
|
+
]);
|
|
2505
2577
|
}
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
role: "assistant",
|
|
2510
|
-
content: "N\xE3o foi poss\xEDvel iniciar a conversa. Tente novamente mais tarde.",
|
|
2511
|
-
timestamp: nowTs(),
|
|
2512
|
-
isStreaming: false,
|
|
2513
|
-
isComplete: true,
|
|
2514
|
-
sender: resolveAssistantFallbackSender(senderOptionsRef.current)
|
|
2515
|
-
}
|
|
2516
|
-
]);
|
|
2517
|
-
}
|
|
2518
|
-
}, [fetchAndSetThreadsState, loadThreadMessages, sendCopilotzMessage, bootstrap, defaultThreadName, getSpecialStateFromError]);
|
|
2578
|
+
},
|
|
2579
|
+
[fetchAndSetThreadsState, loadThreadMessages, sendCopilotzMessage, bootstrap, defaultThreadName, getSpecialStateFromError]
|
|
2580
|
+
);
|
|
2519
2581
|
const reset = useCallback2(() => {
|
|
2520
2582
|
messagesRequestRef.current += 1;
|
|
2521
2583
|
setThreads([]);
|
|
@@ -2564,7 +2626,10 @@ function useCopilotz({
|
|
|
2564
2626
|
const metadata = threadMetadataMap[currentThreadId];
|
|
2565
2627
|
if (!metadata) return;
|
|
2566
2628
|
if (metadata.userContext && typeof metadata.userContext === "object") {
|
|
2567
|
-
setUserContextSeed((prev) => ({
|
|
2629
|
+
setUserContextSeed((prev) => ({
|
|
2630
|
+
...prev,
|
|
2631
|
+
...metadata.userContext
|
|
2632
|
+
}));
|
|
2568
2633
|
}
|
|
2569
2634
|
}, [currentThreadId, threadMetadataMap]);
|
|
2570
2635
|
return {
|
|
@@ -2583,6 +2648,7 @@ function useCopilotz({
|
|
|
2583
2648
|
selectThread: handleSelectThread,
|
|
2584
2649
|
renameThread: handleRenameThread,
|
|
2585
2650
|
archiveThread: handleArchiveThread,
|
|
2651
|
+
updateThreadTags: handleUpdateThreadTags,
|
|
2586
2652
|
deleteThread: handleDeleteThread,
|
|
2587
2653
|
stopGeneration: handleStop,
|
|
2588
2654
|
fetchAndSetThreadsState,
|
|
@@ -2594,39 +2660,7 @@ function useCopilotz({
|
|
|
2594
2660
|
|
|
2595
2661
|
// src/CopilotzChat.tsx
|
|
2596
2662
|
import { jsx } from "react/jsx-runtime";
|
|
2597
|
-
var CopilotzChat = ({
|
|
2598
|
-
userId,
|
|
2599
|
-
userName,
|
|
2600
|
-
userAvatar,
|
|
2601
|
-
userEmail,
|
|
2602
|
-
initialContext,
|
|
2603
|
-
bootstrap,
|
|
2604
|
-
config: userConfig,
|
|
2605
|
-
callbacks: userCallbacks,
|
|
2606
|
-
customComponent,
|
|
2607
|
-
onToolOutput,
|
|
2608
|
-
onCurrentThreadIdChange,
|
|
2609
|
-
onLogout,
|
|
2610
|
-
onViewProfile,
|
|
2611
|
-
onAddMemory,
|
|
2612
|
-
onUpdateMemory,
|
|
2613
|
-
onDeleteMemory,
|
|
2614
|
-
userMenuSections,
|
|
2615
|
-
userMenuAdditionalItems,
|
|
2616
|
-
suggestions,
|
|
2617
|
-
agentOptions = [],
|
|
2618
|
-
selectedAgentId = null,
|
|
2619
|
-
onSelectAgent,
|
|
2620
|
-
participantIds,
|
|
2621
|
-
onParticipantsChange,
|
|
2622
|
-
targetAgentId = null,
|
|
2623
|
-
onTargetAgentChange,
|
|
2624
|
-
getRequestHeaders,
|
|
2625
|
-
className,
|
|
2626
|
-
eventInterceptor,
|
|
2627
|
-
runErrorInterceptor,
|
|
2628
|
-
renderSpecialState
|
|
2629
|
-
}) => {
|
|
2663
|
+
var CopilotzChat = ({ userId, userName, userAvatar, userEmail, initialContext, bootstrap, config: userConfig, callbacks: userCallbacks, customComponent, onToolOutput, onCurrentThreadIdChange, onLogout, onViewProfile, onAddMemory, onUpdateMemory, onDeleteMemory, userMenuSections, userMenuAdditionalItems, suggestions, agentOptions = [], selectedAgentId = null, onSelectAgent, participantIds, onParticipantsChange, targetAgentId = null, onTargetAgentChange, getRequestHeaders, className, eventInterceptor, runErrorInterceptor, renderSpecialState }) => {
|
|
2630
2664
|
const selectedAgent = agentOptions.find((agent) => agent.id === selectedAgentId) || null;
|
|
2631
2665
|
const participantAgentIds = useMemo(() => {
|
|
2632
2666
|
if (!participantIds || participantIds.length === 0) return null;
|
|
@@ -2637,26 +2671,7 @@ var CopilotzChat = ({
|
|
|
2637
2671
|
if (!targetAgentId) return null;
|
|
2638
2672
|
return targetAgentId;
|
|
2639
2673
|
}, [targetAgentId]);
|
|
2640
|
-
const {
|
|
2641
|
-
messages,
|
|
2642
|
-
isMessagesLoading,
|
|
2643
|
-
isLoadingOlderMessages,
|
|
2644
|
-
messagePageInfo,
|
|
2645
|
-
threads,
|
|
2646
|
-
currentThreadId,
|
|
2647
|
-
isStreaming,
|
|
2648
|
-
specialState,
|
|
2649
|
-
clearSpecialState,
|
|
2650
|
-
userContextSeed,
|
|
2651
|
-
sendMessage,
|
|
2652
|
-
createThread,
|
|
2653
|
-
selectThread,
|
|
2654
|
-
renameThread,
|
|
2655
|
-
archiveThread,
|
|
2656
|
-
deleteThread: deleteThread2,
|
|
2657
|
-
stopGeneration,
|
|
2658
|
-
loadOlderMessages
|
|
2659
|
-
} = useCopilotz({
|
|
2674
|
+
const { messages, isMessagesLoading, isLoadingOlderMessages, messagePageInfo, threads, currentThreadId, isStreaming, specialState, clearSpecialState, userContextSeed, sendMessage, createThread, selectThread, renameThread, archiveThread, updateThreadTags, deleteThread: deleteThread2, stopGeneration, loadOlderMessages } = useCopilotz({
|
|
2660
2675
|
userId,
|
|
2661
2676
|
userName,
|
|
2662
2677
|
userAvatar,
|
|
@@ -2677,17 +2692,7 @@ var CopilotzChat = ({
|
|
|
2677
2692
|
onCurrentThreadIdChange?.(currentThreadId);
|
|
2678
2693
|
}, [currentThreadId, onCurrentThreadIdChange]);
|
|
2679
2694
|
const chatCallbacks = useMemo(() => {
|
|
2680
|
-
const {
|
|
2681
|
-
onSendMessage: _1,
|
|
2682
|
-
onStopGeneration: _2,
|
|
2683
|
-
onCreateThread: _3,
|
|
2684
|
-
onSelectThread: _4,
|
|
2685
|
-
onRenameThread: _5,
|
|
2686
|
-
onArchiveThread: _6,
|
|
2687
|
-
onDeleteThread: _7,
|
|
2688
|
-
onCopyMessage: _8,
|
|
2689
|
-
...restUserCallbacks
|
|
2690
|
-
} = userCallbacks || {};
|
|
2695
|
+
const { onSendMessage: _1, onStopGeneration: _2, onCreateThread: _3, onSelectThread: _4, onRenameThread: _5, onArchiveThread: _6, onDeleteThread: _7, onUpdateThreadTags: _8, onCopyMessage: _9, ...restUserCallbacks } = userCallbacks || {};
|
|
2691
2696
|
return {
|
|
2692
2697
|
...restUserCallbacks,
|
|
2693
2698
|
onSendMessage: (content, attachments) => {
|
|
@@ -2714,6 +2719,10 @@ var CopilotzChat = ({
|
|
|
2714
2719
|
void archiveThread(threadId);
|
|
2715
2720
|
userCallbacks?.onArchiveThread?.(threadId);
|
|
2716
2721
|
},
|
|
2722
|
+
onUpdateThreadTags: (threadId, tags) => {
|
|
2723
|
+
void updateThreadTags(threadId, tags);
|
|
2724
|
+
userCallbacks?.onUpdateThreadTags?.(threadId, tags);
|
|
2725
|
+
},
|
|
2717
2726
|
onDeleteThread: (threadId) => {
|
|
2718
2727
|
void deleteThread2(threadId);
|
|
2719
2728
|
userCallbacks?.onDeleteThread?.(threadId);
|
|
@@ -2729,18 +2738,7 @@ var CopilotzChat = ({
|
|
|
2729
2738
|
onLogout,
|
|
2730
2739
|
onViewProfile
|
|
2731
2740
|
};
|
|
2732
|
-
}, [
|
|
2733
|
-
sendMessage,
|
|
2734
|
-
stopGeneration,
|
|
2735
|
-
createThread,
|
|
2736
|
-
selectThread,
|
|
2737
|
-
renameThread,
|
|
2738
|
-
archiveThread,
|
|
2739
|
-
deleteThread2,
|
|
2740
|
-
userCallbacks,
|
|
2741
|
-
onLogout,
|
|
2742
|
-
onViewProfile
|
|
2743
|
-
]);
|
|
2741
|
+
}, [sendMessage, stopGeneration, createThread, selectThread, renameThread, archiveThread, updateThreadTags, deleteThread2, userCallbacks, onLogout, onViewProfile]);
|
|
2744
2742
|
const mergedConfig = useMemo(() => {
|
|
2745
2743
|
const base = userConfig || {};
|
|
2746
2744
|
if (!customComponent) {
|
|
@@ -2757,53 +2755,25 @@ var CopilotzChat = ({
|
|
|
2757
2755
|
}, [userConfig, customComponent]);
|
|
2758
2756
|
const effectiveUserName = userName || userId;
|
|
2759
2757
|
const effectiveUserAvatar = userAvatar;
|
|
2760
|
-
const userProp = useMemo(
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2758
|
+
const userProp = useMemo(
|
|
2759
|
+
() => ({
|
|
2760
|
+
id: userId,
|
|
2761
|
+
name: effectiveUserName,
|
|
2762
|
+
email: userEmail,
|
|
2763
|
+
avatar: effectiveUserAvatar
|
|
2764
|
+
}),
|
|
2765
|
+
[userId, effectiveUserName, userEmail, effectiveUserAvatar]
|
|
2766
|
+
);
|
|
2767
|
+
const assistantProp = useMemo(
|
|
2768
|
+
() => ({
|
|
2769
|
+
name: userConfig?.branding?.title,
|
|
2770
|
+
avatar: userConfig?.branding?.avatar,
|
|
2771
|
+
description: userConfig?.branding?.subtitle
|
|
2772
|
+
}),
|
|
2773
|
+
[userConfig?.branding?.title, userConfig?.branding?.avatar, userConfig?.branding?.subtitle]
|
|
2774
|
+
);
|
|
2775
2775
|
const specialStateContent = specialState ? renderSpecialState?.(specialState, { clear: clearSpecialState }) : null;
|
|
2776
|
-
return /* @__PURE__ */ jsx(ChatUserContextProvider, { initial: userContextSeed, children: specialStateContent ?? /* @__PURE__ */ jsx(
|
|
2777
|
-
ChatUI,
|
|
2778
|
-
{
|
|
2779
|
-
messages,
|
|
2780
|
-
isMessagesLoading,
|
|
2781
|
-
isLoadingOlderMessages,
|
|
2782
|
-
hasMoreMessagesBefore: messagePageInfo.hasMoreBefore,
|
|
2783
|
-
onLoadOlderMessages: loadOlderMessages,
|
|
2784
|
-
threads,
|
|
2785
|
-
currentThreadId,
|
|
2786
|
-
config: mergedConfig,
|
|
2787
|
-
callbacks: chatCallbacks,
|
|
2788
|
-
isGenerating: isStreaming,
|
|
2789
|
-
suggestions,
|
|
2790
|
-
agentOptions,
|
|
2791
|
-
selectedAgentId,
|
|
2792
|
-
onSelectAgent,
|
|
2793
|
-
participantIds,
|
|
2794
|
-
onParticipantsChange,
|
|
2795
|
-
targetAgentId,
|
|
2796
|
-
onTargetAgentChange,
|
|
2797
|
-
user: userProp,
|
|
2798
|
-
assistant: assistantProp,
|
|
2799
|
-
onAddMemory,
|
|
2800
|
-
onUpdateMemory,
|
|
2801
|
-
onDeleteMemory,
|
|
2802
|
-
userMenuSections,
|
|
2803
|
-
userMenuAdditionalItems,
|
|
2804
|
-
className
|
|
2805
|
-
}
|
|
2806
|
-
) });
|
|
2776
|
+
return /* @__PURE__ */ jsx(ChatUserContextProvider, { initial: userContextSeed, children: specialStateContent ?? /* @__PURE__ */ jsx(ChatUI, { messages, isMessagesLoading, isLoadingOlderMessages, hasMoreMessagesBefore: messagePageInfo.hasMoreBefore, onLoadOlderMessages: loadOlderMessages, threads, currentThreadId, config: mergedConfig, callbacks: chatCallbacks, isGenerating: isStreaming, suggestions, agentOptions, selectedAgentId, onSelectAgent, participantIds, onParticipantsChange, targetAgentId, onTargetAgentChange, user: userProp, assistant: assistantProp, onAddMemory, onUpdateMemory, onDeleteMemory, userMenuSections, userMenuAdditionalItems, className }) });
|
|
2807
2777
|
};
|
|
2808
2778
|
export {
|
|
2809
2779
|
CopilotzChat,
|