@mastra/react 0.0.0-studio-deploy-20260404184540 → 0.0.0-studio-cli-20260504022012

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.js CHANGED
@@ -67,6 +67,26 @@ var MastraReactProvider = ({
67
67
  );
68
68
  };
69
69
 
70
+ // src/agent/extractRunIdFromMessages.ts
71
+ var extractRunIdFromMessages = (messages) => {
72
+ for (const message of messages) {
73
+ const metadataSources = [
74
+ message.metadata?.pendingToolApprovals,
75
+ message.metadata?.requireApprovalMetadata,
76
+ message.metadata?.suspendedTools
77
+ ];
78
+ for (const source of metadataSources) {
79
+ if (!source || typeof source !== "object") continue;
80
+ for (const suspensionData of Object.values(source)) {
81
+ if (suspensionData && typeof suspensionData === "object" && typeof suspensionData.runId === "string" && suspensionData.runId.length > 0) {
82
+ return suspensionData.runId;
83
+ }
84
+ }
85
+ }
86
+ }
87
+ return void 0;
88
+ };
89
+
70
90
  // src/lib/ai-sdk/utils/formatCompletionFeedback.ts
71
91
  var formatBaseCompletionFeedback = (result, maxIterationReached, formatScorerHeading, incompleteMessage) => {
72
92
  const lines = [];
@@ -206,30 +226,24 @@ var mapWorkflowStreamChunkToWatchResult = (prev, chunk) => {
206
226
  var toUIMessage = ({ chunk, conversation, metadata }) => {
207
227
  const result = [...conversation];
208
228
  if (chunk.type.startsWith("data-")) {
229
+ const dataPart = {
230
+ type: chunk.type,
231
+ data: "data" in chunk ? chunk.data : void 0,
232
+ ..."id" in chunk && typeof chunk.id === "string" ? { id: chunk.id } : {}
233
+ };
209
234
  const lastMessage = result[result.length - 1];
210
235
  if (!lastMessage || lastMessage.role !== "assistant") {
211
236
  const newMessage = {
212
237
  id: `data-${chunk.runId}-${Date.now()}`,
213
238
  role: "assistant",
214
- parts: [
215
- {
216
- type: chunk.type,
217
- data: "data" in chunk ? chunk.data : void 0
218
- }
219
- ],
239
+ parts: [dataPart],
220
240
  metadata
221
241
  };
222
242
  return [...result, newMessage];
223
243
  }
224
244
  const updatedMessage = {
225
245
  ...lastMessage,
226
- parts: [
227
- ...lastMessage.parts,
228
- {
229
- type: chunk.type,
230
- data: "data" in chunk ? chunk.data : void 0
231
- }
232
- ]
246
+ parts: [...lastMessage.parts, dataPart]
233
247
  };
234
248
  return [...result.slice(0, -1), updatedMessage];
235
249
  }
@@ -295,6 +309,21 @@ var toUIMessage = ({ chunk, conversation, metadata }) => {
295
309
  }
296
310
  ];
297
311
  }
312
+ case "background-task-progress": {
313
+ const lastMessage = result[result.length - 1];
314
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
315
+ return [
316
+ ...result.slice(0, -1),
317
+ {
318
+ ...lastMessage,
319
+ metadata: {
320
+ mode: metadata.mode,
321
+ ...lastMessage.metadata,
322
+ runningBackgroundTasksCount: chunk.payload.runningCount
323
+ }
324
+ }
325
+ ];
326
+ }
298
327
  case "text-delta": {
299
328
  const lastMessage = result[result.length - 1];
300
329
  if (!lastMessage || lastMessage.role !== "assistant") return result;
@@ -418,113 +447,140 @@ var toUIMessage = ({ chunk, conversation, metadata }) => {
418
447
  ];
419
448
  }
420
449
  case "tool-error":
421
- case "tool-result": {
422
- const lastMessage = result[result.length - 1];
423
- if (!lastMessage || lastMessage.role !== "assistant") return result;
424
- const parts = [...lastMessage.parts];
425
- const toolPartIndex = parts.findIndex(
426
- (part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
427
- );
428
- if (toolPartIndex !== -1) {
429
- const toolPart = parts[toolPartIndex];
430
- if (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-")) {
431
- const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
432
- const toolCallId = toolPart.toolCallId;
433
- if (chunk.type === "tool-result" && chunk.payload.isError || chunk.type === "tool-error") {
434
- const error = chunk.type === "tool-error" ? chunk.payload.error : chunk.payload.result;
435
- parts[toolPartIndex] = {
436
- type: "dynamic-tool",
437
- toolName,
438
- toolCallId,
439
- state: "output-error",
440
- input: toolPart.input,
441
- errorText: typeof error === "string" ? error : error instanceof Error ? error.message : error?.message ?? String(error),
442
- callProviderMetadata: chunk.payload.providerMetadata
443
- };
450
+ case "tool-result":
451
+ case "background-task-completed":
452
+ case "background-task-failed": {
453
+ const isBgTaskEvent = chunk.type === "background-task-completed" || chunk.type === "background-task-failed";
454
+ const location = locateToolPart(result, chunk.payload.toolCallId, isBgTaskEvent);
455
+ if (!location) return result;
456
+ const { messageIndex, toolPartIndex } = location;
457
+ const targetMessage = result[messageIndex];
458
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
459
+ const parts = [...targetMessage.parts];
460
+ const toolPart = toolPartIndex >= 0 ? parts[toolPartIndex] : void 0;
461
+ if (toolPart && (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-"))) {
462
+ const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : typeof toolPart.type === "string" && toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
463
+ const toolCallId = toolPart.toolCallId;
464
+ if ((chunk.type === "tool-result" || chunk.type === "background-task-completed") && chunk.payload.isError || chunk.type === "tool-error" || chunk.type === "background-task-failed") {
465
+ const error = chunk.type === "tool-error" || chunk.type === "background-task-failed" ? chunk.payload.error : chunk.payload.result;
466
+ parts[toolPartIndex] = {
467
+ type: "dynamic-tool",
468
+ toolName,
469
+ toolCallId,
470
+ state: "output-error",
471
+ input: toolPart.input,
472
+ errorText: typeof error === "string" ? error : error instanceof Error ? error.message : error?.message ?? String(error),
473
+ callProviderMetadata: chunk.payload.providerMetadata
474
+ };
475
+ } else {
476
+ const isWorkflow = Boolean(chunk.payload.result?.result?.steps);
477
+ const isAgent = chunk?.from === "AGENT";
478
+ let output;
479
+ if (isWorkflow) {
480
+ output = chunk.payload.result?.result;
481
+ } else if (isAgent) {
482
+ const existingOutput = parts[toolPartIndex].output;
483
+ output = existingOutput ? {
484
+ ...chunk.payload.result,
485
+ childMessages: existingOutput.childMessages?.length ? existingOutput.childMessages : chunk.payload.result?.childMessages
486
+ } : chunk.payload.result;
444
487
  } else {
445
- const isWorkflow = Boolean(chunk.payload.result?.result?.steps);
446
- const isAgent = chunk?.from === "AGENT";
447
- let output;
448
- if (isWorkflow) {
449
- output = chunk.payload.result?.result;
450
- } else if (isAgent) {
451
- const existingOutput = parts[toolPartIndex].output;
452
- output = existingOutput ? {
453
- ...chunk.payload.result,
454
- childMessages: existingOutput.childMessages?.length ? existingOutput.childMessages : chunk.payload.result?.childMessages
455
- } : chunk.payload.result;
456
- } else {
457
- output = chunk.payload.result;
458
- }
459
- parts[toolPartIndex] = {
460
- type: "dynamic-tool",
461
- toolName,
462
- toolCallId,
463
- state: "output-available",
464
- input: toolPart.input,
465
- output,
466
- callProviderMetadata: chunk.payload.providerMetadata
467
- };
488
+ output = chunk.payload.result;
468
489
  }
490
+ parts[toolPartIndex] = {
491
+ type: "dynamic-tool",
492
+ toolName,
493
+ toolCallId,
494
+ state: "output-available",
495
+ input: toolPart.input,
496
+ output,
497
+ callProviderMetadata: chunk.payload.providerMetadata
498
+ };
469
499
  }
470
500
  }
501
+ const nextMessage = {
502
+ ...targetMessage,
503
+ parts,
504
+ metadata: mergeBgTaskMetadata(targetMessage.metadata, metadata.mode, {
505
+ resetRunningCount: isBgTaskEvent,
506
+ perTaskEntry: isBgTaskEvent ? {
507
+ toolCallId: chunk.payload.toolCallId,
508
+ completedAt: chunk.payload.completedAt,
509
+ taskId: chunk.payload.taskId
510
+ } : void 0
511
+ })
512
+ };
513
+ return [...result.slice(0, messageIndex), nextMessage, ...result.slice(messageIndex + 1)];
514
+ }
515
+ case "background-task-running": {
516
+ const location = locateToolPart(result, chunk.payload.toolCallId, true);
517
+ if (!location) return result;
518
+ const { messageIndex } = location;
519
+ const targetMessage = result[messageIndex];
520
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
471
521
  return [
472
- ...result.slice(0, -1),
522
+ ...result.slice(0, messageIndex),
473
523
  {
474
- ...lastMessage,
475
- parts
476
- }
524
+ ...targetMessage,
525
+ metadata: mergeBgTaskMetadata(targetMessage.metadata, metadata.mode, {
526
+ perTaskEntry: {
527
+ toolCallId: chunk.payload.toolCallId,
528
+ startedAt: chunk.payload.startedAt,
529
+ taskId: chunk.payload.taskId
530
+ }
531
+ })
532
+ },
533
+ ...result.slice(messageIndex + 1)
477
534
  ];
478
535
  }
479
- case "tool-output": {
480
- const lastMessage = result[result.length - 1];
481
- if (!lastMessage || lastMessage.role !== "assistant") return result;
482
- const parts = [...lastMessage.parts];
483
- const toolPartIndex = parts.findIndex(
484
- (part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
485
- );
486
- if (toolPartIndex !== -1) {
487
- const toolPart = parts[toolPartIndex];
488
- if (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-")) {
489
- const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : typeof toolPart.type === "string" && toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
490
- const toolCallId = toolPart.toolCallId;
491
- const input = toolPart.input;
492
- if (chunk.payload.output?.type?.startsWith("workflow-")) {
493
- const existingWorkflowState = toolPart.output || {};
494
- const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(
495
- existingWorkflowState,
496
- chunk.payload.output
497
- );
498
- parts[toolPartIndex] = {
499
- type: "dynamic-tool",
500
- toolName,
501
- toolCallId,
502
- state: "input-streaming",
503
- input,
504
- output: updatedWorkflowState
505
- };
506
- } else if (chunk.payload.output?.from === "AGENT" || chunk.payload.output?.from === "USER" && chunk.payload.output?.payload?.output?.type?.startsWith("workflow-")) {
507
- return toUIMessageFromAgent(chunk.payload.output, conversation, metadata, toolCallId, toolName);
508
- } else {
509
- const currentOutput = toolPart.output || [];
510
- const existingOutput = Array.isArray(currentOutput) ? currentOutput : [];
511
- parts[toolPartIndex] = {
512
- type: "dynamic-tool",
513
- toolName,
514
- toolCallId,
515
- state: "input-streaming",
516
- input,
517
- output: [...existingOutput, chunk.payload.output]
518
- };
519
- }
536
+ case "tool-output":
537
+ case "background-task-output": {
538
+ const isBgTaskOutput = chunk.type === "background-task-output";
539
+ const location = locateToolPart(result, chunk.payload.toolCallId, isBgTaskOutput);
540
+ if (!location || location.toolPartIndex < 0) return result;
541
+ const { messageIndex, toolPartIndex } = location;
542
+ const targetMessage = result[messageIndex];
543
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
544
+ const parts = [...targetMessage.parts];
545
+ const toolPart = parts[toolPartIndex];
546
+ if (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-")) {
547
+ const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : typeof toolPart.type === "string" && toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
548
+ const toolCallId = toolPart.toolCallId;
549
+ const input = toolPart.input;
550
+ const payloadOutput = chunk.type === "background-task-output" ? chunk.payload.payload.payload.output : chunk.payload.output;
551
+ if (payloadOutput?.type?.startsWith("workflow-")) {
552
+ const existingWorkflowState = toolPart.output || {};
553
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(existingWorkflowState, payloadOutput);
554
+ parts[toolPartIndex] = {
555
+ type: "dynamic-tool",
556
+ toolName,
557
+ toolCallId,
558
+ state: "input-streaming",
559
+ input,
560
+ output: updatedWorkflowState
561
+ };
562
+ } else if (payloadOutput?.from === "AGENT" || payloadOutput?.from === "USER" && payloadOutput?.payload?.output?.type?.startsWith("workflow-")) {
563
+ return toUIMessageFromAgent(payloadOutput, conversation, metadata, toolCallId, toolName);
564
+ } else {
565
+ const currentOutput = toolPart.output || [];
566
+ const existingOutput = Array.isArray(currentOutput) ? currentOutput : [];
567
+ parts[toolPartIndex] = {
568
+ type: "dynamic-tool",
569
+ toolName,
570
+ toolCallId,
571
+ state: "input-streaming",
572
+ input,
573
+ output: [...existingOutput, payloadOutput]
574
+ };
520
575
  }
521
576
  }
522
577
  return [
523
- ...result.slice(0, -1),
578
+ ...result.slice(0, messageIndex),
524
579
  {
525
- ...lastMessage,
580
+ ...targetMessage,
526
581
  parts
527
- }
582
+ },
583
+ ...result.slice(messageIndex + 1)
528
584
  ];
529
585
  }
530
586
  case "is-task-complete": {
@@ -650,7 +706,8 @@ var toUIMessage = ({ chunk, conversation, metadata }) => {
650
706
  toolCallId: chunk.payload.toolCallId,
651
707
  toolName: chunk.payload.toolName,
652
708
  args: chunk.payload.args,
653
- suspendPayload: chunk.payload.suspendPayload
709
+ suspendPayload: chunk.payload.suspendPayload,
710
+ runId: chunk.runId
654
711
  }
655
712
  }
656
713
  }
@@ -805,6 +862,69 @@ var toUIMessageFromAgent = (chunk, conversation, metadata, parentToolCallId, par
805
862
  }
806
863
  ];
807
864
  };
865
+ var findMessageIndexByToolCallId = (messages, toolCallId) => {
866
+ let count = 0;
867
+ for (let i = messages.length - 1; i >= 0; i--) {
868
+ const maxMessagesBack = 10;
869
+ if (count > maxMessagesBack) {
870
+ return -1;
871
+ }
872
+ const message = messages[i];
873
+ if (message.role !== "assistant") {
874
+ continue;
875
+ }
876
+ for (const part of message.parts) {
877
+ if (part.type === "dynamic-tool" && part.toolCallId === toolCallId) {
878
+ return i;
879
+ }
880
+ }
881
+ count++;
882
+ }
883
+ return -1;
884
+ };
885
+ var locateToolPart = (messages, toolCallId, allowMetadataOnlyMatch) => {
886
+ const lastMessage = messages[messages.length - 1];
887
+ if (lastMessage && lastMessage.role === "assistant") {
888
+ const toolPartIndex2 = lastMessage.parts.findIndex(
889
+ (part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === toolCallId
890
+ );
891
+ if (toolPartIndex2 !== -1) {
892
+ return { messageIndex: messages.length - 1, toolPartIndex: toolPartIndex2 };
893
+ }
894
+ }
895
+ const messageIndex = findMessageIndexByToolCallId(messages, toolCallId);
896
+ if (messageIndex === -1) return null;
897
+ const message = messages[messageIndex];
898
+ if (!message || message.role !== "assistant") return null;
899
+ const toolPartIndex = message.parts.findIndex(
900
+ (part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === toolCallId
901
+ );
902
+ if (toolPartIndex === -1) {
903
+ return allowMetadataOnlyMatch ? { messageIndex, toolPartIndex: -1 } : null;
904
+ }
905
+ return { messageIndex, toolPartIndex };
906
+ };
907
+ var mergeBgTaskMetadata = (existing, mode, args) => {
908
+ const existingAny = existing ?? {};
909
+ const existingBgTasks = existingAny.backgroundTasks ?? {};
910
+ const nextBgTasks = { ...existingBgTasks };
911
+ if (args.perTaskEntry) {
912
+ const { toolCallId, startedAt, completedAt, taskId } = args.perTaskEntry;
913
+ const prev = existingBgTasks[toolCallId] ?? { taskId };
914
+ nextBgTasks[toolCallId] = {
915
+ ...prev,
916
+ taskId,
917
+ ...startedAt !== void 0 ? { startedAt } : {},
918
+ ...completedAt !== void 0 ? { completedAt } : {}
919
+ };
920
+ }
921
+ return {
922
+ ...existingAny,
923
+ mode,
924
+ ...args.resetRunningCount ? { runningBackgroundTasksCount: void 0 } : {},
925
+ backgroundTasks: nextBgTasks
926
+ };
927
+ };
808
928
 
809
929
  // src/lib/ai-sdk/utils/toAssistantUIMessage.ts
810
930
  var toAssistantUIMessage = (message) => {
@@ -1308,7 +1428,8 @@ var AISdkNetworkTransformer = class {
1308
1428
  toolCallId: chunk.payload.toolCallId,
1309
1429
  toolName: chunk.payload.toolName,
1310
1430
  args: chunk.payload.args,
1311
- suspendPayload: chunk.payload.suspendPayload
1431
+ suspendPayload: chunk.payload.suspendPayload,
1432
+ runId: chunk.payload.runId
1312
1433
  }
1313
1434
  }
1314
1435
  }
@@ -1487,7 +1608,8 @@ var AISdkNetworkTransformer = class {
1487
1608
  toolCallId: chunk.payload.toolCallId,
1488
1609
  toolName: chunk.payload.toolName,
1489
1610
  args: chunk.payload.args,
1490
- suspendPayload: chunk.payload.suspendPayload
1611
+ suspendPayload: chunk.payload.suspendPayload,
1612
+ runId: chunk.payload.runId
1491
1613
  }
1492
1614
  }
1493
1615
  }
@@ -1602,7 +1724,8 @@ var AISdkNetworkTransformer = class {
1602
1724
  toolCallId: chunk.payload.toolCallId,
1603
1725
  toolName: chunk.payload.toolName,
1604
1726
  args: chunk.payload.args,
1605
- suspendPayload: chunk.payload.suspendPayload
1727
+ suspendPayload: chunk.payload.suspendPayload,
1728
+ runId: chunk.payload.runId
1606
1729
  }
1607
1730
  }
1608
1731
  }
@@ -1689,18 +1812,6 @@ var fromCoreUserMessageToUIMessage = (coreUserMessage) => {
1689
1812
  };
1690
1813
 
1691
1814
  // src/agent/hooks.ts
1692
- var extractRunIdFromMessages = (messages) => {
1693
- for (const message of messages) {
1694
- const pendingToolApprovals = message.metadata?.pendingToolApprovals;
1695
- if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
1696
- const suspensionData = Object.values(pendingToolApprovals)[0];
1697
- if (suspensionData?.runId) {
1698
- return suspensionData.runId;
1699
- }
1700
- }
1701
- }
1702
- return void 0;
1703
- };
1704
1815
  var useChat = ({
1705
1816
  agentId,
1706
1817
  resourceId,
@@ -1712,6 +1823,7 @@ var useChat = ({
1712
1823
  const _networkRunId = useRef(void 0);
1713
1824
  const _onNetworkChunk = useRef(void 0);
1714
1825
  const _requestContext = useRef(propsRequestContext);
1826
+ const _streamAbortRef = useRef(null);
1715
1827
  const [messages, setMessages] = useState([]);
1716
1828
  const [toolCallApprovals, setToolCallApprovals] = useState({});
1717
1829
  const [networkToolCallApprovals, setNetworkToolCallApprovals] = useState({});
@@ -1834,13 +1946,20 @@ var useChat = ({
1834
1946
  const resolvedRequestContext = requestContext ?? propsRequestContext;
1835
1947
  _requestContext.current = resolvedRequestContext;
1836
1948
  setIsRunning(true);
1949
+ _streamAbortRef.current?.abort();
1950
+ const internalAbort = new AbortController();
1951
+ _streamAbortRef.current = internalAbort;
1952
+ if (signal) {
1953
+ if (signal.aborted) internalAbort.abort();
1954
+ else signal.addEventListener("abort", () => internalAbort.abort(), { once: true });
1955
+ }
1837
1956
  const clientWithAbort = new MastraClient({
1838
1957
  ...baseClient.options,
1839
- abortSignal: signal
1958
+ abortSignal: internalAbort.signal
1840
1959
  });
1841
1960
  const agent = clientWithAbort.getAgent(agentId);
1842
1961
  const runId = v4();
1843
- const response = await agent.stream(coreUserMessages, {
1962
+ const response = await agent.streamUntilIdle(coreUserMessages, {
1844
1963
  runId,
1845
1964
  maxSteps,
1846
1965
  modelSettings: {
@@ -1867,6 +1986,9 @@ var useChat = ({
1867
1986
  void onChunk?.(chunk);
1868
1987
  }
1869
1988
  });
1989
+ if (_streamAbortRef.current === internalAbort) {
1990
+ _streamAbortRef.current = null;
1991
+ }
1870
1992
  setIsRunning(false);
1871
1993
  };
1872
1994
  const network = async ({