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