@mastra/react 1.5.1-alpha.2 → 1.6.0-alpha.10
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.cjs +268 -405
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +269 -351
- package/dist/index.js.map +1 -1
- package/dist/lib/mastra-db/accumulator.d.ts +1 -1
- package/dist/lib/mastra-db/accumulator.d.ts.map +1 -1
- package/dist/ui/index.cjs +575 -56
- package/dist/ui/index.cjs.map +1 -0
- package/dist/ui/index.js +497 -1
- package/dist/ui/index.js.map +1 -0
- package/dist/workflows/use-stream-workflow.d.ts +1 -29
- package/dist/workflows/use-stream-workflow.d.ts.map +1 -1
- package/package.json +4 -4
- package/dist/ui-BQyoxYsH.js +0 -498
- package/dist/ui-BQyoxYsH.js.map +0 -1
- package/dist/ui-C979LXC_.cjs +0 -850
- package/dist/ui-C979LXC_.cjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { $ as useEntity, A as TooltipContentClass, B as ToolApprovalContent, C as CodeBlock, D as IconButtonClass, E as IconButton, F as EntryTitleClass, G as ToolApprovalTitleClass, H as ToolApprovalHeader, I as ToolApproval, J as EntityContent, K as Entity, L as ToolApprovalActions, M as Entry, N as EntryClass, O as Tooltip, P as EntryTitle, Q as EntityTriggerVariantClasses, R as ToolApprovalActionsClass, S as AgentIcon, T as CodeCopyButton, U as ToolApprovalHeaderClass, V as ToolApprovalContentClass, W as ToolApprovalTitle, X as EntityTrigger, Y as EntityContentClass, Z as EntityTriggerClass, _ as MessageUsageValueClass, a as MessageClass, b as WorkflowIcon, c as MessageList, d as MessageStreamingClass, et as Icon, f as MessageUsage, g as MessageUsageValue, h as MessageUsageEntryClass, i as MessageActionsClass, j as TooltipTrigger, k as TooltipContent, l as MessageListClass, m as MessageUsageEntry, n as Message, o as MessageContent, p as MessageUsageClass, q as EntityCaret, r as MessageActions, s as MessageContentClass, t as MessageFactory, tt as IconSizes, u as MessageStreaming, v as MessageUsages, w as CodeBlockClass, x as ToolsIcon, y as MessageUsagesClass, z as ToolApprovalClass } from "./ui-BQyoxYsH.js";
|
|
2
1
|
import { MastraClient } from "@mastra/client-js";
|
|
3
2
|
import { createContext, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
4
3
|
import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
|
|
@@ -140,6 +139,37 @@ function toolErrorText(error) {
|
|
|
140
139
|
}
|
|
141
140
|
return String(error);
|
|
142
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Agent-as-tool boundaries wrap progressive chunks in nested `tool-output`
|
|
144
|
+
* envelopes. Peel only agent boundaries; workflow/tool envelopes remain the
|
|
145
|
+
* leaf so existing child-message accumulation can process them normally.
|
|
146
|
+
*/
|
|
147
|
+
const normalizeNestedAgentOutput = (output) => {
|
|
148
|
+
const boundaries = [];
|
|
149
|
+
const seen = /* @__PURE__ */ new Set();
|
|
150
|
+
let current = output;
|
|
151
|
+
while (current !== null && typeof current === "object") {
|
|
152
|
+
if (seen.has(current)) return void 0;
|
|
153
|
+
seen.add(current);
|
|
154
|
+
const chunk = current;
|
|
155
|
+
if (chunk.type !== "tool-output") return {
|
|
156
|
+
leaf: current,
|
|
157
|
+
boundaries
|
|
158
|
+
};
|
|
159
|
+
const toolCallId = chunk.payload?.toolCallId;
|
|
160
|
+
const toolName = chunk.payload?.toolName;
|
|
161
|
+
if (typeof toolName !== "string" || !toolName.startsWith("agent-")) return {
|
|
162
|
+
leaf: current,
|
|
163
|
+
boundaries
|
|
164
|
+
};
|
|
165
|
+
if (typeof toolCallId !== "string" || !("output" in (chunk.payload ?? {}))) return void 0;
|
|
166
|
+
boundaries.push({
|
|
167
|
+
toolCallId,
|
|
168
|
+
toolName
|
|
169
|
+
});
|
|
170
|
+
current = chunk.payload?.output;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
143
173
|
const cloneMetadata = (metadata) => metadata ? { ...metadata } : {};
|
|
144
174
|
const withParts = (message, parts) => ({
|
|
145
175
|
...message,
|
|
@@ -267,39 +297,47 @@ const mergeBgTaskMetadata = (existing, mode, args, otherMetadata) => {
|
|
|
267
297
|
* `mapWorkflowStreamChunkToWatchResult` from the previous accumulator.
|
|
268
298
|
*/
|
|
269
299
|
const mapWorkflowStreamChunkToWatchResult = (prev, chunk) => {
|
|
300
|
+
const previous = prev ?? {
|
|
301
|
+
status: "running",
|
|
302
|
+
input: void 0,
|
|
303
|
+
steps: {}
|
|
304
|
+
};
|
|
270
305
|
if (chunk.type === "workflow-start") return {
|
|
271
|
-
input:
|
|
306
|
+
input: previous.input,
|
|
272
307
|
status: "running",
|
|
273
|
-
steps:
|
|
308
|
+
steps: previous.steps
|
|
274
309
|
};
|
|
275
310
|
if (chunk.type === "workflow-canceled") return {
|
|
276
|
-
...
|
|
311
|
+
...previous,
|
|
277
312
|
status: "canceled"
|
|
278
313
|
};
|
|
314
|
+
if (chunk.type === "workflow-paused") return {
|
|
315
|
+
...previous,
|
|
316
|
+
status: "paused"
|
|
317
|
+
};
|
|
279
318
|
if (chunk.type === "workflow-finish") {
|
|
280
319
|
const finalStatus = chunk.payload.workflowStatus;
|
|
281
|
-
const
|
|
282
|
-
const lastStep = Object.values(prevSteps).pop();
|
|
320
|
+
const lastStep = Object.values(previous.steps).pop();
|
|
283
321
|
return {
|
|
284
|
-
...
|
|
322
|
+
...previous,
|
|
285
323
|
status: chunk.payload.workflowStatus,
|
|
286
324
|
...finalStatus === "success" && lastStep?.status === "success" ? { result: lastStep?.output } : finalStatus === "failed" && lastStep?.status === "failed" ? { error: lastStep?.error } : finalStatus === "tripwire" && chunk.payload.tripwire ? { tripwire: chunk.payload.tripwire } : {}
|
|
287
325
|
};
|
|
288
326
|
}
|
|
289
327
|
const { stepCallId: _stepCallId, stepName: _stepName, ...newPayload } = chunk.payload ?? {};
|
|
290
328
|
const newSteps = {
|
|
291
|
-
...
|
|
329
|
+
...previous.steps,
|
|
292
330
|
[chunk.payload.id]: {
|
|
293
|
-
...
|
|
331
|
+
...previous.steps[chunk.payload.id],
|
|
294
332
|
...newPayload
|
|
295
333
|
}
|
|
296
334
|
};
|
|
297
335
|
if (chunk.type === "workflow-step-start") return {
|
|
298
|
-
...
|
|
336
|
+
...previous,
|
|
299
337
|
steps: newSteps
|
|
300
338
|
};
|
|
301
339
|
if (chunk.type === "workflow-step-suspended") {
|
|
302
|
-
const
|
|
340
|
+
const suspended = Object.entries(newSteps).flatMap(([stepId, stepResult]) => {
|
|
303
341
|
if (stepResult?.status === "suspended") {
|
|
304
342
|
const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
|
|
305
343
|
return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
|
|
@@ -307,24 +345,24 @@ const mapWorkflowStreamChunkToWatchResult = (prev, chunk) => {
|
|
|
307
345
|
return [];
|
|
308
346
|
});
|
|
309
347
|
return {
|
|
310
|
-
...
|
|
348
|
+
...previous,
|
|
311
349
|
status: "suspended",
|
|
312
350
|
steps: newSteps,
|
|
313
351
|
suspendPayload: chunk.payload.suspendPayload,
|
|
314
|
-
suspended
|
|
352
|
+
suspended
|
|
315
353
|
};
|
|
316
354
|
}
|
|
317
355
|
if (chunk.type === "workflow-step-waiting") return {
|
|
318
|
-
...
|
|
356
|
+
...previous,
|
|
319
357
|
status: "waiting",
|
|
320
358
|
steps: newSteps
|
|
321
359
|
};
|
|
322
360
|
if (chunk.type === "workflow-step-progress") return {
|
|
323
|
-
...
|
|
361
|
+
...previous,
|
|
324
362
|
steps: {
|
|
325
|
-
...
|
|
363
|
+
...previous.steps,
|
|
326
364
|
[chunk.payload.id]: {
|
|
327
|
-
...
|
|
365
|
+
...previous.steps[chunk.payload.id],
|
|
328
366
|
foreachProgress: {
|
|
329
367
|
completedCount: chunk.payload.completedCount,
|
|
330
368
|
totalCount: chunk.payload.totalCount,
|
|
@@ -336,10 +374,10 @@ const mapWorkflowStreamChunkToWatchResult = (prev, chunk) => {
|
|
|
336
374
|
}
|
|
337
375
|
};
|
|
338
376
|
if (chunk.type === "workflow-step-result") return {
|
|
339
|
-
...
|
|
377
|
+
...previous,
|
|
340
378
|
steps: newSteps
|
|
341
379
|
};
|
|
342
|
-
return
|
|
380
|
+
return previous;
|
|
343
381
|
};
|
|
344
382
|
const signalContentsToUserMessages = (contents, metadata) => {
|
|
345
383
|
const makeUserMessage = (parts) => ({
|
|
@@ -829,7 +867,7 @@ const accumulateChunk = ({ chunk, conversation, metadata }) => {
|
|
|
829
867
|
toolName,
|
|
830
868
|
args,
|
|
831
869
|
errorText,
|
|
832
|
-
...
|
|
870
|
+
...chunk.from === "AGENT" ? { result: toolPart.toolInvocation.result } : {}
|
|
833
871
|
}
|
|
834
872
|
};
|
|
835
873
|
} else {
|
|
@@ -851,7 +889,7 @@ const accumulateChunk = ({ chunk, conversation, metadata }) => {
|
|
|
851
889
|
};
|
|
852
890
|
else output = payloadResult;
|
|
853
891
|
} else if (isAgent) {
|
|
854
|
-
const existingOutput = toolPart.toolInvocation.state === "result" ? toolPart.toolInvocation.result : void 0;
|
|
892
|
+
const existingOutput = toolPart.toolInvocation.state === "partial-call" || toolPart.toolInvocation.state === "result" ? toolPart.toolInvocation.result : void 0;
|
|
855
893
|
const existingChild = existingOutput?.childMessages;
|
|
856
894
|
output = existingOutput ? {
|
|
857
895
|
...payloadResult,
|
|
@@ -916,7 +954,7 @@ const accumulateChunk = ({ chunk, conversation, metadata }) => {
|
|
|
916
954
|
const { toolName, toolCallId, args } = toolPart.toolInvocation;
|
|
917
955
|
const payloadOutput = chunk.type === "background-task-output" ? chunk.payload.payload.payload.output : chunk.payload.output;
|
|
918
956
|
if (payloadOutput?.type?.startsWith("workflow-")) {
|
|
919
|
-
const existingWorkflowState = toolPart.toolInvocation.result
|
|
957
|
+
const existingWorkflowState = toolPart.toolInvocation.result;
|
|
920
958
|
const updated = mapWorkflowStreamChunkToWatchResult(existingWorkflowState, payloadOutput);
|
|
921
959
|
parts[toolPartIndex] = {
|
|
922
960
|
...toolPart,
|
|
@@ -928,8 +966,13 @@ const accumulateChunk = ({ chunk, conversation, metadata }) => {
|
|
|
928
966
|
result: updated
|
|
929
967
|
}
|
|
930
968
|
};
|
|
931
|
-
} else if (
|
|
932
|
-
|
|
969
|
+
} else if (toolName.startsWith("agent-") || payloadOutput?.from === "AGENT") {
|
|
970
|
+
const normalized = normalizeNestedAgentOutput(payloadOutput);
|
|
971
|
+
if (!normalized) return result;
|
|
972
|
+
const { leaf, boundaries } = normalized;
|
|
973
|
+
if (leaf.from === "AGENT" || leaf.type === "tool-output" && leaf.payload?.output?.type?.startsWith("workflow-")) return accumulateAgentChunk(leaf, result, metadata, toolCallId, toolName, boundaries);
|
|
974
|
+
return result;
|
|
975
|
+
} else {
|
|
933
976
|
const currentResult = toolPart.toolInvocation.result;
|
|
934
977
|
const existing = Array.isArray(currentResult) ? currentResult : [];
|
|
935
978
|
parts[toolPartIndex] = {
|
|
@@ -1146,8 +1189,7 @@ const accumulateChunk = ({ chunk, conversation, metadata }) => {
|
|
|
1146
1189
|
case "network-validation-start":
|
|
1147
1190
|
case "network-validation-end":
|
|
1148
1191
|
case "network-object":
|
|
1149
|
-
case "network-object-result":
|
|
1150
|
-
case "tool-output-denied": return result;
|
|
1192
|
+
case "network-object-result": return result;
|
|
1151
1193
|
default: return assertExhaustive(chunk, result);
|
|
1152
1194
|
}
|
|
1153
1195
|
};
|
|
@@ -1158,112 +1200,130 @@ const accumulateChunk = ({ chunk, conversation, metadata }) => {
|
|
|
1158
1200
|
* that isn't enumerated above.
|
|
1159
1201
|
*/
|
|
1160
1202
|
const assertExhaustive = (_chunk, fallback) => fallback;
|
|
1161
|
-
const
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1203
|
+
const findAgentChildToolIndex = (childMessages, toolCallId, toolName) => {
|
|
1204
|
+
for (let index = childMessages.length - 1; index >= 0; index--) {
|
|
1205
|
+
const message = childMessages[index];
|
|
1206
|
+
if (message?.type !== "tool") continue;
|
|
1207
|
+
if (toolCallId ? message.toolCallId === toolCallId : toolName && message.toolName === toolName) return index;
|
|
1208
|
+
}
|
|
1209
|
+
return -1;
|
|
1210
|
+
};
|
|
1211
|
+
const accumulateAgentChildMessages = (chunk, childMessages) => {
|
|
1166
1212
|
if (chunk.type === "text-delta") {
|
|
1167
|
-
const
|
|
1168
|
-
const toolPartIndex = findToolPartIndex();
|
|
1169
|
-
if (toolPartIndex === -1) return conversation;
|
|
1170
|
-
const toolPart = parts[toolPartIndex];
|
|
1171
|
-
const existingResult = toolPart.toolInvocation.result || {};
|
|
1172
|
-
const childMessages = existingResult.childMessages || [];
|
|
1213
|
+
const text = chunk.payload.text;
|
|
1173
1214
|
const lastChildMessage = childMessages[childMessages.length - 1];
|
|
1174
1215
|
const textMessage = {
|
|
1175
1216
|
type: "text",
|
|
1176
|
-
content: (lastChildMessage?.content
|
|
1217
|
+
content: (lastChildMessage?.type === "text" ? lastChildMessage.content : "") + text
|
|
1177
1218
|
};
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1219
|
+
return lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
|
|
1220
|
+
}
|
|
1221
|
+
if (chunk.type === "tool-call") {
|
|
1222
|
+
const existingIndex = findAgentChildToolIndex(childMessages, chunk.payload.toolCallId);
|
|
1223
|
+
const toolMessage = {
|
|
1224
|
+
...existingIndex === -1 ? {} : childMessages[existingIndex],
|
|
1225
|
+
type: "tool",
|
|
1226
|
+
toolCallId: chunk.payload.toolCallId,
|
|
1227
|
+
toolName: chunk.payload.toolName,
|
|
1228
|
+
args: chunk.payload.args
|
|
1188
1229
|
};
|
|
1189
|
-
|
|
1190
|
-
const
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
const
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
}]
|
|
1208
|
-
}
|
|
1230
|
+
if (existingIndex === -1) return [...childMessages, toolMessage];
|
|
1231
|
+
const nextMessages = [...childMessages];
|
|
1232
|
+
nextMessages[existingIndex] = toolMessage;
|
|
1233
|
+
return nextMessages;
|
|
1234
|
+
}
|
|
1235
|
+
if (chunk.type === "tool-output" && chunk.payload.output?.type?.startsWith("workflow-")) {
|
|
1236
|
+
const toolIndex = findAgentChildToolIndex(childMessages, chunk.payload.toolCallId, chunk.payload.toolName);
|
|
1237
|
+
if (toolIndex === -1) return childMessages;
|
|
1238
|
+
const currentMessage = childMessages[toolIndex];
|
|
1239
|
+
if (currentMessage?.type !== "tool") return childMessages;
|
|
1240
|
+
const existingWorkflowState = currentMessage.toolOutput && typeof currentMessage.toolOutput === "object" ? currentMessage.toolOutput : {};
|
|
1241
|
+
const updated = mapWorkflowStreamChunkToWatchResult(existingWorkflowState, chunk.payload.output);
|
|
1242
|
+
const nextMessages = [...childMessages];
|
|
1243
|
+
nextMessages[toolIndex] = {
|
|
1244
|
+
...currentMessage,
|
|
1245
|
+
toolOutput: {
|
|
1246
|
+
...updated,
|
|
1247
|
+
runId: chunk.payload.output.runId
|
|
1209
1248
|
}
|
|
1210
1249
|
};
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
...toolPart.toolInvocation,
|
|
1227
|
-
result: {
|
|
1228
|
-
...existingResult,
|
|
1229
|
-
childMessages: [...childMessages.slice(0, -1), {
|
|
1230
|
-
...currentMessage,
|
|
1231
|
-
toolOutput: {
|
|
1232
|
-
...updated,
|
|
1233
|
-
runId: agentChunk.output.runId
|
|
1234
|
-
}
|
|
1235
|
-
}]
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
};
|
|
1239
|
-
}
|
|
1240
|
-
} else if (chunk.type === "tool-result") {
|
|
1241
|
-
const agentChunk = chunk.payload;
|
|
1242
|
-
const toolPartIndex = findToolPartIndex();
|
|
1243
|
-
if (toolPartIndex === -1) return conversation;
|
|
1244
|
-
const toolPart = parts[toolPartIndex];
|
|
1245
|
-
const existingResult = toolPart.toolInvocation.result || {};
|
|
1246
|
-
const childMessages = existingResult.childMessages || [];
|
|
1247
|
-
const lastIndex = childMessages.length - 1;
|
|
1248
|
-
const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
|
|
1249
|
-
if (lastIndex >= 0 && childMessages[lastIndex]?.type === "tool") parts[toolPartIndex] = {
|
|
1250
|
-
...toolPart,
|
|
1251
|
-
toolInvocation: {
|
|
1252
|
-
...toolPart.toolInvocation,
|
|
1253
|
-
result: {
|
|
1254
|
-
...existingResult,
|
|
1255
|
-
childMessages: [...childMessages.slice(0, -1), {
|
|
1256
|
-
...childMessages[lastIndex],
|
|
1257
|
-
toolOutput: isWorkflow ? {
|
|
1258
|
-
...agentChunk.result?.result,
|
|
1259
|
-
runId: agentChunk.result?.runId
|
|
1260
|
-
} : agentChunk.result
|
|
1261
|
-
}]
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1250
|
+
return nextMessages;
|
|
1251
|
+
}
|
|
1252
|
+
if (chunk.type === "tool-result") {
|
|
1253
|
+
const toolIndex = findAgentChildToolIndex(childMessages, chunk.payload.toolCallId, chunk.payload.toolName);
|
|
1254
|
+
if (toolIndex === -1) return childMessages;
|
|
1255
|
+
const currentMessage = childMessages[toolIndex];
|
|
1256
|
+
if (currentMessage?.type !== "tool") return childMessages;
|
|
1257
|
+
const result = chunk.payload.result;
|
|
1258
|
+
const nextMessages = [...childMessages];
|
|
1259
|
+
nextMessages[toolIndex] = {
|
|
1260
|
+
...currentMessage,
|
|
1261
|
+
toolOutput: chunk.payload.toolName?.startsWith("workflow-") ? {
|
|
1262
|
+
...result?.result ?? {},
|
|
1263
|
+
runId: result?.runId
|
|
1264
|
+
} : chunk.payload.result
|
|
1264
1265
|
};
|
|
1266
|
+
return nextMessages;
|
|
1265
1267
|
}
|
|
1266
|
-
return
|
|
1268
|
+
return childMessages;
|
|
1269
|
+
};
|
|
1270
|
+
const routeAgentChunk = (chunk, childMessages, boundaries) => {
|
|
1271
|
+
const [boundary, ...remaining] = boundaries;
|
|
1272
|
+
if (!boundary) return accumulateAgentChildMessages(chunk, childMessages);
|
|
1273
|
+
let toolIndex = findAgentChildToolIndex(childMessages, boundary.toolCallId, boundary.toolName);
|
|
1274
|
+
let nextMessages = childMessages;
|
|
1275
|
+
if (toolIndex === -1) {
|
|
1276
|
+
toolIndex = childMessages.length;
|
|
1277
|
+
nextMessages = [...childMessages, {
|
|
1278
|
+
type: "tool",
|
|
1279
|
+
toolCallId: boundary.toolCallId,
|
|
1280
|
+
toolName: boundary.toolName,
|
|
1281
|
+
args: {}
|
|
1282
|
+
}];
|
|
1283
|
+
}
|
|
1284
|
+
const currentMessage = nextMessages[toolIndex];
|
|
1285
|
+
if (currentMessage?.type !== "tool" || !currentMessage.toolName.startsWith("agent-")) return childMessages;
|
|
1286
|
+
const currentOutput = currentMessage.toolOutput !== null && typeof currentMessage.toolOutput === "object" ? currentMessage.toolOutput : {};
|
|
1287
|
+
const nestedMessages = Array.isArray(currentOutput.childMessages) ? currentOutput.childMessages : [];
|
|
1288
|
+
const updatedNestedMessages = routeAgentChunk(chunk, nestedMessages, remaining);
|
|
1289
|
+
if (updatedNestedMessages === nestedMessages) return childMessages;
|
|
1290
|
+
const updatedMessages = [...nextMessages];
|
|
1291
|
+
updatedMessages[toolIndex] = {
|
|
1292
|
+
...currentMessage,
|
|
1293
|
+
toolOutput: {
|
|
1294
|
+
...currentOutput,
|
|
1295
|
+
childMessages: updatedNestedMessages
|
|
1296
|
+
}
|
|
1297
|
+
};
|
|
1298
|
+
return updatedMessages;
|
|
1299
|
+
};
|
|
1300
|
+
const accumulateAgentChunk = (chunk, conversation, _metadata, parentToolCallId, parentToolName, boundaries = []) => {
|
|
1301
|
+
if (!parentToolCallId) return conversation;
|
|
1302
|
+
const location = locateToolPart(conversation, parentToolCallId, false);
|
|
1303
|
+
if (!location) return conversation;
|
|
1304
|
+
const targetMessage = conversation[location.messageIndex];
|
|
1305
|
+
if (!targetMessage || targetMessage.role !== "assistant") return conversation;
|
|
1306
|
+
const parts = [...targetMessage.content.parts];
|
|
1307
|
+
const toolPart = parts[location.toolPartIndex];
|
|
1308
|
+
if (!toolPart || !isToolPart(toolPart)) return conversation;
|
|
1309
|
+
if (parentToolName && toolPart.toolInvocation.toolName !== parentToolName) return conversation;
|
|
1310
|
+
const invocationResult = "result" in toolPart.toolInvocation && toolPart.toolInvocation.result !== null ? toolPart.toolInvocation.result : void 0;
|
|
1311
|
+
const existingResult = invocationResult && typeof invocationResult === "object" ? invocationResult : {};
|
|
1312
|
+
const childMessages = Array.isArray(existingResult.childMessages) ? existingResult.childMessages : [];
|
|
1313
|
+
const updatedChildMessages = routeAgentChunk(chunk, childMessages, boundaries);
|
|
1314
|
+
if (updatedChildMessages === childMessages) return conversation;
|
|
1315
|
+
parts[location.toolPartIndex] = {
|
|
1316
|
+
...toolPart,
|
|
1317
|
+
toolInvocation: {
|
|
1318
|
+
...toolPart.toolInvocation,
|
|
1319
|
+
state: "partial-call",
|
|
1320
|
+
result: {
|
|
1321
|
+
...existingResult,
|
|
1322
|
+
childMessages: updatedChildMessages
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
};
|
|
1326
|
+
return replaceAt(conversation, location.messageIndex, withParts(targetMessage, parts));
|
|
1267
1327
|
};
|
|
1268
1328
|
const networkMode = (metadata) => ({
|
|
1269
1329
|
...metadata,
|
|
@@ -2816,275 +2876,133 @@ function useMutation(mutationFn) {
|
|
|
2816
2876
|
}
|
|
2817
2877
|
//#endregion
|
|
2818
2878
|
//#region src/workflows/use-stream-workflow.ts
|
|
2819
|
-
/**
|
|
2820
|
-
* Hook for streaming workflow execution with support for observing, resuming, and time-travel.
|
|
2821
|
-
*
|
|
2822
|
-
* @example
|
|
2823
|
-
* ```tsx
|
|
2824
|
-
* const {
|
|
2825
|
-
* streamWorkflow,
|
|
2826
|
-
* streamResult,
|
|
2827
|
-
* isStreaming,
|
|
2828
|
-
* observeWorkflowStream,
|
|
2829
|
-
* closeStreamsAndReset,
|
|
2830
|
-
* resumeWorkflowStream,
|
|
2831
|
-
* timeTravelWorkflowStream,
|
|
2832
|
-
* } = useStreamWorkflow({
|
|
2833
|
-
* debugMode: true,
|
|
2834
|
-
* tracingOptions: { enabled: true },
|
|
2835
|
-
* onError: (error, defaultMessage) => console.error(defaultMessage, error),
|
|
2836
|
-
* });
|
|
2837
|
-
*
|
|
2838
|
-
* // Start streaming a workflow
|
|
2839
|
-
* await streamWorkflow.mutateAsync({
|
|
2840
|
-
* workflowId: 'my-workflow',
|
|
2841
|
-
* runId: 'run-123',
|
|
2842
|
-
* inputData: { key: 'value' },
|
|
2843
|
-
* requestContext: {},
|
|
2844
|
-
* });
|
|
2845
|
-
* ```
|
|
2846
|
-
*/
|
|
2847
2879
|
function useStreamWorkflow({ debugMode, tracingOptions, onError }) {
|
|
2848
2880
|
const client = useMastraClient();
|
|
2849
|
-
const [streamResult, setStreamResult] = useState(
|
|
2881
|
+
const [streamResult, setStreamResult] = useState();
|
|
2850
2882
|
const [isStreaming, setIsStreaming] = useState(false);
|
|
2851
|
-
const
|
|
2852
|
-
const observerRef = useRef(null);
|
|
2853
|
-
const resumeStreamRef = useRef(null);
|
|
2854
|
-
const timeTravelStreamRef = useRef(null);
|
|
2883
|
+
const activeStream = useRef(void 0);
|
|
2855
2884
|
const isMountedRef = useRef(true);
|
|
2885
|
+
const closeActiveStream = useCallback(() => {
|
|
2886
|
+
const operation = activeStream.current;
|
|
2887
|
+
activeStream.current = void 0;
|
|
2888
|
+
if (!operation) return;
|
|
2889
|
+
operation.controller.abort();
|
|
2890
|
+
operation.reader?.cancel().catch(() => void 0);
|
|
2891
|
+
operation.reader?.releaseLock();
|
|
2892
|
+
operation.reader = void 0;
|
|
2893
|
+
}, []);
|
|
2856
2894
|
useEffect(() => {
|
|
2857
2895
|
isMountedRef.current = true;
|
|
2858
2896
|
return () => {
|
|
2859
2897
|
isMountedRef.current = false;
|
|
2860
|
-
|
|
2861
|
-
try {
|
|
2862
|
-
readerRef.current.releaseLock();
|
|
2863
|
-
} catch {}
|
|
2864
|
-
readerRef.current = null;
|
|
2865
|
-
}
|
|
2866
|
-
if (observerRef.current) {
|
|
2867
|
-
try {
|
|
2868
|
-
observerRef.current.releaseLock();
|
|
2869
|
-
} catch {}
|
|
2870
|
-
observerRef.current = null;
|
|
2871
|
-
}
|
|
2872
|
-
if (resumeStreamRef.current) {
|
|
2873
|
-
try {
|
|
2874
|
-
resumeStreamRef.current.releaseLock();
|
|
2875
|
-
} catch {}
|
|
2876
|
-
resumeStreamRef.current = null;
|
|
2877
|
-
}
|
|
2878
|
-
if (timeTravelStreamRef.current) {
|
|
2879
|
-
try {
|
|
2880
|
-
timeTravelStreamRef.current.releaseLock();
|
|
2881
|
-
} catch {}
|
|
2882
|
-
timeTravelStreamRef.current = null;
|
|
2883
|
-
}
|
|
2898
|
+
closeActiveStream();
|
|
2884
2899
|
};
|
|
2885
|
-
}, []);
|
|
2886
|
-
|
|
2887
|
-
if (err instanceof TypeError) return;
|
|
2888
|
-
const error = err instanceof Error ? err : new Error(defaultMessage);
|
|
2889
|
-
onError?.(error, defaultMessage);
|
|
2890
|
-
setStreamingState?.(false);
|
|
2891
|
-
}, [onError]);
|
|
2892
|
-
const handleWorkflowFinish = useCallback((value) => {
|
|
2893
|
-
if (value.type === "workflow-finish") {
|
|
2894
|
-
const streamStatus = value.payload?.workflowStatus;
|
|
2895
|
-
const metadata = value.payload?.metadata;
|
|
2896
|
-
setStreamResult((prev) => ({
|
|
2897
|
-
...prev,
|
|
2898
|
-
status: streamStatus
|
|
2899
|
-
}));
|
|
2900
|
-
if (streamStatus === "failed") throw new Error(metadata?.errorMessage || "Workflow execution failed");
|
|
2901
|
-
}
|
|
2902
|
-
}, []);
|
|
2903
|
-
const streamWorkflow = useMutation(async ({ workflowId, runId, inputData, initialState, requestContext: playgroundRequestContext, perStep }) => {
|
|
2904
|
-
if (readerRef.current) readerRef.current.releaseLock();
|
|
2900
|
+
}, [closeActiveStream]);
|
|
2901
|
+
async function consumeStream(openStream, defaultMessage) {
|
|
2905
2902
|
if (!isMountedRef.current) return;
|
|
2903
|
+
closeActiveStream();
|
|
2904
|
+
const operation = { controller: new AbortController() };
|
|
2905
|
+
activeStream.current = operation;
|
|
2906
|
+
const { signal } = operation.controller;
|
|
2906
2907
|
setIsStreaming(true);
|
|
2907
|
-
setStreamResult({ input: inputData });
|
|
2908
|
-
const stream = await (await client.getWorkflow(workflowId).createRun({ runId })).stream({
|
|
2909
|
-
inputData,
|
|
2910
|
-
initialState,
|
|
2911
|
-
requestContext: playgroundRequestContext,
|
|
2912
|
-
closeOnSuspend: true,
|
|
2913
|
-
tracingOptions,
|
|
2914
|
-
perStep: perStep ?? debugMode
|
|
2915
|
-
});
|
|
2916
|
-
if (!stream) return handleStreamError(/* @__PURE__ */ new Error("No stream returned"), "No stream returned", setIsStreaming);
|
|
2917
|
-
const reader = stream.getReader();
|
|
2918
|
-
readerRef.current = reader;
|
|
2919
2908
|
try {
|
|
2920
|
-
|
|
2921
|
-
|
|
2909
|
+
const stream = await openStream(signal);
|
|
2910
|
+
if (signal.aborted) {
|
|
2911
|
+
await stream?.cancel();
|
|
2912
|
+
return;
|
|
2913
|
+
}
|
|
2914
|
+
if (!stream) {
|
|
2915
|
+
onError?.(/* @__PURE__ */ new Error("No stream returned"), "No stream returned");
|
|
2916
|
+
return;
|
|
2917
|
+
}
|
|
2918
|
+
const reader = stream.getReader();
|
|
2919
|
+
operation.reader = reader;
|
|
2920
|
+
while (!signal.aborted) {
|
|
2922
2921
|
const { done, value } = await reader.read();
|
|
2923
|
-
if (done) break;
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2922
|
+
if (done || signal.aborted) break;
|
|
2923
|
+
setStreamResult((previous) => mapWorkflowStreamChunkToWatchResult(previous, value));
|
|
2924
|
+
if (value.type === "workflow-step-start") setIsStreaming(true);
|
|
2925
|
+
if (value.type === "workflow-step-suspended") setIsStreaming(false);
|
|
2926
|
+
if (value.type === "workflow-finish" && value.payload.workflowStatus === "failed") throw new Error(value.payload.metadata?.errorMessage || "Workflow execution failed");
|
|
2927
|
+
}
|
|
2928
|
+
} catch (error) {
|
|
2929
|
+
if (!signal.aborted) {
|
|
2930
|
+
if (!operation.reader) throw error;
|
|
2931
|
+
onError?.(error instanceof Error ? error : new Error(defaultMessage), defaultMessage);
|
|
2932
2932
|
}
|
|
2933
|
-
} catch (err) {
|
|
2934
|
-
handleStreamError(err, "Error streaming workflow");
|
|
2935
2933
|
} finally {
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2934
|
+
operation.reader?.releaseLock();
|
|
2935
|
+
operation.reader = void 0;
|
|
2936
|
+
if (activeStream.current === operation) {
|
|
2937
|
+
activeStream.current = void 0;
|
|
2938
|
+
setIsStreaming(false);
|
|
2940
2939
|
}
|
|
2941
2940
|
}
|
|
2941
|
+
}
|
|
2942
|
+
const streamWorkflow = useMutation(({ workflowId, runId, inputData, initialState, requestContext, perStep }) => {
|
|
2943
|
+
setStreamResult({
|
|
2944
|
+
status: "pending",
|
|
2945
|
+
input: inputData,
|
|
2946
|
+
steps: {}
|
|
2947
|
+
});
|
|
2948
|
+
return consumeStream(async (signal) => {
|
|
2949
|
+
const run = await client.getWorkflow(workflowId).createRun({ runId });
|
|
2950
|
+
if (signal.aborted) return;
|
|
2951
|
+
return run.stream({
|
|
2952
|
+
inputData,
|
|
2953
|
+
initialState,
|
|
2954
|
+
requestContext,
|
|
2955
|
+
closeOnSuspend: true,
|
|
2956
|
+
tracingOptions,
|
|
2957
|
+
perStep: perStep ?? debugMode
|
|
2958
|
+
});
|
|
2959
|
+
}, "Error streaming workflow");
|
|
2942
2960
|
});
|
|
2943
2961
|
const observeWorkflowStream = useMutation(async ({ workflowId, runId, storeRunResult }) => {
|
|
2944
|
-
if (observerRef.current) observerRef.current.releaseLock();
|
|
2945
2962
|
if (!isMountedRef.current) return;
|
|
2946
|
-
|
|
2947
|
-
setStreamResult(storeRunResult || {});
|
|
2963
|
+
setStreamResult(storeRunResult ?? void 0);
|
|
2948
2964
|
if (storeRunResult?.status === "suspended") {
|
|
2965
|
+
closeActiveStream();
|
|
2949
2966
|
setIsStreaming(false);
|
|
2950
2967
|
return;
|
|
2951
2968
|
}
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
while (true) {
|
|
2958
|
-
if (!isMountedRef.current) break;
|
|
2959
|
-
const { done, value } = await reader.read();
|
|
2960
|
-
if (done) break;
|
|
2961
|
-
if (isMountedRef.current) {
|
|
2962
|
-
setStreamResult((prev) => {
|
|
2963
|
-
return mapWorkflowStreamChunkToWatchResult(prev, value);
|
|
2964
|
-
});
|
|
2965
|
-
if (value.type === "workflow-step-start") setIsStreaming(true);
|
|
2966
|
-
if (value.type === "workflow-step-suspended") setIsStreaming(false);
|
|
2967
|
-
if (value.type === "workflow-finish") handleWorkflowFinish(value);
|
|
2968
|
-
}
|
|
2969
|
-
}
|
|
2970
|
-
} catch (err) {
|
|
2971
|
-
handleStreamError(err, "Error observing workflow");
|
|
2972
|
-
} finally {
|
|
2973
|
-
if (isMountedRef.current) setIsStreaming(false);
|
|
2974
|
-
if (observerRef.current) {
|
|
2975
|
-
observerRef.current.releaseLock();
|
|
2976
|
-
observerRef.current = null;
|
|
2977
|
-
}
|
|
2978
|
-
}
|
|
2969
|
+
await consumeStream(async (signal) => {
|
|
2970
|
+
const run = await client.getWorkflow(workflowId).createRun({ runId });
|
|
2971
|
+
if (signal.aborted) return;
|
|
2972
|
+
return run.observeStream();
|
|
2973
|
+
}, "Error observing workflow");
|
|
2979
2974
|
});
|
|
2980
|
-
const resumeWorkflowStream = useMutation(
|
|
2981
|
-
|
|
2982
|
-
if (
|
|
2983
|
-
|
|
2984
|
-
const stream = await (await client.getWorkflow(workflowId).createRun({ runId })).resumeStream({
|
|
2975
|
+
const resumeWorkflowStream = useMutation(({ workflowId, runId, step, resumeData, requestContext, perStep }) => consumeStream(async (signal) => {
|
|
2976
|
+
const run = await client.getWorkflow(workflowId).createRun({ runId });
|
|
2977
|
+
if (signal.aborted) return;
|
|
2978
|
+
return run.resumeStream({
|
|
2985
2979
|
step,
|
|
2986
2980
|
resumeData,
|
|
2987
|
-
requestContext
|
|
2981
|
+
requestContext,
|
|
2988
2982
|
tracingOptions,
|
|
2989
2983
|
perStep: perStep ?? debugMode
|
|
2990
2984
|
});
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
if (!isMountedRef.current) break;
|
|
2997
|
-
const { done, value } = await reader.read();
|
|
2998
|
-
if (done) break;
|
|
2999
|
-
if (isMountedRef.current) {
|
|
3000
|
-
setStreamResult((prev) => {
|
|
3001
|
-
return mapWorkflowStreamChunkToWatchResult(prev, value);
|
|
3002
|
-
});
|
|
3003
|
-
if (value.type === "workflow-step-start") setIsStreaming(true);
|
|
3004
|
-
if (value.type === "workflow-step-suspended") setIsStreaming(false);
|
|
3005
|
-
if (value.type === "workflow-finish") handleWorkflowFinish(value);
|
|
3006
|
-
}
|
|
3007
|
-
}
|
|
3008
|
-
} catch (err) {
|
|
3009
|
-
handleStreamError(err, "Error resuming workflow stream");
|
|
3010
|
-
} finally {
|
|
3011
|
-
if (isMountedRef.current) setIsStreaming(false);
|
|
3012
|
-
if (resumeStreamRef.current) {
|
|
3013
|
-
resumeStreamRef.current.releaseLock();
|
|
3014
|
-
resumeStreamRef.current = null;
|
|
3015
|
-
}
|
|
3016
|
-
}
|
|
3017
|
-
});
|
|
3018
|
-
const timeTravelWorkflowStream = useMutation(async ({ workflowId, requestContext: playgroundRequestContext, runId, perStep, ...params }) => {
|
|
3019
|
-
if (timeTravelStreamRef.current) timeTravelStreamRef.current.releaseLock();
|
|
3020
|
-
if (!isMountedRef.current) return;
|
|
3021
|
-
setIsStreaming(true);
|
|
3022
|
-
const stream = await (await client.getWorkflow(workflowId).createRun({ runId })).timeTravelStream({
|
|
2985
|
+
}, "Error resuming workflow stream"));
|
|
2986
|
+
const timeTravelWorkflowStream = useMutation(({ workflowId, requestContext, runId, perStep, ...params }) => consumeStream(async (signal) => {
|
|
2987
|
+
const run = await client.getWorkflow(workflowId).createRun({ runId });
|
|
2988
|
+
if (signal.aborted) return;
|
|
2989
|
+
return run.timeTravelStream({
|
|
3023
2990
|
...params,
|
|
3024
2991
|
perStep: perStep ?? debugMode,
|
|
3025
|
-
requestContext
|
|
2992
|
+
requestContext,
|
|
3026
2993
|
tracingOptions
|
|
3027
2994
|
});
|
|
3028
|
-
|
|
3029
|
-
const reader = stream.getReader();
|
|
3030
|
-
timeTravelStreamRef.current = reader;
|
|
3031
|
-
try {
|
|
3032
|
-
while (true) {
|
|
3033
|
-
if (!isMountedRef.current) break;
|
|
3034
|
-
const { done, value } = await reader.read();
|
|
3035
|
-
if (done) break;
|
|
3036
|
-
if (isMountedRef.current) {
|
|
3037
|
-
setStreamResult((prev) => {
|
|
3038
|
-
return mapWorkflowStreamChunkToWatchResult(prev, value);
|
|
3039
|
-
});
|
|
3040
|
-
if (value.type === "workflow-step-start") setIsStreaming(true);
|
|
3041
|
-
if (value.type === "workflow-step-suspended") setIsStreaming(false);
|
|
3042
|
-
if (value.type === "workflow-finish") handleWorkflowFinish(value);
|
|
3043
|
-
}
|
|
3044
|
-
}
|
|
3045
|
-
} catch (err) {
|
|
3046
|
-
handleStreamError(err, "Error time traveling workflow stream");
|
|
3047
|
-
} finally {
|
|
3048
|
-
if (isMountedRef.current) setIsStreaming(false);
|
|
3049
|
-
if (timeTravelStreamRef.current) {
|
|
3050
|
-
timeTravelStreamRef.current.releaseLock();
|
|
3051
|
-
timeTravelStreamRef.current = null;
|
|
3052
|
-
}
|
|
3053
|
-
}
|
|
3054
|
-
});
|
|
2995
|
+
}, "Error time traveling workflow stream"));
|
|
3055
2996
|
return {
|
|
3056
2997
|
streamWorkflow,
|
|
3057
2998
|
streamResult,
|
|
3058
2999
|
isStreaming,
|
|
3059
3000
|
observeWorkflowStream,
|
|
3060
3001
|
closeStreamsAndReset: useCallback(() => {
|
|
3002
|
+
closeActiveStream();
|
|
3061
3003
|
setIsStreaming(false);
|
|
3062
|
-
setStreamResult(
|
|
3063
|
-
|
|
3064
|
-
try {
|
|
3065
|
-
readerRef.current.releaseLock();
|
|
3066
|
-
} catch {}
|
|
3067
|
-
readerRef.current = null;
|
|
3068
|
-
}
|
|
3069
|
-
if (observerRef.current) {
|
|
3070
|
-
try {
|
|
3071
|
-
observerRef.current.releaseLock();
|
|
3072
|
-
} catch {}
|
|
3073
|
-
observerRef.current = null;
|
|
3074
|
-
}
|
|
3075
|
-
if (resumeStreamRef.current) {
|
|
3076
|
-
try {
|
|
3077
|
-
resumeStreamRef.current.releaseLock();
|
|
3078
|
-
} catch {}
|
|
3079
|
-
resumeStreamRef.current = null;
|
|
3080
|
-
}
|
|
3081
|
-
if (timeTravelStreamRef.current) {
|
|
3082
|
-
try {
|
|
3083
|
-
timeTravelStreamRef.current.releaseLock();
|
|
3084
|
-
} catch {}
|
|
3085
|
-
timeTravelStreamRef.current = null;
|
|
3086
|
-
}
|
|
3087
|
-
}, []),
|
|
3004
|
+
setStreamResult(void 0);
|
|
3005
|
+
}, [closeActiveStream]),
|
|
3088
3006
|
resumeWorkflowStream,
|
|
3089
3007
|
timeTravelWorkflowStream
|
|
3090
3008
|
};
|
|
@@ -3421,6 +3339,6 @@ const useMastraSpeechToText = ({ agent, language }) => {
|
|
|
3421
3339
|
};
|
|
3422
3340
|
};
|
|
3423
3341
|
//#endregion
|
|
3424
|
-
export {
|
|
3342
|
+
export { CLIENT_MESSAGE_ID_KEY, MastraReactProvider, WorkflowStepFactory, accumulateChunk, accumulateNetworkChunk, finishStreamingAssistantMessage, fromCoreUserMessageToMastraDBMessage, fromCoreUserMessagesToMastraDBMessage, mapWorkflowStreamChunkToWatchResult, playStreamWithWebAudio, recordMicrophoneToFile, useCancelWorkflowRun, useChat, useCreateWorkflowRun, useMastraClient, useSpeechRecognition, useStreamWorkflow };
|
|
3425
3343
|
|
|
3426
3344
|
//# sourceMappingURL=index.js.map
|