@mastra/react 1.4.12 → 1.4.13-alpha.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/agent/hooks.d.ts.map +1 -1
- package/dist/index.cjs +111 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +111 -44
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1795,7 +1795,7 @@ const extractRunIdFromMessages = (messages) => {
|
|
|
1795
1795
|
};
|
|
1796
1796
|
//#endregion
|
|
1797
1797
|
//#region src/agent/hooks.ts
|
|
1798
|
-
const extractPendingToolApprovalIdsFromMessages = (messages) => {
|
|
1798
|
+
const extractPendingToolApprovalIdsFromMessages = (messages, runId) => {
|
|
1799
1799
|
const pendingToolApprovalIds = /* @__PURE__ */ new Set();
|
|
1800
1800
|
for (const message of messages) {
|
|
1801
1801
|
const metadata = message.content?.metadata;
|
|
@@ -1808,6 +1808,7 @@ const extractPendingToolApprovalIdsFromMessages = (messages) => {
|
|
|
1808
1808
|
for (const source of metadataSources) {
|
|
1809
1809
|
if (!source || typeof source !== "object") continue;
|
|
1810
1810
|
for (const suspensionData of Object.values(source)) {
|
|
1811
|
+
if (runId && suspensionData?.runId !== runId) continue;
|
|
1811
1812
|
const toolCallId = suspensionData?.toolCallId;
|
|
1812
1813
|
if (typeof toolCallId === "string" && toolCallId.length > 0) pendingToolApprovalIds.add(toolCallId);
|
|
1813
1814
|
}
|
|
@@ -1821,6 +1822,11 @@ const toolCallHasOutput = (parts, toolCallId) => parts.some((part) => {
|
|
|
1821
1822
|
if (invocation.toolCallId !== toolCallId) return false;
|
|
1822
1823
|
return invocation.state === "result" || invocation.result != null;
|
|
1823
1824
|
});
|
|
1825
|
+
const filterUnresolvedApprovals = (entries, parts) => {
|
|
1826
|
+
if (!entries || typeof entries !== "object") return void 0;
|
|
1827
|
+
const pending = Object.fromEntries(Object.entries(entries).filter(([, approval]) => approval && typeof approval === "object" && typeof approval.toolCallId === "string" && !toolCallHasOutput(parts, approval.toolCallId)));
|
|
1828
|
+
return Object.keys(pending).length ? pending : void 0;
|
|
1829
|
+
};
|
|
1824
1830
|
/**
|
|
1825
1831
|
* Normalize persisted initial messages back into the stream-friendly shape the
|
|
1826
1832
|
* UI renders from. Mirrors `main`'s `resolveInitialMessages`:
|
|
@@ -1850,22 +1856,25 @@ const resolveInitialMessages = (messages) => messages.filter((message) => {
|
|
|
1850
1856
|
};
|
|
1851
1857
|
})() : message;
|
|
1852
1858
|
const normalizedMetadata = normalizedMessage.content?.metadata;
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
const
|
|
1856
|
-
const
|
|
1857
|
-
const
|
|
1859
|
+
if (!normalizedMetadata?.pendingToolApprovals && !normalizedMetadata?.requireApprovalMetadata && !normalizedMetadata?.suspendedTools) return normalizedMessage;
|
|
1860
|
+
const { pendingToolApprovals, requireApprovalMetadata, suspendedTools, ...restMetadata } = normalizedMetadata;
|
|
1861
|
+
const parts = normalizedMessage.content.parts;
|
|
1862
|
+
const pending = filterUnresolvedApprovals(pendingToolApprovals, parts);
|
|
1863
|
+
const required = {
|
|
1864
|
+
...filterUnresolvedApprovals(requireApprovalMetadata, parts),
|
|
1865
|
+
...pending
|
|
1866
|
+
};
|
|
1867
|
+
const suspended = filterUnresolvedApprovals(suspendedTools, parts);
|
|
1858
1868
|
return {
|
|
1859
1869
|
...normalizedMessage,
|
|
1860
1870
|
content: {
|
|
1861
1871
|
...normalizedMessage.content,
|
|
1862
1872
|
metadata: {
|
|
1863
1873
|
...restMetadata,
|
|
1864
|
-
mode: "stream",
|
|
1865
|
-
...
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
} : {}
|
|
1874
|
+
...pendingToolApprovals ? { mode: "stream" } : {},
|
|
1875
|
+
...pending ? { pendingToolApprovals: pending } : {},
|
|
1876
|
+
...Object.keys(required).length ? { requireApprovalMetadata: required } : {},
|
|
1877
|
+
...suspended ? { suspendedTools: suspended } : {}
|
|
1869
1878
|
}
|
|
1870
1879
|
}
|
|
1871
1880
|
};
|
|
@@ -1914,20 +1923,64 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
|
|
|
1914
1923
|
const _threadSignalsUnsupportedRef = useRef(false);
|
|
1915
1924
|
const [messages, setMessages] = useState([]);
|
|
1916
1925
|
const [tasks, setTasks] = useState([]);
|
|
1926
|
+
const liveTasks = useRef(void 0);
|
|
1917
1927
|
const [toolCallApprovals, setToolCallApprovals] = useState({});
|
|
1918
1928
|
const [networkToolCallApprovals, setNetworkToolCallApprovals] = useState({});
|
|
1919
1929
|
const pendingToolApprovalIdsRef = useRef(/* @__PURE__ */ new Set());
|
|
1930
|
+
const liveApprovalIds = useRef(/* @__PURE__ */ new Set());
|
|
1931
|
+
const liveRunId = useRef(void 0);
|
|
1932
|
+
const liveRunFinished = useRef(false);
|
|
1920
1933
|
const [isAwaitingToolApproval, setIsAwaitingToolApproval] = useState(false);
|
|
1921
1934
|
const baseClient = useMastraClient();
|
|
1922
1935
|
const [isRunning, setIsRunning] = useState(false);
|
|
1936
|
+
const lastHydration = useRef(void 0);
|
|
1923
1937
|
useEffect(() => {
|
|
1938
|
+
const previous = lastHydration.current;
|
|
1939
|
+
const sameThread = previous?.agentId === agentId && previous.resourceId === resourceId && previous.threadId === threadId;
|
|
1940
|
+
if (sameThread && previous.initialMessages === initialMessages) return;
|
|
1924
1941
|
const formattedMessages = resolveInitialMessages(initialMessages ?? []);
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1942
|
+
lastHydration.current = {
|
|
1943
|
+
agentId,
|
|
1944
|
+
resourceId,
|
|
1945
|
+
threadId,
|
|
1946
|
+
initialMessages,
|
|
1947
|
+
formattedMessages
|
|
1948
|
+
};
|
|
1949
|
+
if (sameThread) {
|
|
1950
|
+
const previousById = new Map(previous.formattedMessages.map((message) => [message.id, message]));
|
|
1951
|
+
setMessages((current) => {
|
|
1952
|
+
const live = current.filter((message) => previousById.get(message.id) !== message);
|
|
1953
|
+
const liveById = new Map(live.map((message) => [message.id, message]));
|
|
1954
|
+
const historyIds = new Set(formattedMessages.map((message) => message.id));
|
|
1955
|
+
return [...formattedMessages.map((message) => liveById.get(message.id) ?? message), ...live.filter((message) => !historyIds.has(message.id))];
|
|
1956
|
+
});
|
|
1957
|
+
setTasks(liveTasks.current ?? extractLatestTasksFromMessages(formattedMessages));
|
|
1958
|
+
const historyRunId = extractRunIdFromMessages(formattedMessages);
|
|
1959
|
+
if (liveRunFinished.current) return;
|
|
1960
|
+
if (!liveRunId.current && isRunning && historyRunId !== _currentRunId.current) return;
|
|
1961
|
+
} else {
|
|
1962
|
+
liveTasks.current = void 0;
|
|
1963
|
+
liveApprovalIds.current.clear();
|
|
1964
|
+
liveRunId.current = void 0;
|
|
1965
|
+
liveRunFinished.current = false;
|
|
1966
|
+
if (previous) setIsRunning(false);
|
|
1967
|
+
setMessages(formattedMessages);
|
|
1968
|
+
setTasks(extractLatestTasksFromMessages(formattedMessages));
|
|
1969
|
+
}
|
|
1970
|
+
const pendingApprovals = extractPendingToolApprovalIdsFromMessages(formattedMessages, liveRunId.current);
|
|
1971
|
+
for (const toolCallId of liveApprovalIds.current) if (pendingToolApprovalIdsRef.current.has(toolCallId)) pendingApprovals.add(toolCallId);
|
|
1972
|
+
else pendingApprovals.delete(toolCallId);
|
|
1973
|
+
pendingToolApprovalIdsRef.current = pendingApprovals;
|
|
1974
|
+
setIsAwaitingToolApproval(pendingApprovals.size > 0);
|
|
1975
|
+
_currentRunId.current = liveRunId.current ?? extractRunIdFromMessages(formattedMessages);
|
|
1976
|
+
}, [
|
|
1977
|
+
agentId,
|
|
1978
|
+
resourceId,
|
|
1979
|
+
threadId,
|
|
1980
|
+
initialMessages,
|
|
1981
|
+
isRunning,
|
|
1982
|
+
isAwaitingToolApproval
|
|
1983
|
+
]);
|
|
1931
1984
|
useEffect(() => {
|
|
1932
1985
|
_activeContinuation.current = {
|
|
1933
1986
|
..._activeContinuation.current,
|
|
@@ -1990,29 +2043,40 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
|
|
|
1990
2043
|
_threadSubscriptionPromiseRef.current = null;
|
|
1991
2044
|
}, []);
|
|
1992
2045
|
const processStreamChunk = useCallback(async (chunk, onChunk) => {
|
|
2046
|
+
const isTerminal = chunk.type === "finish" || chunk.type === "abort" || chunk.type === "error";
|
|
2047
|
+
if (isTerminal && liveRunId.current && chunk.runId !== liveRunId.current) return;
|
|
1993
2048
|
setMessages((prev) => accumulateChunk({
|
|
1994
2049
|
chunk,
|
|
1995
2050
|
conversation: prev,
|
|
1996
2051
|
metadata: { mode: "stream" }
|
|
1997
2052
|
}));
|
|
1998
|
-
const
|
|
1999
|
-
if (
|
|
2000
|
-
|
|
2001
|
-
|
|
2053
|
+
const streamedTasks = extractTasksFromToolResultChunk(chunk) ?? extractTasksFromSignalChunk(chunk);
|
|
2054
|
+
if (streamedTasks !== void 0) {
|
|
2055
|
+
liveTasks.current = streamedTasks;
|
|
2056
|
+
setTasks(streamedTasks);
|
|
2057
|
+
}
|
|
2002
2058
|
if (chunk.type === "data-user-message" && isDataChunk(chunk) && (chunk.data?.type === "user-message" || chunk.data?.type === "user") && typeof chunk.data?.id === "string") onSignalEcho?.(chunk.data.id);
|
|
2003
2059
|
if (chunk.type === "start") {
|
|
2004
2060
|
setIsRunning(true);
|
|
2005
|
-
if ("runId" in chunk && typeof chunk.runId === "string")
|
|
2061
|
+
if ("runId" in chunk && typeof chunk.runId === "string") {
|
|
2062
|
+
if (liveRunId.current !== chunk.runId) liveApprovalIds.current.clear();
|
|
2063
|
+
liveRunFinished.current = false;
|
|
2064
|
+
liveRunId.current = chunk.runId;
|
|
2065
|
+
_currentRunId.current = chunk.runId;
|
|
2066
|
+
}
|
|
2006
2067
|
}
|
|
2007
2068
|
if (chunk.type === "tool-call-approval" || chunk.type === "tool-call-suspended") {
|
|
2008
2069
|
const toolCallId = chunk.payload?.toolCallId;
|
|
2009
2070
|
if (typeof toolCallId === "string") {
|
|
2071
|
+
liveApprovalIds.current.add(toolCallId);
|
|
2010
2072
|
pendingToolApprovalIdsRef.current.add(toolCallId);
|
|
2011
2073
|
setIsAwaitingToolApproval(true);
|
|
2012
2074
|
}
|
|
2013
2075
|
setIsRunning(false);
|
|
2014
2076
|
}
|
|
2015
|
-
if (
|
|
2077
|
+
if (isTerminal) {
|
|
2078
|
+
if (chunk.runId === liveRunId.current) liveRunFinished.current = true;
|
|
2079
|
+
for (const toolCallId of pendingToolApprovalIdsRef.current) liveApprovalIds.current.add(toolCallId);
|
|
2016
2080
|
pendingToolApprovalIdsRef.current.clear();
|
|
2017
2081
|
setIsAwaitingToolApproval(false);
|
|
2018
2082
|
setIsRunning(false);
|
|
@@ -2293,30 +2357,28 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
|
|
|
2293
2357
|
onSignalSent?.(echoedSignalId, getSignalPreview(coreUserMessages));
|
|
2294
2358
|
if (pendingToolApprovalIdsRef.current.size > 0) setIsRunning(false);
|
|
2295
2359
|
} catch (error) {
|
|
2296
|
-
if (isThreadSignalUnsupportedError(error)) {
|
|
2360
|
+
if (isThreadSignalUnsupportedError(error)) try {
|
|
2361
|
+
await agent.sendSignal({
|
|
2362
|
+
signal: {
|
|
2363
|
+
id: resolvedSignalId,
|
|
2364
|
+
type: "user-message",
|
|
2365
|
+
contents: messageContents
|
|
2366
|
+
},
|
|
2367
|
+
resourceId: resourceId || agentId,
|
|
2368
|
+
threadId,
|
|
2369
|
+
ifIdle: { streamOptions }
|
|
2370
|
+
});
|
|
2297
2371
|
onSignalSent?.(resolvedSignalId, getSignalPreview(coreUserMessages));
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
resourceId: resourceId || agentId,
|
|
2306
|
-
threadId,
|
|
2307
|
-
ifIdle: { streamOptions }
|
|
2308
|
-
});
|
|
2372
|
+
return;
|
|
2373
|
+
} catch (signalError) {
|
|
2374
|
+
onSignalEcho?.(resolvedSignalId);
|
|
2375
|
+
if (isThreadSignalUnsupportedError(signalError)) {
|
|
2376
|
+
markThreadSignalsUnsupported();
|
|
2377
|
+
setMessages((prev) => [...prev, fromCoreUserMessagesToMastraDBMessage(coreUserMessages)]);
|
|
2378
|
+
await streamWithLegacyRoute();
|
|
2309
2379
|
return;
|
|
2310
|
-
} catch (signalError) {
|
|
2311
|
-
onSignalEcho?.(resolvedSignalId);
|
|
2312
|
-
if (isThreadSignalUnsupportedError(signalError)) {
|
|
2313
|
-
markThreadSignalsUnsupported();
|
|
2314
|
-
setMessages((prev) => [...prev, fromCoreUserMessagesToMastraDBMessage(coreUserMessages)]);
|
|
2315
|
-
await streamWithLegacyRoute();
|
|
2316
|
-
return;
|
|
2317
|
-
}
|
|
2318
|
-
throw signalError;
|
|
2319
2380
|
}
|
|
2381
|
+
throw signalError;
|
|
2320
2382
|
}
|
|
2321
2383
|
throw error;
|
|
2322
2384
|
}
|
|
@@ -2377,6 +2439,7 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
|
|
|
2377
2439
|
});
|
|
2378
2440
|
closeThreadSubscription();
|
|
2379
2441
|
setMessages((prev) => finishStreamingAssistantMessage(prev));
|
|
2442
|
+
liveRunFinished.current = true;
|
|
2380
2443
|
pendingToolApprovalIdsRef.current.clear();
|
|
2381
2444
|
setIsAwaitingToolApproval(false);
|
|
2382
2445
|
setIsRunning(false);
|
|
@@ -2408,6 +2471,8 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
|
|
|
2408
2471
|
...resumeData !== void 0 ? { resumeData } : {},
|
|
2409
2472
|
requestContext: continuation.requestContext
|
|
2410
2473
|
});
|
|
2474
|
+
liveRunId.current ??= currentRunId;
|
|
2475
|
+
liveApprovalIds.current.add(toolCallId);
|
|
2411
2476
|
pendingToolApprovalIdsRef.current.delete(toolCallId);
|
|
2412
2477
|
setIsAwaitingToolApproval(pendingToolApprovalIdsRef.current.size > 0);
|
|
2413
2478
|
setIsRunning(false);
|
|
@@ -2466,6 +2531,8 @@ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContex
|
|
|
2466
2531
|
...continuation.model !== void 0 ? { streamOptions: { model: continuation.model } } : {},
|
|
2467
2532
|
requestContext: continuation.requestContext
|
|
2468
2533
|
});
|
|
2534
|
+
liveRunId.current ??= currentRunId;
|
|
2535
|
+
liveApprovalIds.current.add(toolCallId);
|
|
2469
2536
|
pendingToolApprovalIdsRef.current.delete(toolCallId);
|
|
2470
2537
|
setIsAwaitingToolApproval(pendingToolApprovalIdsRef.current.size > 0);
|
|
2471
2538
|
setIsRunning(false);
|