@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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { createContext, useContext, useState, Fragment, useLayoutEffect, useRef, useEffect } from 'react';
2
+ import { createContext, useContext, useRef, useState, Fragment, useLayoutEffect, useEffect } from 'react';
3
3
  import { MastraClient } from '@mastra/client-js';
4
- import { flushSync } from 'react-dom';
4
+ import { v4 } from '@lukeed/uuid';
5
5
  import { ChevronDownIcon, CheckIcon, CopyIcon } from 'lucide-react';
6
6
  import { twMerge } from 'tailwind-merge';
7
7
  import { toJsxRuntime } from 'hast-util-to-jsx-runtime';
@@ -250,35 +250,48 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
250
250
  }
251
251
  ];
252
252
  }
253
+ case "tool-error":
253
254
  case "tool-result": {
254
255
  const lastMessage = result[result.length - 1];
255
256
  if (!lastMessage || lastMessage.role !== "assistant") return result;
256
257
  const parts = [...lastMessage.parts];
257
258
  const toolPartIndex = parts.findIndex(
258
- (part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
259
+ (part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
259
260
  );
260
261
  if (toolPartIndex !== -1) {
261
262
  const toolPart = parts[toolPartIndex];
262
- if (toolPart.type === "dynamic-tool") {
263
- if (chunk.payload.isError) {
263
+ if (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-")) {
264
+ const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
265
+ const toolCallId = toolPart.toolCallId;
266
+ if (chunk.type === "tool-result" && chunk.payload.isError || chunk.type === "tool-error") {
267
+ const error = chunk.type === "tool-error" ? chunk.payload.error : chunk.payload.result;
264
268
  parts[toolPartIndex] = {
265
269
  type: "dynamic-tool",
266
- toolName: toolPart.toolName,
267
- toolCallId: toolPart.toolCallId,
270
+ toolName,
271
+ toolCallId,
268
272
  state: "output-error",
269
273
  input: toolPart.input,
270
- errorText: String(chunk.payload.result),
274
+ errorText: String(error),
271
275
  callProviderMetadata: chunk.payload.providerMetadata
272
276
  };
273
277
  } else {
274
278
  const isWorkflow = Boolean(chunk.payload.result?.result?.steps);
279
+ const isAgent = chunk?.from === "AGENT";
280
+ let output;
281
+ if (isWorkflow) {
282
+ output = chunk.payload.result?.result;
283
+ } else if (isAgent) {
284
+ output = parts[toolPartIndex].output ?? chunk.payload.result;
285
+ } else {
286
+ output = chunk.payload.result;
287
+ }
275
288
  parts[toolPartIndex] = {
276
289
  type: "dynamic-tool",
277
- toolName: toolPart.toolName,
278
- toolCallId: toolPart.toolCallId,
290
+ toolName,
291
+ toolCallId,
279
292
  state: "output-available",
280
293
  input: toolPart.input,
281
- output: isWorkflow ? chunk.payload.result?.result : chunk.payload.result,
294
+ output,
282
295
  callProviderMetadata: chunk.payload.providerMetadata
283
296
  };
284
297
  }
@@ -297,11 +310,14 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
297
310
  if (!lastMessage || lastMessage.role !== "assistant") return result;
298
311
  const parts = [...lastMessage.parts];
299
312
  const toolPartIndex = parts.findIndex(
300
- (part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
313
+ (part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
301
314
  );
302
315
  if (toolPartIndex !== -1) {
303
316
  const toolPart = parts[toolPartIndex];
304
- if (toolPart.type === "dynamic-tool") {
317
+ if (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-")) {
318
+ const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : typeof toolPart.type === "string" && toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
319
+ const toolCallId = toolPart.toolCallId;
320
+ const input = toolPart.input;
305
321
  if (chunk.payload.output?.type?.startsWith("workflow-")) {
306
322
  const existingWorkflowState = toolPart.output || {};
307
323
  const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(
@@ -309,14 +325,24 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
309
325
  chunk.payload.output
310
326
  );
311
327
  parts[toolPartIndex] = {
312
- ...toolPart,
328
+ type: "dynamic-tool",
329
+ toolName,
330
+ toolCallId,
331
+ state: "input-streaming",
332
+ input,
313
333
  output: updatedWorkflowState
314
334
  };
335
+ } else if (chunk.payload.output?.from === "AGENT" || chunk.payload.output?.from === "USER" && chunk.payload.output?.payload?.output?.type?.startsWith("workflow-")) {
336
+ return toUIMessageFromAgent(chunk.payload.output, conversation);
315
337
  } else {
316
338
  const currentOutput = toolPart.output || [];
317
339
  const existingOutput = Array.isArray(currentOutput) ? currentOutput : [];
318
340
  parts[toolPartIndex] = {
319
- ...toolPart,
341
+ type: "dynamic-tool",
342
+ toolName,
343
+ toolCallId,
344
+ state: "input-streaming",
345
+ input,
320
346
  output: [...existingOutput, chunk.payload.output]
321
347
  };
322
348
  }
@@ -385,6 +411,29 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
385
411
  }
386
412
  ];
387
413
  }
414
+ case "tool-call-approval": {
415
+ const lastMessage = result[result.length - 1];
416
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
417
+ const lastRequireApprovalMetadata = lastMessage.metadata?.mode === "stream" ? lastMessage.metadata?.requireApprovalMetadata : {};
418
+ return [
419
+ ...result.slice(0, -1),
420
+ {
421
+ ...lastMessage,
422
+ metadata: {
423
+ ...lastMessage.metadata,
424
+ mode: "stream",
425
+ requireApprovalMetadata: {
426
+ ...lastRequireApprovalMetadata,
427
+ [chunk.payload.toolCallId]: {
428
+ toolCallId: chunk.payload.toolCallId,
429
+ toolName: chunk.payload.toolName,
430
+ args: chunk.payload.args
431
+ }
432
+ }
433
+ }
434
+ }
435
+ ];
436
+ }
388
437
  case "finish": {
389
438
  const lastMessage = result[result.length - 1];
390
439
  if (!lastMessage || lastMessage.role !== "assistant") return result;
@@ -427,6 +476,105 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
427
476
  return result;
428
477
  }
429
478
  };
479
+ const toUIMessageFromAgent = (chunk, conversation, metadata) => {
480
+ const lastMessage = conversation[conversation.length - 1];
481
+ if (!lastMessage || lastMessage.role !== "assistant") return conversation;
482
+ const parts = [...lastMessage.parts];
483
+ if (chunk.type === "text-delta") {
484
+ const agentChunk = chunk.payload;
485
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
486
+ if (toolPartIndex === -1) return conversation;
487
+ const toolPart = parts[toolPartIndex];
488
+ const childMessages = toolPart?.output?.childMessages || [];
489
+ const lastChildMessage = childMessages[childMessages.length - 1];
490
+ const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
491
+ const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
492
+ parts[toolPartIndex] = {
493
+ ...toolPart,
494
+ output: {
495
+ childMessages: nextMessages
496
+ }
497
+ };
498
+ } else if (chunk.type === "tool-call") {
499
+ const agentChunk = chunk.payload;
500
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
501
+ if (toolPartIndex === -1) return conversation;
502
+ const toolPart = parts[toolPartIndex];
503
+ const childMessages = toolPart?.output?.childMessages || [];
504
+ parts[toolPartIndex] = {
505
+ ...toolPart,
506
+ output: {
507
+ ...toolPart?.output,
508
+ childMessages: [
509
+ ...childMessages,
510
+ {
511
+ type: "tool",
512
+ toolCallId: agentChunk.toolCallId,
513
+ toolName: agentChunk.toolName,
514
+ args: agentChunk.args
515
+ }
516
+ ]
517
+ }
518
+ };
519
+ } else if (chunk.type === "tool-output") {
520
+ const agentChunk = chunk.payload;
521
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
522
+ if (toolPartIndex === -1) return conversation;
523
+ const toolPart = parts[toolPartIndex];
524
+ if (agentChunk?.output?.type?.startsWith("workflow-")) {
525
+ const childMessages = toolPart?.output?.childMessages || [];
526
+ const lastToolIndex = childMessages.length - 1;
527
+ const currentMessage = childMessages[lastToolIndex];
528
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
529
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
530
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
531
+ parts[toolPartIndex] = {
532
+ ...toolPart,
533
+ output: {
534
+ ...toolPart?.output,
535
+ childMessages: [
536
+ ...childMessages.slice(0, -1),
537
+ {
538
+ ...currentMessage,
539
+ toolOutput: { ...updatedWorkflowState, runId: agentChunk.output.runId }
540
+ }
541
+ ]
542
+ }
543
+ };
544
+ }
545
+ }
546
+ } else if (chunk.type === "tool-result") {
547
+ const agentChunk = chunk.payload;
548
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
549
+ if (toolPartIndex === -1) return conversation;
550
+ const toolPart = parts[toolPartIndex];
551
+ const childMessages = toolPart?.output?.childMessages || [];
552
+ const lastToolIndex = childMessages.length - 1;
553
+ const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
554
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
555
+ parts[toolPartIndex] = {
556
+ ...toolPart,
557
+ output: {
558
+ ...toolPart?.output,
559
+ childMessages: [
560
+ ...childMessages.slice(0, -1),
561
+ {
562
+ ...childMessages[lastToolIndex],
563
+ toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
564
+ }
565
+ ]
566
+ }
567
+ };
568
+ }
569
+ }
570
+ return [
571
+ ...conversation.slice(0, -1),
572
+ {
573
+ ...lastMessage,
574
+ parts
575
+ }
576
+ ];
577
+ };
430
578
 
431
579
  const toAssistantUIMessage = (message) => {
432
580
  const extendedMessage = message;
@@ -508,6 +656,20 @@ const toAssistantUIMessage = (message) => {
508
656
  }
509
657
  return baseToolCall;
510
658
  }
659
+ const requireApprovalMetadata = extendedMessage.metadata?.requireApprovalMetadata;
660
+ const partToolCallId = "toolCallId" in part && typeof part.toolCallId === "string" ? part.toolCallId : void 0;
661
+ const suspensionData = partToolCallId ? requireApprovalMetadata?.[partToolCallId] : void 0;
662
+ if (suspensionData) {
663
+ const toolName = "toolName" in part && typeof part.toolName === "string" ? part.toolName : part.type.startsWith("tool-") ? part.type.substring(5) : "";
664
+ return {
665
+ type: "tool-call",
666
+ toolCallId: partToolCallId,
667
+ toolName,
668
+ argsText: "input" in part ? JSON.stringify(part.input) : "{}",
669
+ args: "input" in part ? part.input : {},
670
+ metadata: extendedMessage.metadata
671
+ };
672
+ }
511
673
  return {
512
674
  type: "text",
513
675
  text: "",
@@ -547,9 +709,127 @@ const toAssistantUIMessage = (message) => {
547
709
  return threadMessage;
548
710
  };
549
711
 
712
+ const resolveInitialMessages = (messages) => {
713
+ return messages.map((message) => {
714
+ const networkPart = message.parts.find((part) => part.type === "text" && part.text.includes('"isNetwork":true'));
715
+ if (networkPart && networkPart.type === "text") {
716
+ try {
717
+ const json = JSON.parse(networkPart.text);
718
+ if (json.isNetwork === true) {
719
+ const selectionReason = json.selectionReason || "";
720
+ const primitiveType = json.primitiveType || "";
721
+ const primitiveId = json.primitiveId || "";
722
+ const finalResult = json.finalResult;
723
+ const toolCalls = finalResult?.toolCalls || [];
724
+ const childMessages = [];
725
+ for (const toolCall of toolCalls) {
726
+ if (toolCall.type === "tool-call" && toolCall.payload) {
727
+ const toolCallId = toolCall.payload.toolCallId;
728
+ let toolResult;
729
+ for (const message2 of finalResult?.messages || []) {
730
+ for (const part of message2.content || []) {
731
+ if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
732
+ toolResult = part;
733
+ break;
734
+ }
735
+ }
736
+ }
737
+ const isWorkflow = Boolean(toolResult?.result?.result?.steps);
738
+ childMessages.push({
739
+ type: "tool",
740
+ toolCallId: toolCall.payload.toolCallId,
741
+ toolName: toolCall.payload.toolName,
742
+ args: toolCall.payload.args,
743
+ toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
744
+ });
745
+ }
746
+ }
747
+ if (finalResult && finalResult.text) {
748
+ childMessages.push({
749
+ type: "text",
750
+ content: finalResult.text
751
+ });
752
+ }
753
+ const result = {
754
+ childMessages,
755
+ result: finalResult?.text || ""
756
+ };
757
+ const nextMessage = {
758
+ role: "assistant",
759
+ parts: [
760
+ {
761
+ type: "dynamic-tool",
762
+ toolCallId: primitiveId,
763
+ toolName: primitiveId,
764
+ state: "output-available",
765
+ input: json.input,
766
+ output: result
767
+ }
768
+ ],
769
+ id: message.id,
770
+ metadata: {
771
+ ...message.metadata,
772
+ mode: "network",
773
+ selectionReason,
774
+ agentInput: json.input,
775
+ from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
776
+ }
777
+ };
778
+ return nextMessage;
779
+ }
780
+ } catch (error) {
781
+ return message;
782
+ }
783
+ }
784
+ const extendedMessage = message;
785
+ const pendingToolApprovals = extendedMessage.metadata?.pendingToolApprovals;
786
+ if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
787
+ return {
788
+ ...message,
789
+ metadata: {
790
+ ...message.metadata,
791
+ mode: "stream",
792
+ requireApprovalMetadata: pendingToolApprovals
793
+ }
794
+ };
795
+ }
796
+ return message;
797
+ });
798
+ };
799
+ const resolveToChildMessages = (messages) => {
800
+ const assistantMessage = messages.find((message) => message.role === "assistant");
801
+ if (!assistantMessage) return [];
802
+ const parts = assistantMessage.parts;
803
+ let childMessages = [];
804
+ for (const part of parts) {
805
+ const toolPart = part;
806
+ if (part.type.startsWith("tool-")) {
807
+ const toolName = part.type.substring("tool-".length);
808
+ const isWorkflow = toolName.startsWith("workflow-");
809
+ childMessages.push({
810
+ type: "tool",
811
+ toolCallId: toolPart.toolCallId,
812
+ toolName,
813
+ args: toolPart.input,
814
+ toolOutput: isWorkflow ? { ...toolPart.output?.result, runId: toolPart.output?.runId } : toolPart.output
815
+ });
816
+ }
817
+ if (part.type === "text") {
818
+ childMessages.push({
819
+ type: "text",
820
+ content: toolPart.text
821
+ });
822
+ }
823
+ }
824
+ return childMessages;
825
+ };
826
+
550
827
  class AISdkNetworkTransformer {
551
828
  transform({ chunk, conversation, metadata }) {
552
829
  const newConversation = [...conversation];
830
+ if (chunk.type === "routing-agent-text-delta") {
831
+ return this.handleRoutingAgentConversation(chunk, newConversation);
832
+ }
553
833
  if (chunk.type.startsWith("agent-execution-")) {
554
834
  return this.handleAgentConversation(chunk, newConversation, metadata);
555
835
  }
@@ -560,22 +840,80 @@ class AISdkNetworkTransformer {
560
840
  return this.handleToolConversation(chunk, newConversation, metadata);
561
841
  }
562
842
  if (chunk.type === "network-execution-event-step-finish") {
563
- const newMessage = {
564
- id: `network-execution-event-step-finish-${chunk.runId}-${Date.now()}`,
565
- role: "assistant",
566
- parts: [
843
+ const lastMessage = newConversation[newConversation.length - 1];
844
+ if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
845
+ const agentChunk = chunk.payload;
846
+ const parts = [...lastMessage.parts];
847
+ const textPartIndex = parts.findIndex((part) => part.type === "text");
848
+ if (textPartIndex === -1) {
849
+ parts.push({
850
+ type: "text",
851
+ text: agentChunk.result,
852
+ state: "done"
853
+ });
854
+ return [
855
+ ...newConversation.slice(0, -1),
567
856
  {
568
- type: "text",
569
- text: chunk.payload?.result || "",
570
- state: "done"
857
+ ...lastMessage,
858
+ parts
571
859
  }
572
- ],
573
- metadata
574
- };
575
- return [...newConversation, newMessage];
860
+ ];
861
+ }
862
+ const textPart = parts[textPartIndex];
863
+ if (textPart.type === "text") {
864
+ parts[textPartIndex] = {
865
+ ...textPart,
866
+ state: "done"
867
+ };
868
+ return [
869
+ ...newConversation.slice(0, -1),
870
+ {
871
+ ...lastMessage,
872
+ parts
873
+ }
874
+ ];
875
+ }
876
+ return newConversation;
576
877
  }
577
878
  return newConversation;
578
879
  }
880
+ handleRoutingAgentConversation = (chunk, newConversation) => {
881
+ const lastMessage = newConversation[newConversation.length - 1];
882
+ if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
883
+ const agentChunk = chunk.payload;
884
+ const parts = [...lastMessage.parts];
885
+ const textPartIndex = parts.findIndex((part) => part.type === "text");
886
+ if (textPartIndex === -1) {
887
+ parts.push({
888
+ type: "text",
889
+ text: agentChunk.text,
890
+ state: "streaming"
891
+ });
892
+ return [
893
+ ...newConversation.slice(0, -1),
894
+ {
895
+ ...lastMessage,
896
+ parts
897
+ }
898
+ ];
899
+ }
900
+ const textPart = parts[textPartIndex];
901
+ if (textPart.type === "text") {
902
+ parts[textPartIndex] = {
903
+ ...textPart,
904
+ text: textPart.text + agentChunk.text,
905
+ state: "streaming"
906
+ };
907
+ return [
908
+ ...newConversation.slice(0, -1),
909
+ {
910
+ ...lastMessage,
911
+ parts
912
+ }
913
+ ];
914
+ }
915
+ return newConversation;
916
+ };
579
917
  handleAgentConversation = (chunk, newConversation, metadata) => {
580
918
  if (chunk.type === "agent-execution-start") {
581
919
  const primitiveId = chunk.payload?.args?.primitiveId;
@@ -858,87 +1196,25 @@ class AISdkNetworkTransformer {
858
1196
  };
859
1197
  }
860
1198
 
861
- const resolveInitialMessages = (messages) => {
862
- return messages.map((message) => {
863
- const networkPart = message.parts.find((part) => part.type === "text" && part.text.includes('"isNetwork":true'));
864
- if (networkPart && networkPart.type === "text") {
865
- try {
866
- const json = JSON.parse(networkPart.text);
867
- if (json.isNetwork === true) {
868
- const selectionReason = json.selectionReason || "";
869
- const primitiveType = json.primitiveType || "";
870
- const primitiveId = json.primitiveId || "";
871
- const finalResult = json.finalResult;
872
- const toolCalls = finalResult?.toolCalls || [];
873
- const childMessages = [];
874
- for (const toolCall of toolCalls) {
875
- if (toolCall.type === "tool-call" && toolCall.payload) {
876
- const toolCallId = toolCall.payload.toolCallId;
877
- let toolResult;
878
- for (const message2 of finalResult?.messages || []) {
879
- for (const part of message2.content || []) {
880
- if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
881
- toolResult = part;
882
- break;
883
- }
884
- }
885
- }
886
- const isWorkflow = Boolean(toolResult?.result?.result?.steps);
887
- childMessages.push({
888
- type: "tool",
889
- toolCallId: toolCall.payload.toolCallId,
890
- toolName: toolCall.payload.toolName,
891
- args: toolCall.payload.args,
892
- toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
893
- });
894
- }
895
- }
896
- if (finalResult && finalResult.text) {
897
- childMessages.push({
898
- type: "text",
899
- content: finalResult.text
900
- });
901
- }
902
- const result = {
903
- childMessages,
904
- result: finalResult?.text || ""
905
- };
906
- console.log("json", json);
907
- const nextMessage = {
908
- role: "assistant",
909
- parts: [
910
- {
911
- type: "dynamic-tool",
912
- toolCallId: primitiveId,
913
- toolName: primitiveId,
914
- state: "output-available",
915
- input: json.input,
916
- output: result
917
- }
918
- ],
919
- id: message.id,
920
- metadata: {
921
- ...message.metadata,
922
- mode: "network",
923
- selectionReason,
924
- agentInput: json.input,
925
- from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
926
- }
927
- };
928
- return nextMessage;
1199
+ const useChat = ({ agentId, resourceId, initializeMessages }) => {
1200
+ const extractRunIdFromMessages = (messages2) => {
1201
+ for (const message of messages2) {
1202
+ const pendingToolApprovals = message.metadata?.pendingToolApprovals;
1203
+ if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
1204
+ const suspensionData = Object.values(pendingToolApprovals)[0];
1205
+ if (suspensionData?.runId) {
1206
+ return suspensionData.runId;
929
1207
  }
930
- } catch (error) {
931
- return message;
932
1208
  }
933
1209
  }
934
- return message;
935
- });
936
- };
937
-
938
- const useChat = ({ agentId, initializeMessages }) => {
939
- const [messages, setMessages] = useState(
940
- () => resolveInitialMessages(initializeMessages?.() || [])
941
- );
1210
+ return void 0;
1211
+ };
1212
+ const initialMessages = initializeMessages?.() || [];
1213
+ const initialRunId = extractRunIdFromMessages(initialMessages);
1214
+ const _currentRunId = useRef(initialRunId);
1215
+ const _onChunk = useRef(void 0);
1216
+ const [messages, setMessages] = useState(() => resolveInitialMessages(initialMessages));
1217
+ const [toolCallApprovals, setToolCallApprovals] = useState({});
942
1218
  const baseClient = useMastraClient();
943
1219
  const [isRunning, setIsRunning] = useState(false);
944
1220
  const generate = async ({
@@ -969,7 +1245,7 @@ const useChat = ({ agentId, initializeMessages }) => {
969
1245
  const agent = clientWithAbort.getAgent(agentId);
970
1246
  const response = await agent.generate({
971
1247
  messages: coreUserMessages,
972
- runId: agentId,
1248
+ runId: v4(),
973
1249
  maxSteps,
974
1250
  modelSettings: {
975
1251
  frequencyPenalty,
@@ -982,7 +1258,7 @@ const useChat = ({ agentId, initializeMessages }) => {
982
1258
  },
983
1259
  instructions,
984
1260
  runtimeContext,
985
- ...threadId ? { threadId, resourceId: agentId } : {},
1261
+ ...threadId ? { threadId, resourceId: resourceId || agentId } : {},
986
1262
  providerOptions
987
1263
  });
988
1264
  setIsRunning(false);
@@ -1008,7 +1284,8 @@ const useChat = ({ agentId, initializeMessages }) => {
1008
1284
  topP,
1009
1285
  instructions,
1010
1286
  providerOptions,
1011
- maxSteps
1287
+ maxSteps,
1288
+ requireToolApproval
1012
1289
  } = modelSettings || {};
1013
1290
  setIsRunning(true);
1014
1291
  const clientWithAbort = new MastraClient({
@@ -1016,9 +1293,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1016
1293
  abortSignal: signal
1017
1294
  });
1018
1295
  const agent = clientWithAbort.getAgent(agentId);
1296
+ const runId = v4();
1019
1297
  const response = await agent.stream({
1020
1298
  messages: coreUserMessages,
1021
- runId: agentId,
1299
+ runId,
1022
1300
  maxSteps,
1023
1301
  modelSettings: {
1024
1302
  frequencyPenalty,
@@ -1031,18 +1309,15 @@ const useChat = ({ agentId, initializeMessages }) => {
1031
1309
  },
1032
1310
  instructions,
1033
1311
  runtimeContext,
1034
- ...threadId ? { threadId, resourceId: agentId } : {},
1035
- providerOptions
1312
+ ...threadId ? { threadId, resourceId: resourceId || agentId } : {},
1313
+ providerOptions,
1314
+ requireToolApproval
1036
1315
  });
1037
- if (!response.body) {
1038
- setIsRunning(false);
1039
- throw new Error("[Stream] No response body");
1040
- }
1316
+ _onChunk.current = onChunk;
1317
+ _currentRunId.current = runId;
1041
1318
  await response.processDataStream({
1042
1319
  onChunk: async (chunk) => {
1043
- flushSync(() => {
1044
- setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1045
- });
1320
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1046
1321
  onChunk?.(chunk);
1047
1322
  }
1048
1323
  });
@@ -1063,6 +1338,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1063
1338
  abortSignal: signal
1064
1339
  });
1065
1340
  const agent = clientWithAbort.getAgent(agentId);
1341
+ const runId = v4();
1066
1342
  const response = await agent.network({
1067
1343
  messages: coreUserMessages,
1068
1344
  maxSteps,
@@ -1075,21 +1351,58 @@ const useChat = ({ agentId, initializeMessages }) => {
1075
1351
  topK,
1076
1352
  topP
1077
1353
  },
1078
- runId: agentId,
1354
+ runId,
1079
1355
  runtimeContext,
1080
- ...threadId ? { thread: threadId, resourceId: agentId } : {}
1356
+ ...threadId ? { thread: threadId, resourceId: resourceId || agentId } : {}
1081
1357
  });
1082
1358
  const transformer = new AISdkNetworkTransformer();
1083
1359
  await response.processDataStream({
1084
1360
  onChunk: async (chunk) => {
1085
- flushSync(() => {
1086
- setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1087
- });
1361
+ setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1088
1362
  onNetworkChunk?.(chunk);
1089
1363
  }
1090
1364
  });
1091
1365
  setIsRunning(false);
1092
1366
  };
1367
+ const handleCancelRun = () => {
1368
+ setIsRunning(false);
1369
+ _currentRunId.current = void 0;
1370
+ _onChunk.current = void 0;
1371
+ };
1372
+ const approveToolCall = async (toolCallId) => {
1373
+ const onChunk = _onChunk.current;
1374
+ const currentRunId = _currentRunId.current;
1375
+ if (!currentRunId)
1376
+ return console.info("[approveToolCall] approveToolCall can only be called after a stream has started");
1377
+ setIsRunning(true);
1378
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "approved" } }));
1379
+ const agent = baseClient.getAgent(agentId);
1380
+ const response = await agent.approveToolCall({ runId: currentRunId, toolCallId });
1381
+ await response.processDataStream({
1382
+ onChunk: async (chunk) => {
1383
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1384
+ onChunk?.(chunk);
1385
+ }
1386
+ });
1387
+ setIsRunning(false);
1388
+ };
1389
+ const declineToolCall = async (toolCallId) => {
1390
+ const onChunk = _onChunk.current;
1391
+ const currentRunId = _currentRunId.current;
1392
+ if (!currentRunId)
1393
+ return console.info("[declineToolCall] declineToolCall can only be called after a stream has started");
1394
+ setIsRunning(true);
1395
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "declined" } }));
1396
+ const agent = baseClient.getAgent(agentId);
1397
+ const response = await agent.declineToolCall({ runId: currentRunId, toolCallId });
1398
+ await response.processDataStream({
1399
+ onChunk: async (chunk) => {
1400
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1401
+ onChunk?.(chunk);
1402
+ }
1403
+ });
1404
+ setIsRunning(false);
1405
+ };
1093
1406
  const sendMessage = async ({ mode = "stream", ...args }) => {
1094
1407
  const nextMessage = { role: "user", content: [{ type: "text", text: args.message }] };
1095
1408
  const messages2 = args.coreUserMessages ? [nextMessage, ...args.coreUserMessages] : [nextMessage];
@@ -1107,7 +1420,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1107
1420
  sendMessage,
1108
1421
  isRunning,
1109
1422
  messages,
1110
- cancelRun: () => setIsRunning(false)
1423
+ approveToolCall,
1424
+ declineToolCall,
1425
+ cancelRun: handleCancelRun,
1426
+ toolCallApprovals
1111
1427
  };
1112
1428
  };
1113
1429
 
@@ -1426,5 +1742,5 @@ const MessageStreaming = ({ className, ...props }) => {
1426
1742
  return /* @__PURE__ */ jsx("span", { className: className || MessageStreamingClass, ...props });
1427
1743
  };
1428
1744
 
1429
- export { AgentIcon, CodeBlock, CodeBlockClass, CodeCopyButton, Entity, EntityCaret, EntityContent, EntityContentClass, EntityTrigger, EntityTriggerClass, EntityTriggerVariantClasses, Entry, EntryClass, EntryTitle, EntryTitleClass, Icon, IconButton, IconButtonClass, IconSizes, MastraReactProvider, Message, MessageActions, MessageActionsClass, MessageClass, MessageContent, MessageContentClass, MessageList, MessageListClass, MessageStreaming, MessageStreamingClass, MessageUsage, MessageUsageClass, MessageUsageEntry, MessageUsageEntryClass, MessageUsageValue, MessageUsageValueClass, MessageUsages, MessageUsagesClass, ToolApproval, ToolApprovalActions, ToolApprovalActionsClass, ToolApprovalClass, ToolApprovalContent, ToolApprovalContentClass, ToolApprovalHeader, ToolApprovalHeaderClass, ToolApprovalTitle, ToolApprovalTitleClass, ToolsIcon, Tooltip, TooltipContent, TooltipContentClass, TooltipTrigger, WorkflowIcon, mapWorkflowStreamChunkToWatchResult, toAssistantUIMessage, toUIMessage, useChat, useEntity, useMastraClient };
1745
+ export { AgentIcon, CodeBlock, CodeBlockClass, CodeCopyButton, Entity, EntityCaret, EntityContent, EntityContentClass, EntityTrigger, EntityTriggerClass, EntityTriggerVariantClasses, Entry, EntryClass, EntryTitle, EntryTitleClass, Icon, IconButton, IconButtonClass, IconSizes, MastraReactProvider, Message, MessageActions, MessageActionsClass, MessageClass, MessageContent, MessageContentClass, MessageList, MessageListClass, MessageStreaming, MessageStreamingClass, MessageUsage, MessageUsageClass, MessageUsageEntry, MessageUsageEntryClass, MessageUsageValue, MessageUsageValueClass, MessageUsages, MessageUsagesClass, ToolApproval, ToolApprovalActions, ToolApprovalActionsClass, ToolApprovalClass, ToolApprovalContent, ToolApprovalContentClass, ToolApprovalHeader, ToolApprovalHeaderClass, ToolApprovalTitle, ToolApprovalTitleClass, ToolsIcon, Tooltip, TooltipContent, TooltipContentClass, TooltipTrigger, WorkflowIcon, mapWorkflowStreamChunkToWatchResult, resolveToChildMessages, toAssistantUIMessage, toUIMessage, useChat, useEntity, useMastraClient };
1430
1746
  //# sourceMappingURL=index.js.map