@mastra/react 1.6.0-alpha.8 → 1.6.0

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 CHANGED
@@ -140,6 +140,37 @@ function toolErrorText(error) {
140
140
  }
141
141
  return String(error);
142
142
  }
143
+ /**
144
+ * Agent-as-tool boundaries wrap progressive chunks in nested `tool-output`
145
+ * envelopes. Peel only agent boundaries; workflow/tool envelopes remain the
146
+ * leaf so existing child-message accumulation can process them normally.
147
+ */
148
+ const normalizeNestedAgentOutput = (output) => {
149
+ const boundaries = [];
150
+ const seen = /* @__PURE__ */ new Set();
151
+ let current = output;
152
+ while (current !== null && typeof current === "object") {
153
+ if (seen.has(current)) return void 0;
154
+ seen.add(current);
155
+ const chunk = current;
156
+ if (chunk.type !== "tool-output") return {
157
+ leaf: current,
158
+ boundaries
159
+ };
160
+ const toolCallId = chunk.payload?.toolCallId;
161
+ const toolName = chunk.payload?.toolName;
162
+ if (typeof toolName !== "string" || !toolName.startsWith("agent-")) return {
163
+ leaf: current,
164
+ boundaries
165
+ };
166
+ if (typeof toolCallId !== "string" || !("output" in (chunk.payload ?? {}))) return void 0;
167
+ boundaries.push({
168
+ toolCallId,
169
+ toolName
170
+ });
171
+ current = chunk.payload?.output;
172
+ }
173
+ };
143
174
  const cloneMetadata = (metadata) => metadata ? { ...metadata } : {};
144
175
  const withParts = (message, parts) => ({
145
176
  ...message,
@@ -837,7 +868,7 @@ const accumulateChunk = ({ chunk, conversation, metadata }) => {
837
868
  toolName,
838
869
  args,
839
870
  errorText,
840
- ...toolName?.startsWith("agent-") ? { result: toolPart.toolInvocation.result } : {}
871
+ ...chunk.from === "AGENT" ? { result: toolPart.toolInvocation.result } : {}
841
872
  }
842
873
  };
843
874
  } else {
@@ -859,7 +890,7 @@ const accumulateChunk = ({ chunk, conversation, metadata }) => {
859
890
  };
860
891
  else output = payloadResult;
861
892
  } else if (isAgent) {
862
- const existingOutput = toolPart.toolInvocation.state === "result" ? toolPart.toolInvocation.result : void 0;
893
+ const existingOutput = toolPart.toolInvocation.state === "partial-call" || toolPart.toolInvocation.state === "result" ? toolPart.toolInvocation.result : void 0;
863
894
  const existingChild = existingOutput?.childMessages;
864
895
  output = existingOutput ? {
865
896
  ...payloadResult,
@@ -936,8 +967,13 @@ const accumulateChunk = ({ chunk, conversation, metadata }) => {
936
967
  result: updated
937
968
  }
938
969
  };
939
- } else if (payloadOutput?.from === "AGENT" || payloadOutput?.from === "USER" && payloadOutput?.payload?.output?.type?.startsWith("workflow-")) return accumulateAgentChunk(payloadOutput, result, metadata, toolCallId, toolName);
940
- else {
970
+ } else if (toolName.startsWith("agent-") || payloadOutput?.from === "AGENT") {
971
+ const normalized = normalizeNestedAgentOutput(payloadOutput);
972
+ if (!normalized) return result;
973
+ const { leaf, boundaries } = normalized;
974
+ if (leaf.from === "AGENT" || leaf.type === "tool-output" && leaf.payload?.output?.type?.startsWith("workflow-")) return accumulateAgentChunk(leaf, result, metadata, toolCallId, toolName, boundaries);
975
+ return result;
976
+ } else {
941
977
  const currentResult = toolPart.toolInvocation.result;
942
978
  const existing = Array.isArray(currentResult) ? currentResult : [];
943
979
  parts[toolPartIndex] = {
@@ -1165,112 +1201,130 @@ const accumulateChunk = ({ chunk, conversation, metadata }) => {
1165
1201
  * that isn't enumerated above.
1166
1202
  */
1167
1203
  const assertExhaustive = (_chunk, fallback) => fallback;
1168
- const accumulateAgentChunk = (chunk, conversation, _metadata, parentToolCallId, parentToolName) => {
1169
- const lastMessage = conversation[conversation.length - 1];
1170
- if (!lastMessage || lastMessage.role !== "assistant") return conversation;
1171
- const parts = [...lastMessage.content.parts];
1172
- const findToolPartIndex = () => parts.findIndex((part) => isToolPart(part) && (parentToolCallId && part.toolInvocation.toolCallId === parentToolCallId || parentToolName && part.toolInvocation.toolName === parentToolName));
1204
+ const findAgentChildToolIndex = (childMessages, toolCallId, toolName) => {
1205
+ for (let index = childMessages.length - 1; index >= 0; index--) {
1206
+ const message = childMessages[index];
1207
+ if (message?.type !== "tool") continue;
1208
+ if (toolCallId ? message.toolCallId === toolCallId : toolName && message.toolName === toolName) return index;
1209
+ }
1210
+ return -1;
1211
+ };
1212
+ const accumulateAgentChildMessages = (chunk, childMessages) => {
1173
1213
  if (chunk.type === "text-delta") {
1174
- const agentChunk = chunk.payload;
1175
- const toolPartIndex = findToolPartIndex();
1176
- if (toolPartIndex === -1) return conversation;
1177
- const toolPart = parts[toolPartIndex];
1178
- const existingResult = toolPart.toolInvocation.result || {};
1179
- const childMessages = existingResult.childMessages || [];
1214
+ const text = chunk.payload.text;
1180
1215
  const lastChildMessage = childMessages[childMessages.length - 1];
1181
1216
  const textMessage = {
1182
1217
  type: "text",
1183
- content: (lastChildMessage?.content || "") + agentChunk.text
1218
+ content: (lastChildMessage?.type === "text" ? lastChildMessage.content : "") + text
1184
1219
  };
1185
- const nextChildren = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
1186
- parts[toolPartIndex] = {
1187
- ...toolPart,
1188
- toolInvocation: {
1189
- ...toolPart.toolInvocation,
1190
- result: {
1191
- ...existingResult,
1192
- childMessages: nextChildren
1193
- }
1194
- }
1220
+ return lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
1221
+ }
1222
+ if (chunk.type === "tool-call") {
1223
+ const existingIndex = findAgentChildToolIndex(childMessages, chunk.payload.toolCallId);
1224
+ const toolMessage = {
1225
+ ...existingIndex === -1 ? {} : childMessages[existingIndex],
1226
+ type: "tool",
1227
+ toolCallId: chunk.payload.toolCallId,
1228
+ toolName: chunk.payload.toolName,
1229
+ args: chunk.payload.args
1195
1230
  };
1196
- } else if (chunk.type === "tool-call") {
1197
- const agentChunk = chunk.payload;
1198
- const toolPartIndex = findToolPartIndex();
1199
- if (toolPartIndex === -1) return conversation;
1200
- const toolPart = parts[toolPartIndex];
1201
- const existingResult = toolPart.toolInvocation.result || {};
1202
- const childMessages = existingResult.childMessages || [];
1203
- parts[toolPartIndex] = {
1204
- ...toolPart,
1205
- toolInvocation: {
1206
- ...toolPart.toolInvocation,
1207
- result: {
1208
- ...existingResult,
1209
- childMessages: [...childMessages, {
1210
- type: "tool",
1211
- toolCallId: agentChunk.toolCallId,
1212
- toolName: agentChunk.toolName,
1213
- args: agentChunk.args
1214
- }]
1215
- }
1231
+ if (existingIndex === -1) return [...childMessages, toolMessage];
1232
+ const nextMessages = [...childMessages];
1233
+ nextMessages[existingIndex] = toolMessage;
1234
+ return nextMessages;
1235
+ }
1236
+ if (chunk.type === "tool-output" && chunk.payload.output?.type?.startsWith("workflow-")) {
1237
+ const toolIndex = findAgentChildToolIndex(childMessages, chunk.payload.toolCallId, chunk.payload.toolName);
1238
+ if (toolIndex === -1) return childMessages;
1239
+ const currentMessage = childMessages[toolIndex];
1240
+ if (currentMessage?.type !== "tool") return childMessages;
1241
+ const existingWorkflowState = currentMessage.toolOutput && typeof currentMessage.toolOutput === "object" ? currentMessage.toolOutput : {};
1242
+ const updated = mapWorkflowStreamChunkToWatchResult(existingWorkflowState, chunk.payload.output);
1243
+ const nextMessages = [...childMessages];
1244
+ nextMessages[toolIndex] = {
1245
+ ...currentMessage,
1246
+ toolOutput: {
1247
+ ...updated,
1248
+ runId: chunk.payload.output.runId
1216
1249
  }
1217
1250
  };
1218
- } else if (chunk.type === "tool-output") {
1219
- const agentChunk = chunk.payload;
1220
- const toolPartIndex = findToolPartIndex();
1221
- if (toolPartIndex === -1) return conversation;
1222
- const toolPart = parts[toolPartIndex];
1223
- if (agentChunk?.output?.type?.startsWith("workflow-")) {
1224
- const existingResult = toolPart.toolInvocation.result || {};
1225
- const childMessages = existingResult.childMessages || [];
1226
- const lastIndex = childMessages.length - 1;
1227
- const currentMessage = childMessages[lastIndex];
1228
- const actualExistingWorkflowState = currentMessage?.toolOutput || {};
1229
- const updated = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
1230
- if (lastIndex >= 0 && childMessages[lastIndex]?.type === "tool") parts[toolPartIndex] = {
1231
- ...toolPart,
1232
- toolInvocation: {
1233
- ...toolPart.toolInvocation,
1234
- result: {
1235
- ...existingResult,
1236
- childMessages: [...childMessages.slice(0, -1), {
1237
- ...currentMessage,
1238
- toolOutput: {
1239
- ...updated,
1240
- runId: agentChunk.output.runId
1241
- }
1242
- }]
1243
- }
1244
- }
1245
- };
1246
- }
1247
- } else if (chunk.type === "tool-result") {
1248
- const agentChunk = chunk.payload;
1249
- const toolPartIndex = findToolPartIndex();
1250
- if (toolPartIndex === -1) return conversation;
1251
- const toolPart = parts[toolPartIndex];
1252
- const existingResult = toolPart.toolInvocation.result || {};
1253
- const childMessages = existingResult.childMessages || [];
1254
- const lastIndex = childMessages.length - 1;
1255
- const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
1256
- if (lastIndex >= 0 && childMessages[lastIndex]?.type === "tool") parts[toolPartIndex] = {
1257
- ...toolPart,
1258
- toolInvocation: {
1259
- ...toolPart.toolInvocation,
1260
- result: {
1261
- ...existingResult,
1262
- childMessages: [...childMessages.slice(0, -1), {
1263
- ...childMessages[lastIndex],
1264
- toolOutput: isWorkflow ? {
1265
- ...agentChunk.result?.result,
1266
- runId: agentChunk.result?.runId
1267
- } : agentChunk.result
1268
- }]
1269
- }
1270
- }
1251
+ return nextMessages;
1252
+ }
1253
+ if (chunk.type === "tool-result") {
1254
+ const toolIndex = findAgentChildToolIndex(childMessages, chunk.payload.toolCallId, chunk.payload.toolName);
1255
+ if (toolIndex === -1) return childMessages;
1256
+ const currentMessage = childMessages[toolIndex];
1257
+ if (currentMessage?.type !== "tool") return childMessages;
1258
+ const result = chunk.payload.result;
1259
+ const nextMessages = [...childMessages];
1260
+ nextMessages[toolIndex] = {
1261
+ ...currentMessage,
1262
+ toolOutput: chunk.payload.toolName?.startsWith("workflow-") ? {
1263
+ ...result?.result ?? {},
1264
+ runId: result?.runId
1265
+ } : chunk.payload.result
1271
1266
  };
1267
+ return nextMessages;
1272
1268
  }
1273
- return replaceLast(conversation, withParts(lastMessage, parts));
1269
+ return childMessages;
1270
+ };
1271
+ const routeAgentChunk = (chunk, childMessages, boundaries) => {
1272
+ const [boundary, ...remaining] = boundaries;
1273
+ if (!boundary) return accumulateAgentChildMessages(chunk, childMessages);
1274
+ let toolIndex = findAgentChildToolIndex(childMessages, boundary.toolCallId, boundary.toolName);
1275
+ let nextMessages = childMessages;
1276
+ if (toolIndex === -1) {
1277
+ toolIndex = childMessages.length;
1278
+ nextMessages = [...childMessages, {
1279
+ type: "tool",
1280
+ toolCallId: boundary.toolCallId,
1281
+ toolName: boundary.toolName,
1282
+ args: {}
1283
+ }];
1284
+ }
1285
+ const currentMessage = nextMessages[toolIndex];
1286
+ if (currentMessage?.type !== "tool" || !currentMessage.toolName.startsWith("agent-")) return childMessages;
1287
+ const currentOutput = currentMessage.toolOutput !== null && typeof currentMessage.toolOutput === "object" ? currentMessage.toolOutput : {};
1288
+ const nestedMessages = Array.isArray(currentOutput.childMessages) ? currentOutput.childMessages : [];
1289
+ const updatedNestedMessages = routeAgentChunk(chunk, nestedMessages, remaining);
1290
+ if (updatedNestedMessages === nestedMessages) return childMessages;
1291
+ const updatedMessages = [...nextMessages];
1292
+ updatedMessages[toolIndex] = {
1293
+ ...currentMessage,
1294
+ toolOutput: {
1295
+ ...currentOutput,
1296
+ childMessages: updatedNestedMessages
1297
+ }
1298
+ };
1299
+ return updatedMessages;
1300
+ };
1301
+ const accumulateAgentChunk = (chunk, conversation, _metadata, parentToolCallId, parentToolName, boundaries = []) => {
1302
+ if (!parentToolCallId) return conversation;
1303
+ const location = locateToolPart(conversation, parentToolCallId, false);
1304
+ if (!location) return conversation;
1305
+ const targetMessage = conversation[location.messageIndex];
1306
+ if (!targetMessage || targetMessage.role !== "assistant") return conversation;
1307
+ const parts = [...targetMessage.content.parts];
1308
+ const toolPart = parts[location.toolPartIndex];
1309
+ if (!toolPart || !isToolPart(toolPart)) return conversation;
1310
+ if (parentToolName && toolPart.toolInvocation.toolName !== parentToolName) return conversation;
1311
+ const invocationResult = "result" in toolPart.toolInvocation && toolPart.toolInvocation.result !== null ? toolPart.toolInvocation.result : void 0;
1312
+ const existingResult = invocationResult && typeof invocationResult === "object" ? invocationResult : {};
1313
+ const childMessages = Array.isArray(existingResult.childMessages) ? existingResult.childMessages : [];
1314
+ const updatedChildMessages = routeAgentChunk(chunk, childMessages, boundaries);
1315
+ if (updatedChildMessages === childMessages) return conversation;
1316
+ parts[location.toolPartIndex] = {
1317
+ ...toolPart,
1318
+ toolInvocation: {
1319
+ ...toolPart.toolInvocation,
1320
+ state: "partial-call",
1321
+ result: {
1322
+ ...existingResult,
1323
+ childMessages: updatedChildMessages
1324
+ }
1325
+ }
1326
+ };
1327
+ return replaceAt(conversation, location.messageIndex, withParts(targetMessage, parts));
1274
1328
  };
1275
1329
  const networkMode = (metadata) => ({
1276
1330
  ...metadata,
@@ -2886,14 +2940,17 @@ function useStreamWorkflow({ debugMode, tracingOptions, onError }) {
2886
2940
  }
2887
2941
  }
2888
2942
  }
2889
- const streamWorkflow = useMutation(({ workflowId, runId, inputData, initialState, requestContext, perStep }) => {
2943
+ const streamWorkflow = useMutation(({ workflowId, runId, inputData, initialState, requestContext, perStep, resourceId }) => {
2890
2944
  setStreamResult({
2891
2945
  status: "pending",
2892
2946
  input: inputData,
2893
2947
  steps: {}
2894
2948
  });
2895
2949
  return consumeStream(async (signal) => {
2896
- const run = await client.getWorkflow(workflowId).createRun({ runId });
2950
+ const run = await client.getWorkflow(workflowId).createRun({
2951
+ runId,
2952
+ resourceId
2953
+ });
2897
2954
  if (signal.aborted) return;
2898
2955
  return run.stream({
2899
2956
  inputData,
@@ -2901,7 +2958,8 @@ function useStreamWorkflow({ debugMode, tracingOptions, onError }) {
2901
2958
  requestContext,
2902
2959
  closeOnSuspend: true,
2903
2960
  tracingOptions,
2904
- perStep: perStep ?? debugMode
2961
+ perStep: perStep ?? debugMode,
2962
+ resourceId
2905
2963
  });
2906
2964
  }, "Error streaming workflow");
2907
2965
  });
@@ -2972,9 +3030,12 @@ function useStreamWorkflow({ debugMode, tracingOptions, onError }) {
2972
3030
  */
2973
3031
  function useCreateWorkflowRun() {
2974
3032
  const client = useMastraClient();
2975
- return useMutation(async ({ workflowId, prevRunId }) => {
3033
+ return useMutation(async ({ workflowId, prevRunId, resourceId }) => {
2976
3034
  try {
2977
- const { runId: newRunId } = await client.getWorkflow(workflowId).createRun({ runId: prevRunId });
3035
+ const { runId: newRunId } = await client.getWorkflow(workflowId).createRun({
3036
+ runId: prevRunId,
3037
+ resourceId
3038
+ });
2978
3039
  return { runId: newRunId };
2979
3040
  } catch (error) {
2980
3041
  console.error("Error creating workflow run:", error);
@@ -3156,7 +3217,8 @@ const useBrowserSpeechRecognition = ({ language = "en-US" }) => {
3156
3217
  setState((prev) => ({
3157
3218
  ...prev,
3158
3219
  isListening: true,
3159
- error: null
3220
+ error: null,
3221
+ transcript: ""
3160
3222
  }));
3161
3223
  };
3162
3224
  recognition.onresult = (event) => {
@@ -3165,9 +3227,10 @@ const useBrowserSpeechRecognition = ({ language = "en-US" }) => {
3165
3227
  const transcript = event.results[i][0].transcript;
3166
3228
  if (event.results[i].isFinal) finalTranscript += transcript + " ";
3167
3229
  }
3230
+ if (!finalTranscript) return;
3168
3231
  setState((prev) => ({
3169
3232
  ...prev,
3170
- transcript: finalTranscript
3233
+ transcript: prev.transcript + finalTranscript
3171
3234
  }));
3172
3235
  };
3173
3236
  recognition.onerror = (event) => {