@mastra/react 0.0.0-monorepo-binary-20251013210052 → 0.0.0-partial-response-backport-20251204204441

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
@@ -5,7 +5,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5
5
  const jsxRuntime = require('react/jsx-runtime');
6
6
  const react = require('react');
7
7
  const clientJs = require('@mastra/client-js');
8
- const reactDom = require('react-dom');
8
+ const uuid = require('@lukeed/uuid');
9
9
  const lucideReact = require('lucide-react');
10
10
  const tailwindMerge = require('tailwind-merge');
11
11
  const hastUtilToJsxRuntime = require('hast-util-to-jsx-runtime');
@@ -254,35 +254,48 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
254
254
  }
255
255
  ];
256
256
  }
257
+ case "tool-error":
257
258
  case "tool-result": {
258
259
  const lastMessage = result[result.length - 1];
259
260
  if (!lastMessage || lastMessage.role !== "assistant") return result;
260
261
  const parts = [...lastMessage.parts];
261
262
  const toolPartIndex = parts.findIndex(
262
- (part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
263
+ (part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
263
264
  );
264
265
  if (toolPartIndex !== -1) {
265
266
  const toolPart = parts[toolPartIndex];
266
- if (toolPart.type === "dynamic-tool") {
267
- if (chunk.payload.isError) {
267
+ if (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-")) {
268
+ const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
269
+ const toolCallId = toolPart.toolCallId;
270
+ if (chunk.type === "tool-result" && chunk.payload.isError || chunk.type === "tool-error") {
271
+ const error = chunk.type === "tool-error" ? chunk.payload.error : chunk.payload.result;
268
272
  parts[toolPartIndex] = {
269
273
  type: "dynamic-tool",
270
- toolName: toolPart.toolName,
271
- toolCallId: toolPart.toolCallId,
274
+ toolName,
275
+ toolCallId,
272
276
  state: "output-error",
273
277
  input: toolPart.input,
274
- errorText: String(chunk.payload.result),
278
+ errorText: String(error),
275
279
  callProviderMetadata: chunk.payload.providerMetadata
276
280
  };
277
281
  } else {
278
282
  const isWorkflow = Boolean(chunk.payload.result?.result?.steps);
283
+ const isAgent = chunk?.from === "AGENT";
284
+ let output;
285
+ if (isWorkflow) {
286
+ output = chunk.payload.result?.result;
287
+ } else if (isAgent) {
288
+ output = parts[toolPartIndex].output ?? chunk.payload.result;
289
+ } else {
290
+ output = chunk.payload.result;
291
+ }
279
292
  parts[toolPartIndex] = {
280
293
  type: "dynamic-tool",
281
- toolName: toolPart.toolName,
282
- toolCallId: toolPart.toolCallId,
294
+ toolName,
295
+ toolCallId,
283
296
  state: "output-available",
284
297
  input: toolPart.input,
285
- output: isWorkflow ? chunk.payload.result?.result : chunk.payload.result,
298
+ output,
286
299
  callProviderMetadata: chunk.payload.providerMetadata
287
300
  };
288
301
  }
@@ -301,11 +314,14 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
301
314
  if (!lastMessage || lastMessage.role !== "assistant") return result;
302
315
  const parts = [...lastMessage.parts];
303
316
  const toolPartIndex = parts.findIndex(
304
- (part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
317
+ (part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
305
318
  );
306
319
  if (toolPartIndex !== -1) {
307
320
  const toolPart = parts[toolPartIndex];
308
- if (toolPart.type === "dynamic-tool") {
321
+ if (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-")) {
322
+ const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : typeof toolPart.type === "string" && toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
323
+ const toolCallId = toolPart.toolCallId;
324
+ const input = toolPart.input;
309
325
  if (chunk.payload.output?.type?.startsWith("workflow-")) {
310
326
  const existingWorkflowState = toolPart.output || {};
311
327
  const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(
@@ -313,14 +329,24 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
313
329
  chunk.payload.output
314
330
  );
315
331
  parts[toolPartIndex] = {
316
- ...toolPart,
332
+ type: "dynamic-tool",
333
+ toolName,
334
+ toolCallId,
335
+ state: "input-streaming",
336
+ input,
317
337
  output: updatedWorkflowState
318
338
  };
339
+ } else if (chunk.payload.output?.from === "AGENT" || chunk.payload.output?.from === "USER" && chunk.payload.output?.payload?.output?.type?.startsWith("workflow-")) {
340
+ return toUIMessageFromAgent(chunk.payload.output, conversation);
319
341
  } else {
320
342
  const currentOutput = toolPart.output || [];
321
343
  const existingOutput = Array.isArray(currentOutput) ? currentOutput : [];
322
344
  parts[toolPartIndex] = {
323
- ...toolPart,
345
+ type: "dynamic-tool",
346
+ toolName,
347
+ toolCallId,
348
+ state: "input-streaming",
349
+ input,
324
350
  output: [...existingOutput, chunk.payload.output]
325
351
  };
326
352
  }
@@ -389,6 +415,29 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
389
415
  }
390
416
  ];
391
417
  }
418
+ case "tool-call-approval": {
419
+ const lastMessage = result[result.length - 1];
420
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
421
+ const lastRequireApprovalMetadata = lastMessage.metadata?.mode === "stream" ? lastMessage.metadata?.requireApprovalMetadata : {};
422
+ return [
423
+ ...result.slice(0, -1),
424
+ {
425
+ ...lastMessage,
426
+ metadata: {
427
+ ...lastMessage.metadata,
428
+ mode: "stream",
429
+ requireApprovalMetadata: {
430
+ ...lastRequireApprovalMetadata,
431
+ [chunk.payload.toolCallId]: {
432
+ toolCallId: chunk.payload.toolCallId,
433
+ toolName: chunk.payload.toolName,
434
+ args: chunk.payload.args
435
+ }
436
+ }
437
+ }
438
+ }
439
+ ];
440
+ }
392
441
  case "finish": {
393
442
  const lastMessage = result[result.length - 1];
394
443
  if (!lastMessage || lastMessage.role !== "assistant") return result;
@@ -431,6 +480,105 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
431
480
  return result;
432
481
  }
433
482
  };
483
+ const toUIMessageFromAgent = (chunk, conversation, metadata) => {
484
+ const lastMessage = conversation[conversation.length - 1];
485
+ if (!lastMessage || lastMessage.role !== "assistant") return conversation;
486
+ const parts = [...lastMessage.parts];
487
+ if (chunk.type === "text-delta") {
488
+ const agentChunk = chunk.payload;
489
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
490
+ if (toolPartIndex === -1) return conversation;
491
+ const toolPart = parts[toolPartIndex];
492
+ const childMessages = toolPart?.output?.childMessages || [];
493
+ const lastChildMessage = childMessages[childMessages.length - 1];
494
+ const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
495
+ const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
496
+ parts[toolPartIndex] = {
497
+ ...toolPart,
498
+ output: {
499
+ childMessages: nextMessages
500
+ }
501
+ };
502
+ } else if (chunk.type === "tool-call") {
503
+ const agentChunk = chunk.payload;
504
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
505
+ if (toolPartIndex === -1) return conversation;
506
+ const toolPart = parts[toolPartIndex];
507
+ const childMessages = toolPart?.output?.childMessages || [];
508
+ parts[toolPartIndex] = {
509
+ ...toolPart,
510
+ output: {
511
+ ...toolPart?.output,
512
+ childMessages: [
513
+ ...childMessages,
514
+ {
515
+ type: "tool",
516
+ toolCallId: agentChunk.toolCallId,
517
+ toolName: agentChunk.toolName,
518
+ args: agentChunk.args
519
+ }
520
+ ]
521
+ }
522
+ };
523
+ } else if (chunk.type === "tool-output") {
524
+ const agentChunk = chunk.payload;
525
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
526
+ if (toolPartIndex === -1) return conversation;
527
+ const toolPart = parts[toolPartIndex];
528
+ if (agentChunk?.output?.type?.startsWith("workflow-")) {
529
+ const childMessages = toolPart?.output?.childMessages || [];
530
+ const lastToolIndex = childMessages.length - 1;
531
+ const currentMessage = childMessages[lastToolIndex];
532
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
533
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
534
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
535
+ parts[toolPartIndex] = {
536
+ ...toolPart,
537
+ output: {
538
+ ...toolPart?.output,
539
+ childMessages: [
540
+ ...childMessages.slice(0, -1),
541
+ {
542
+ ...currentMessage,
543
+ toolOutput: { ...updatedWorkflowState, runId: agentChunk.output.runId }
544
+ }
545
+ ]
546
+ }
547
+ };
548
+ }
549
+ }
550
+ } else if (chunk.type === "tool-result") {
551
+ const agentChunk = chunk.payload;
552
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
553
+ if (toolPartIndex === -1) return conversation;
554
+ const toolPart = parts[toolPartIndex];
555
+ const childMessages = toolPart?.output?.childMessages || [];
556
+ const lastToolIndex = childMessages.length - 1;
557
+ const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
558
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
559
+ parts[toolPartIndex] = {
560
+ ...toolPart,
561
+ output: {
562
+ ...toolPart?.output,
563
+ childMessages: [
564
+ ...childMessages.slice(0, -1),
565
+ {
566
+ ...childMessages[lastToolIndex],
567
+ toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
568
+ }
569
+ ]
570
+ }
571
+ };
572
+ }
573
+ }
574
+ return [
575
+ ...conversation.slice(0, -1),
576
+ {
577
+ ...lastMessage,
578
+ parts
579
+ }
580
+ ];
581
+ };
434
582
 
435
583
  const toAssistantUIMessage = (message) => {
436
584
  const extendedMessage = message;
@@ -512,6 +660,20 @@ const toAssistantUIMessage = (message) => {
512
660
  }
513
661
  return baseToolCall;
514
662
  }
663
+ const requireApprovalMetadata = extendedMessage.metadata?.requireApprovalMetadata;
664
+ const partToolCallId = "toolCallId" in part && typeof part.toolCallId === "string" ? part.toolCallId : void 0;
665
+ const suspensionData = partToolCallId ? requireApprovalMetadata?.[partToolCallId] : void 0;
666
+ if (suspensionData) {
667
+ const toolName = "toolName" in part && typeof part.toolName === "string" ? part.toolName : part.type.startsWith("tool-") ? part.type.substring(5) : "";
668
+ return {
669
+ type: "tool-call",
670
+ toolCallId: partToolCallId,
671
+ toolName,
672
+ argsText: "input" in part ? JSON.stringify(part.input) : "{}",
673
+ args: "input" in part ? part.input : {},
674
+ metadata: extendedMessage.metadata
675
+ };
676
+ }
515
677
  return {
516
678
  type: "text",
517
679
  text: "",
@@ -551,9 +713,127 @@ const toAssistantUIMessage = (message) => {
551
713
  return threadMessage;
552
714
  };
553
715
 
716
+ const resolveInitialMessages = (messages) => {
717
+ return messages.map((message) => {
718
+ const networkPart = message.parts.find((part) => part.type === "text" && part.text.includes('"isNetwork":true'));
719
+ if (networkPart && networkPart.type === "text") {
720
+ try {
721
+ const json = JSON.parse(networkPart.text);
722
+ if (json.isNetwork === true) {
723
+ const selectionReason = json.selectionReason || "";
724
+ const primitiveType = json.primitiveType || "";
725
+ const primitiveId = json.primitiveId || "";
726
+ const finalResult = json.finalResult;
727
+ const toolCalls = finalResult?.toolCalls || [];
728
+ const childMessages = [];
729
+ for (const toolCall of toolCalls) {
730
+ if (toolCall.type === "tool-call" && toolCall.payload) {
731
+ const toolCallId = toolCall.payload.toolCallId;
732
+ let toolResult;
733
+ for (const message2 of finalResult?.messages || []) {
734
+ for (const part of message2.content || []) {
735
+ if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
736
+ toolResult = part;
737
+ break;
738
+ }
739
+ }
740
+ }
741
+ const isWorkflow = Boolean(toolResult?.result?.result?.steps);
742
+ childMessages.push({
743
+ type: "tool",
744
+ toolCallId: toolCall.payload.toolCallId,
745
+ toolName: toolCall.payload.toolName,
746
+ args: toolCall.payload.args,
747
+ toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
748
+ });
749
+ }
750
+ }
751
+ if (finalResult && finalResult.text) {
752
+ childMessages.push({
753
+ type: "text",
754
+ content: finalResult.text
755
+ });
756
+ }
757
+ const result = {
758
+ childMessages,
759
+ result: finalResult?.text || ""
760
+ };
761
+ const nextMessage = {
762
+ role: "assistant",
763
+ parts: [
764
+ {
765
+ type: "dynamic-tool",
766
+ toolCallId: primitiveId,
767
+ toolName: primitiveId,
768
+ state: "output-available",
769
+ input: json.input,
770
+ output: result
771
+ }
772
+ ],
773
+ id: message.id,
774
+ metadata: {
775
+ ...message.metadata,
776
+ mode: "network",
777
+ selectionReason,
778
+ agentInput: json.input,
779
+ from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
780
+ }
781
+ };
782
+ return nextMessage;
783
+ }
784
+ } catch (error) {
785
+ return message;
786
+ }
787
+ }
788
+ const extendedMessage = message;
789
+ const pendingToolApprovals = extendedMessage.metadata?.pendingToolApprovals;
790
+ if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
791
+ return {
792
+ ...message,
793
+ metadata: {
794
+ ...message.metadata,
795
+ mode: "stream",
796
+ requireApprovalMetadata: pendingToolApprovals
797
+ }
798
+ };
799
+ }
800
+ return message;
801
+ });
802
+ };
803
+ const resolveToChildMessages = (messages) => {
804
+ const assistantMessage = messages.find((message) => message.role === "assistant");
805
+ if (!assistantMessage) return [];
806
+ const parts = assistantMessage.parts;
807
+ let childMessages = [];
808
+ for (const part of parts) {
809
+ const toolPart = part;
810
+ if (part.type.startsWith("tool-")) {
811
+ const toolName = part.type.substring("tool-".length);
812
+ const isWorkflow = toolName.startsWith("workflow-");
813
+ childMessages.push({
814
+ type: "tool",
815
+ toolCallId: toolPart.toolCallId,
816
+ toolName,
817
+ args: toolPart.input,
818
+ toolOutput: isWorkflow ? { ...toolPart.output?.result, runId: toolPart.output?.runId } : toolPart.output
819
+ });
820
+ }
821
+ if (part.type === "text") {
822
+ childMessages.push({
823
+ type: "text",
824
+ content: toolPart.text
825
+ });
826
+ }
827
+ }
828
+ return childMessages;
829
+ };
830
+
554
831
  class AISdkNetworkTransformer {
555
832
  transform({ chunk, conversation, metadata }) {
556
833
  const newConversation = [...conversation];
834
+ if (chunk.type === "routing-agent-text-delta") {
835
+ return this.handleRoutingAgentConversation(chunk, newConversation);
836
+ }
557
837
  if (chunk.type.startsWith("agent-execution-")) {
558
838
  return this.handleAgentConversation(chunk, newConversation, metadata);
559
839
  }
@@ -564,22 +844,80 @@ class AISdkNetworkTransformer {
564
844
  return this.handleToolConversation(chunk, newConversation, metadata);
565
845
  }
566
846
  if (chunk.type === "network-execution-event-step-finish") {
567
- const newMessage = {
568
- id: `network-execution-event-step-finish-${chunk.runId}-${Date.now()}`,
569
- role: "assistant",
570
- parts: [
847
+ const lastMessage = newConversation[newConversation.length - 1];
848
+ if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
849
+ const agentChunk = chunk.payload;
850
+ const parts = [...lastMessage.parts];
851
+ const textPartIndex = parts.findIndex((part) => part.type === "text");
852
+ if (textPartIndex === -1) {
853
+ parts.push({
854
+ type: "text",
855
+ text: agentChunk.result,
856
+ state: "done"
857
+ });
858
+ return [
859
+ ...newConversation.slice(0, -1),
571
860
  {
572
- type: "text",
573
- text: chunk.payload?.result || "",
574
- state: "done"
861
+ ...lastMessage,
862
+ parts
575
863
  }
576
- ],
577
- metadata
578
- };
579
- return [...newConversation, newMessage];
864
+ ];
865
+ }
866
+ const textPart = parts[textPartIndex];
867
+ if (textPart.type === "text") {
868
+ parts[textPartIndex] = {
869
+ ...textPart,
870
+ state: "done"
871
+ };
872
+ return [
873
+ ...newConversation.slice(0, -1),
874
+ {
875
+ ...lastMessage,
876
+ parts
877
+ }
878
+ ];
879
+ }
880
+ return newConversation;
580
881
  }
581
882
  return newConversation;
582
883
  }
884
+ handleRoutingAgentConversation = (chunk, newConversation) => {
885
+ const lastMessage = newConversation[newConversation.length - 1];
886
+ if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
887
+ const agentChunk = chunk.payload;
888
+ const parts = [...lastMessage.parts];
889
+ const textPartIndex = parts.findIndex((part) => part.type === "text");
890
+ if (textPartIndex === -1) {
891
+ parts.push({
892
+ type: "text",
893
+ text: agentChunk.text,
894
+ state: "streaming"
895
+ });
896
+ return [
897
+ ...newConversation.slice(0, -1),
898
+ {
899
+ ...lastMessage,
900
+ parts
901
+ }
902
+ ];
903
+ }
904
+ const textPart = parts[textPartIndex];
905
+ if (textPart.type === "text") {
906
+ parts[textPartIndex] = {
907
+ ...textPart,
908
+ text: textPart.text + agentChunk.text,
909
+ state: "streaming"
910
+ };
911
+ return [
912
+ ...newConversation.slice(0, -1),
913
+ {
914
+ ...lastMessage,
915
+ parts
916
+ }
917
+ ];
918
+ }
919
+ return newConversation;
920
+ };
583
921
  handleAgentConversation = (chunk, newConversation, metadata) => {
584
922
  if (chunk.type === "agent-execution-start") {
585
923
  const primitiveId = chunk.payload?.args?.primitiveId;
@@ -862,87 +1200,25 @@ class AISdkNetworkTransformer {
862
1200
  };
863
1201
  }
864
1202
 
865
- const resolveInitialMessages = (messages) => {
866
- return messages.map((message) => {
867
- const networkPart = message.parts.find((part) => part.type === "text" && part.text.includes('"isNetwork":true'));
868
- if (networkPart && networkPart.type === "text") {
869
- try {
870
- const json = JSON.parse(networkPart.text);
871
- if (json.isNetwork === true) {
872
- const selectionReason = json.selectionReason || "";
873
- const primitiveType = json.primitiveType || "";
874
- const primitiveId = json.primitiveId || "";
875
- const finalResult = json.finalResult;
876
- const toolCalls = finalResult?.toolCalls || [];
877
- const childMessages = [];
878
- for (const toolCall of toolCalls) {
879
- if (toolCall.type === "tool-call" && toolCall.payload) {
880
- const toolCallId = toolCall.payload.toolCallId;
881
- let toolResult;
882
- for (const message2 of finalResult?.messages || []) {
883
- for (const part of message2.content || []) {
884
- if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
885
- toolResult = part;
886
- break;
887
- }
888
- }
889
- }
890
- const isWorkflow = Boolean(toolResult?.result?.result?.steps);
891
- childMessages.push({
892
- type: "tool",
893
- toolCallId: toolCall.payload.toolCallId,
894
- toolName: toolCall.payload.toolName,
895
- args: toolCall.payload.args,
896
- toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
897
- });
898
- }
899
- }
900
- if (finalResult && finalResult.text) {
901
- childMessages.push({
902
- type: "text",
903
- content: finalResult.text
904
- });
905
- }
906
- const result = {
907
- childMessages,
908
- result: finalResult?.text || ""
909
- };
910
- console.log("json", json);
911
- const nextMessage = {
912
- role: "assistant",
913
- parts: [
914
- {
915
- type: "dynamic-tool",
916
- toolCallId: primitiveId,
917
- toolName: primitiveId,
918
- state: "output-available",
919
- input: json.input,
920
- output: result
921
- }
922
- ],
923
- id: message.id,
924
- metadata: {
925
- ...message.metadata,
926
- mode: "network",
927
- selectionReason,
928
- agentInput: json.input,
929
- from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
930
- }
931
- };
932
- return nextMessage;
1203
+ const useChat = ({ agentId, resourceId, initializeMessages }) => {
1204
+ const extractRunIdFromMessages = (messages2) => {
1205
+ for (const message of messages2) {
1206
+ const pendingToolApprovals = message.metadata?.pendingToolApprovals;
1207
+ if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
1208
+ const suspensionData = Object.values(pendingToolApprovals)[0];
1209
+ if (suspensionData?.runId) {
1210
+ return suspensionData.runId;
933
1211
  }
934
- } catch (error) {
935
- return message;
936
1212
  }
937
1213
  }
938
- return message;
939
- });
940
- };
941
-
942
- const useChat = ({ agentId, initializeMessages }) => {
943
- const [messages, setMessages] = react.useState(
944
- () => resolveInitialMessages(initializeMessages?.() || [])
945
- );
1214
+ return void 0;
1215
+ };
1216
+ const initialMessages = initializeMessages?.() || [];
1217
+ const initialRunId = extractRunIdFromMessages(initialMessages);
1218
+ const _currentRunId = react.useRef(initialRunId);
1219
+ const _onChunk = react.useRef(void 0);
1220
+ const [messages, setMessages] = react.useState(() => resolveInitialMessages(initialMessages));
1221
+ const [toolCallApprovals, setToolCallApprovals] = react.useState({});
946
1222
  const baseClient = useMastraClient();
947
1223
  const [isRunning, setIsRunning] = react.useState(false);
948
1224
  const generate = async ({
@@ -973,7 +1249,7 @@ const useChat = ({ agentId, initializeMessages }) => {
973
1249
  const agent = clientWithAbort.getAgent(agentId);
974
1250
  const response = await agent.generate({
975
1251
  messages: coreUserMessages,
976
- runId: agentId,
1252
+ runId: uuid.v4(),
977
1253
  maxSteps,
978
1254
  modelSettings: {
979
1255
  frequencyPenalty,
@@ -986,7 +1262,7 @@ const useChat = ({ agentId, initializeMessages }) => {
986
1262
  },
987
1263
  instructions,
988
1264
  runtimeContext,
989
- ...threadId ? { threadId, resourceId: agentId } : {},
1265
+ ...threadId ? { threadId, resourceId: resourceId || agentId } : {},
990
1266
  providerOptions
991
1267
  });
992
1268
  setIsRunning(false);
@@ -1012,7 +1288,8 @@ const useChat = ({ agentId, initializeMessages }) => {
1012
1288
  topP,
1013
1289
  instructions,
1014
1290
  providerOptions,
1015
- maxSteps
1291
+ maxSteps,
1292
+ requireToolApproval
1016
1293
  } = modelSettings || {};
1017
1294
  setIsRunning(true);
1018
1295
  const clientWithAbort = new clientJs.MastraClient({
@@ -1020,9 +1297,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1020
1297
  abortSignal: signal
1021
1298
  });
1022
1299
  const agent = clientWithAbort.getAgent(agentId);
1300
+ const runId = uuid.v4();
1023
1301
  const response = await agent.stream({
1024
1302
  messages: coreUserMessages,
1025
- runId: agentId,
1303
+ runId,
1026
1304
  maxSteps,
1027
1305
  modelSettings: {
1028
1306
  frequencyPenalty,
@@ -1035,18 +1313,15 @@ const useChat = ({ agentId, initializeMessages }) => {
1035
1313
  },
1036
1314
  instructions,
1037
1315
  runtimeContext,
1038
- ...threadId ? { threadId, resourceId: agentId } : {},
1039
- providerOptions
1316
+ ...threadId ? { threadId, resourceId: resourceId || agentId } : {},
1317
+ providerOptions,
1318
+ requireToolApproval
1040
1319
  });
1041
- if (!response.body) {
1042
- setIsRunning(false);
1043
- throw new Error("[Stream] No response body");
1044
- }
1320
+ _onChunk.current = onChunk;
1321
+ _currentRunId.current = runId;
1045
1322
  await response.processDataStream({
1046
1323
  onChunk: async (chunk) => {
1047
- reactDom.flushSync(() => {
1048
- setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1049
- });
1324
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1050
1325
  onChunk?.(chunk);
1051
1326
  }
1052
1327
  });
@@ -1067,6 +1342,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1067
1342
  abortSignal: signal
1068
1343
  });
1069
1344
  const agent = clientWithAbort.getAgent(agentId);
1345
+ const runId = uuid.v4();
1070
1346
  const response = await agent.network({
1071
1347
  messages: coreUserMessages,
1072
1348
  maxSteps,
@@ -1079,21 +1355,58 @@ const useChat = ({ agentId, initializeMessages }) => {
1079
1355
  topK,
1080
1356
  topP
1081
1357
  },
1082
- runId: agentId,
1358
+ runId,
1083
1359
  runtimeContext,
1084
- ...threadId ? { thread: threadId, resourceId: agentId } : {}
1360
+ ...threadId ? { thread: threadId, resourceId: resourceId || agentId } : {}
1085
1361
  });
1086
1362
  const transformer = new AISdkNetworkTransformer();
1087
1363
  await response.processDataStream({
1088
1364
  onChunk: async (chunk) => {
1089
- reactDom.flushSync(() => {
1090
- setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1091
- });
1365
+ setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1092
1366
  onNetworkChunk?.(chunk);
1093
1367
  }
1094
1368
  });
1095
1369
  setIsRunning(false);
1096
1370
  };
1371
+ const handleCancelRun = () => {
1372
+ setIsRunning(false);
1373
+ _currentRunId.current = void 0;
1374
+ _onChunk.current = void 0;
1375
+ };
1376
+ const approveToolCall = async (toolCallId) => {
1377
+ const onChunk = _onChunk.current;
1378
+ const currentRunId = _currentRunId.current;
1379
+ if (!currentRunId)
1380
+ return console.info("[approveToolCall] approveToolCall can only be called after a stream has started");
1381
+ setIsRunning(true);
1382
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "approved" } }));
1383
+ const agent = baseClient.getAgent(agentId);
1384
+ const response = await agent.approveToolCall({ runId: currentRunId, toolCallId });
1385
+ await response.processDataStream({
1386
+ onChunk: async (chunk) => {
1387
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1388
+ onChunk?.(chunk);
1389
+ }
1390
+ });
1391
+ setIsRunning(false);
1392
+ };
1393
+ const declineToolCall = async (toolCallId) => {
1394
+ const onChunk = _onChunk.current;
1395
+ const currentRunId = _currentRunId.current;
1396
+ if (!currentRunId)
1397
+ return console.info("[declineToolCall] declineToolCall can only be called after a stream has started");
1398
+ setIsRunning(true);
1399
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "declined" } }));
1400
+ const agent = baseClient.getAgent(agentId);
1401
+ const response = await agent.declineToolCall({ runId: currentRunId, toolCallId });
1402
+ await response.processDataStream({
1403
+ onChunk: async (chunk) => {
1404
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1405
+ onChunk?.(chunk);
1406
+ }
1407
+ });
1408
+ setIsRunning(false);
1409
+ };
1097
1410
  const sendMessage = async ({ mode = "stream", ...args }) => {
1098
1411
  const nextMessage = { role: "user", content: [{ type: "text", text: args.message }] };
1099
1412
  const messages2 = args.coreUserMessages ? [nextMessage, ...args.coreUserMessages] : [nextMessage];
@@ -1111,7 +1424,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1111
1424
  sendMessage,
1112
1425
  isRunning,
1113
1426
  messages,
1114
- cancelRun: () => setIsRunning(false)
1427
+ approveToolCall,
1428
+ declineToolCall,
1429
+ cancelRun: handleCancelRun,
1430
+ toolCallApprovals
1115
1431
  };
1116
1432
  };
1117
1433
 
@@ -1485,6 +1801,7 @@ exports.TooltipContentClass = TooltipContentClass;
1485
1801
  exports.TooltipTrigger = TooltipTrigger;
1486
1802
  exports.WorkflowIcon = WorkflowIcon;
1487
1803
  exports.mapWorkflowStreamChunkToWatchResult = mapWorkflowStreamChunkToWatchResult;
1804
+ exports.resolveToChildMessages = resolveToChildMessages;
1488
1805
  exports.toAssistantUIMessage = toAssistantUIMessage;
1489
1806
  exports.toUIMessage = toUIMessage;
1490
1807
  exports.useChat = useChat;