@mastra/react 0.0.0-monorepo-binary-20251013210052 → 0.0.0-playground-studio-again-20251114100107

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,6 @@
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';
5
4
  import { ChevronDownIcon, CheckIcon, CopyIcon } from 'lucide-react';
6
5
  import { twMerge } from 'tailwind-merge';
7
6
  import { toJsxRuntime } from 'hast-util-to-jsx-runtime';
@@ -250,6 +249,7 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
250
249
  }
251
250
  ];
252
251
  }
252
+ case "tool-error":
253
253
  case "tool-result": {
254
254
  const lastMessage = result[result.length - 1];
255
255
  if (!lastMessage || lastMessage.role !== "assistant") return result;
@@ -260,25 +260,35 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
260
260
  if (toolPartIndex !== -1) {
261
261
  const toolPart = parts[toolPartIndex];
262
262
  if (toolPart.type === "dynamic-tool") {
263
- if (chunk.payload.isError) {
263
+ if (chunk.type === "tool-result" && chunk.payload.isError || chunk.type === "tool-error") {
264
+ const error = chunk.type === "tool-error" ? chunk.payload.error : chunk.payload.result;
264
265
  parts[toolPartIndex] = {
265
266
  type: "dynamic-tool",
266
267
  toolName: toolPart.toolName,
267
268
  toolCallId: toolPart.toolCallId,
268
269
  state: "output-error",
269
270
  input: toolPart.input,
270
- errorText: String(chunk.payload.result),
271
+ errorText: String(error),
271
272
  callProviderMetadata: chunk.payload.providerMetadata
272
273
  };
273
274
  } else {
274
275
  const isWorkflow = Boolean(chunk.payload.result?.result?.steps);
276
+ const isAgent = chunk?.from === "AGENT";
277
+ let output;
278
+ if (isWorkflow) {
279
+ output = chunk.payload.result?.result;
280
+ } else if (isAgent) {
281
+ output = parts[toolPartIndex].output ?? chunk.payload.result;
282
+ } else {
283
+ output = chunk.payload.result;
284
+ }
275
285
  parts[toolPartIndex] = {
276
286
  type: "dynamic-tool",
277
287
  toolName: toolPart.toolName,
278
288
  toolCallId: toolPart.toolCallId,
279
289
  state: "output-available",
280
290
  input: toolPart.input,
281
- output: isWorkflow ? chunk.payload.result?.result : chunk.payload.result,
291
+ output,
282
292
  callProviderMetadata: chunk.payload.providerMetadata
283
293
  };
284
294
  }
@@ -312,6 +322,8 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
312
322
  ...toolPart,
313
323
  output: updatedWorkflowState
314
324
  };
325
+ } else if (chunk.payload.output?.from === "AGENT" || chunk.payload.output?.from === "USER" && chunk.payload.output?.payload?.output?.type?.startsWith("workflow-")) {
326
+ return toUIMessageFromAgent(chunk.payload.output, conversation);
315
327
  } else {
316
328
  const currentOutput = toolPart.output || [];
317
329
  const existingOutput = Array.isArray(currentOutput) ? currentOutput : [];
@@ -385,15 +397,37 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
385
397
  }
386
398
  ];
387
399
  }
400
+ case "tool-call-approval": {
401
+ const lastMessage = result[result.length - 1];
402
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
403
+ const lastRequireApprovalMetadata = lastMessage.metadata?.mode === "stream" ? lastMessage.metadata?.requireApprovalMetadata : {};
404
+ return [
405
+ ...result.slice(0, -1),
406
+ {
407
+ ...lastMessage,
408
+ metadata: {
409
+ ...lastMessage.metadata,
410
+ mode: "stream",
411
+ requireApprovalMetadata: {
412
+ ...lastRequireApprovalMetadata,
413
+ [chunk.payload.toolCallId]: {
414
+ toolCallId: chunk.payload.toolCallId,
415
+ toolName: chunk.payload.toolName,
416
+ args: chunk.payload.args
417
+ }
418
+ }
419
+ }
420
+ }
421
+ ];
422
+ }
388
423
  case "finish": {
389
424
  const lastMessage = result[result.length - 1];
390
425
  if (!lastMessage || lastMessage.role !== "assistant") return result;
391
426
  const parts = lastMessage.parts.map((part) => {
392
- if (part.type === "text" && part.state === "streaming") {
393
- return { ...part, state: "done" };
394
- }
395
- if (part.type === "reasoning" && part.state === "streaming") {
396
- return { ...part, state: "done" };
427
+ if (typeof part === "object" && part !== null && "type" in part && "state" in part && part.state === "streaming") {
428
+ if (part.type === "text" || part.type === "reasoning") {
429
+ return { ...part, state: "done" };
430
+ }
397
431
  }
398
432
  return part;
399
433
  });
@@ -427,6 +461,105 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
427
461
  return result;
428
462
  }
429
463
  };
464
+ const toUIMessageFromAgent = (chunk, conversation, metadata) => {
465
+ const lastMessage = conversation[conversation.length - 1];
466
+ if (!lastMessage || lastMessage.role !== "assistant") return conversation;
467
+ const parts = [...lastMessage.parts];
468
+ if (chunk.type === "text-delta") {
469
+ const agentChunk = chunk.payload;
470
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
471
+ if (toolPartIndex === -1) return conversation;
472
+ const toolPart = parts[toolPartIndex];
473
+ const childMessages = toolPart?.output?.childMessages || [];
474
+ const lastChildMessage = childMessages[childMessages.length - 1];
475
+ const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
476
+ const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
477
+ parts[toolPartIndex] = {
478
+ ...toolPart,
479
+ output: {
480
+ childMessages: nextMessages
481
+ }
482
+ };
483
+ } else if (chunk.type === "tool-call") {
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
+ parts[toolPartIndex] = {
490
+ ...toolPart,
491
+ output: {
492
+ ...toolPart?.output,
493
+ childMessages: [
494
+ ...childMessages,
495
+ {
496
+ type: "tool",
497
+ toolCallId: agentChunk.toolCallId,
498
+ toolName: agentChunk.toolName,
499
+ args: agentChunk.args
500
+ }
501
+ ]
502
+ }
503
+ };
504
+ } else if (chunk.type === "tool-output") {
505
+ const agentChunk = chunk.payload;
506
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
507
+ if (toolPartIndex === -1) return conversation;
508
+ const toolPart = parts[toolPartIndex];
509
+ if (agentChunk?.output?.type?.startsWith("workflow-")) {
510
+ const childMessages = toolPart?.output?.childMessages || [];
511
+ const lastToolIndex = childMessages.length - 1;
512
+ const currentMessage = childMessages[lastToolIndex];
513
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
514
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
515
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
516
+ parts[toolPartIndex] = {
517
+ ...toolPart,
518
+ output: {
519
+ ...toolPart?.output,
520
+ childMessages: [
521
+ ...childMessages.slice(0, -1),
522
+ {
523
+ ...currentMessage,
524
+ toolOutput: { ...updatedWorkflowState, runId: agentChunk.output.runId }
525
+ }
526
+ ]
527
+ }
528
+ };
529
+ }
530
+ }
531
+ } else if (chunk.type === "tool-result") {
532
+ const agentChunk = chunk.payload;
533
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
534
+ if (toolPartIndex === -1) return conversation;
535
+ const toolPart = parts[toolPartIndex];
536
+ const childMessages = toolPart?.output?.childMessages || [];
537
+ const lastToolIndex = childMessages.length - 1;
538
+ const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
539
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
540
+ parts[toolPartIndex] = {
541
+ ...toolPart,
542
+ output: {
543
+ ...toolPart?.output,
544
+ childMessages: [
545
+ ...childMessages.slice(0, -1),
546
+ {
547
+ ...childMessages[lastToolIndex],
548
+ toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
549
+ }
550
+ ]
551
+ }
552
+ };
553
+ }
554
+ }
555
+ return [
556
+ ...conversation.slice(0, -1),
557
+ {
558
+ ...lastMessage,
559
+ parts
560
+ }
561
+ ];
562
+ };
430
563
 
431
564
  const toAssistantUIMessage = (message) => {
432
565
  const extendedMessage = message;
@@ -466,13 +599,23 @@ const toAssistantUIMessage = (message) => {
466
599
  };
467
600
  }
468
601
  if (part.type === "file") {
469
- return {
470
- type: "file",
471
- mimeType: part.mediaType,
472
- data: part.url,
473
- // Use URL as data source
474
- metadata: message.metadata
475
- };
602
+ const type = part.mediaType.includes("image/") ? "image" : "file";
603
+ if (type === "file") {
604
+ return {
605
+ type,
606
+ mimeType: part.mediaType,
607
+ data: part.url,
608
+ // Use URL as data source
609
+ metadata: message.metadata
610
+ };
611
+ }
612
+ if (type === "image") {
613
+ return {
614
+ type,
615
+ image: part.url,
616
+ metadata: message.metadata
617
+ };
618
+ }
476
619
  }
477
620
  if (part.type === "dynamic-tool") {
478
621
  const baseToolCall = {
@@ -547,9 +690,118 @@ const toAssistantUIMessage = (message) => {
547
690
  return threadMessage;
548
691
  };
549
692
 
693
+ const resolveInitialMessages = (messages) => {
694
+ return messages.map((message) => {
695
+ const networkPart = message.parts.find(
696
+ (part) => typeof part === "object" && part !== null && "type" in part && part.type === "text" && "text" in part && typeof part.text === "string" && part.text.includes('"isNetwork":true')
697
+ );
698
+ if (networkPart && networkPart.type === "text") {
699
+ try {
700
+ const json = JSON.parse(networkPart.text);
701
+ if (json.isNetwork === true) {
702
+ const selectionReason = json.selectionReason || "";
703
+ const primitiveType = json.primitiveType || "";
704
+ const primitiveId = json.primitiveId || "";
705
+ const finalResult = json.finalResult;
706
+ const toolCalls = finalResult?.toolCalls || [];
707
+ const childMessages = [];
708
+ for (const toolCall of toolCalls) {
709
+ if (toolCall.type === "tool-call" && toolCall.payload) {
710
+ const toolCallId = toolCall.payload.toolCallId;
711
+ let toolResult;
712
+ for (const message2 of finalResult?.messages || []) {
713
+ for (const part of message2.content || []) {
714
+ if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
715
+ toolResult = part;
716
+ break;
717
+ }
718
+ }
719
+ }
720
+ const isWorkflow = Boolean(toolResult?.result?.result?.steps);
721
+ childMessages.push({
722
+ type: "tool",
723
+ toolCallId: toolCall.payload.toolCallId,
724
+ toolName: toolCall.payload.toolName,
725
+ args: toolCall.payload.args,
726
+ toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
727
+ });
728
+ }
729
+ }
730
+ if (finalResult && finalResult.text) {
731
+ childMessages.push({
732
+ type: "text",
733
+ content: finalResult.text
734
+ });
735
+ }
736
+ const result = {
737
+ childMessages,
738
+ result: finalResult?.text || ""
739
+ };
740
+ console.log("json", json);
741
+ const nextMessage = {
742
+ role: "assistant",
743
+ parts: [
744
+ {
745
+ type: "dynamic-tool",
746
+ toolCallId: primitiveId,
747
+ toolName: primitiveId,
748
+ state: "output-available",
749
+ input: json.input,
750
+ output: result
751
+ }
752
+ ],
753
+ id: message.id,
754
+ metadata: {
755
+ ...message.metadata,
756
+ mode: "network",
757
+ selectionReason,
758
+ agentInput: json.input,
759
+ from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
760
+ }
761
+ };
762
+ return nextMessage;
763
+ }
764
+ } catch (error) {
765
+ return message;
766
+ }
767
+ }
768
+ return message;
769
+ });
770
+ };
771
+ const resolveToChildMessages = (messages) => {
772
+ const assistantMessage = messages.find((message) => message.role === "assistant");
773
+ if (!assistantMessage) return [];
774
+ const parts = assistantMessage.parts;
775
+ let childMessages = [];
776
+ for (const part of parts) {
777
+ const toolPart = part;
778
+ if (part.type.startsWith("tool-")) {
779
+ const toolName = part.type.substring("tool-".length);
780
+ const isWorkflow = toolName.startsWith("workflow-");
781
+ childMessages.push({
782
+ type: "tool",
783
+ toolCallId: toolPart.toolCallId,
784
+ toolName,
785
+ args: toolPart.input,
786
+ toolOutput: isWorkflow ? { ...toolPart.output?.result, runId: toolPart.output?.runId } : toolPart.output
787
+ });
788
+ }
789
+ if (part.type === "text") {
790
+ childMessages.push({
791
+ type: "text",
792
+ content: toolPart.text
793
+ });
794
+ }
795
+ }
796
+ return childMessages;
797
+ };
798
+
550
799
  class AISdkNetworkTransformer {
551
800
  transform({ chunk, conversation, metadata }) {
552
801
  const newConversation = [...conversation];
802
+ if (chunk.type === "routing-agent-text-delta") {
803
+ return this.handleRoutingAgentConversation(chunk, newConversation);
804
+ }
553
805
  if (chunk.type.startsWith("agent-execution-")) {
554
806
  return this.handleAgentConversation(chunk, newConversation, metadata);
555
807
  }
@@ -560,22 +812,80 @@ class AISdkNetworkTransformer {
560
812
  return this.handleToolConversation(chunk, newConversation, metadata);
561
813
  }
562
814
  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: [
815
+ const lastMessage = newConversation[newConversation.length - 1];
816
+ if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
817
+ const agentChunk = chunk.payload;
818
+ const parts = [...lastMessage.parts];
819
+ const textPartIndex = parts.findIndex((part) => part.type === "text");
820
+ if (textPartIndex === -1) {
821
+ parts.push({
822
+ type: "text",
823
+ text: agentChunk.result,
824
+ state: "done"
825
+ });
826
+ return [
827
+ ...newConversation.slice(0, -1),
567
828
  {
568
- type: "text",
569
- text: chunk.payload?.result || "",
570
- state: "done"
829
+ ...lastMessage,
830
+ parts
571
831
  }
572
- ],
573
- metadata
574
- };
575
- return [...newConversation, newMessage];
832
+ ];
833
+ }
834
+ const textPart = parts[textPartIndex];
835
+ if (textPart.type === "text") {
836
+ parts[textPartIndex] = {
837
+ ...textPart,
838
+ state: "done"
839
+ };
840
+ return [
841
+ ...newConversation.slice(0, -1),
842
+ {
843
+ ...lastMessage,
844
+ parts
845
+ }
846
+ ];
847
+ }
848
+ return newConversation;
576
849
  }
577
850
  return newConversation;
578
851
  }
852
+ handleRoutingAgentConversation = (chunk, newConversation) => {
853
+ const lastMessage = newConversation[newConversation.length - 1];
854
+ if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
855
+ const agentChunk = chunk.payload;
856
+ const parts = [...lastMessage.parts];
857
+ const textPartIndex = parts.findIndex((part) => part.type === "text");
858
+ if (textPartIndex === -1) {
859
+ parts.push({
860
+ type: "text",
861
+ text: agentChunk.text,
862
+ state: "streaming"
863
+ });
864
+ return [
865
+ ...newConversation.slice(0, -1),
866
+ {
867
+ ...lastMessage,
868
+ parts
869
+ }
870
+ ];
871
+ }
872
+ const textPart = parts[textPartIndex];
873
+ if (textPart.type === "text") {
874
+ parts[textPartIndex] = {
875
+ ...textPart,
876
+ text: textPart.text + agentChunk.text,
877
+ state: "streaming"
878
+ };
879
+ return [
880
+ ...newConversation.slice(0, -1),
881
+ {
882
+ ...lastMessage,
883
+ parts
884
+ }
885
+ ];
886
+ }
887
+ return newConversation;
888
+ };
579
889
  handleAgentConversation = (chunk, newConversation, metadata) => {
580
890
  if (chunk.type === "agent-execution-start") {
581
891
  const primitiveId = chunk.payload?.args?.primitiveId;
@@ -858,92 +1168,63 @@ class AISdkNetworkTransformer {
858
1168
  };
859
1169
  }
860
1170
 
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;
929
- }
930
- } catch (error) {
931
- return message;
1171
+ const fromCoreUserMessageToUIMessage = (coreUserMessage) => {
1172
+ const id = `user-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1173
+ const parts = typeof coreUserMessage.content === "string" ? [
1174
+ {
1175
+ type: "text",
1176
+ text: coreUserMessage.content
1177
+ }
1178
+ ] : coreUserMessage.content.map((part) => {
1179
+ switch (part.type) {
1180
+ case "text": {
1181
+ return {
1182
+ type: "text",
1183
+ text: part.text
1184
+ };
1185
+ }
1186
+ case "image": {
1187
+ const url = typeof part.image === "string" ? part.image : part.image instanceof URL ? part.image.toString() : "";
1188
+ return {
1189
+ type: "file",
1190
+ mediaType: part.mimeType ?? "image/*",
1191
+ url
1192
+ };
1193
+ }
1194
+ case "file": {
1195
+ const url = typeof part.data === "string" ? part.data : part.data instanceof URL ? part.data.toString() : "";
1196
+ return {
1197
+ type: "file",
1198
+ mediaType: part.mimeType,
1199
+ url,
1200
+ ...part.filename !== void 0 ? { filename: part.filename } : {}
1201
+ };
1202
+ }
1203
+ default: {
1204
+ const exhaustiveCheck = part;
1205
+ throw new Error(`Unhandled content part type: ${exhaustiveCheck.type}`);
932
1206
  }
933
1207
  }
934
- return message;
935
1208
  });
1209
+ return {
1210
+ id,
1211
+ role: "user",
1212
+ parts
1213
+ };
936
1214
  };
937
1215
 
938
1216
  const useChat = ({ agentId, initializeMessages }) => {
1217
+ const _currentRunId = useRef(void 0);
1218
+ const _onChunk = useRef(void 0);
939
1219
  const [messages, setMessages] = useState(
940
1220
  () => resolveInitialMessages(initializeMessages?.() || [])
941
1221
  );
1222
+ const [toolCallApprovals, setToolCallApprovals] = useState({});
942
1223
  const baseClient = useMastraClient();
943
1224
  const [isRunning, setIsRunning] = useState(false);
944
1225
  const generate = async ({
945
1226
  coreUserMessages,
946
- runtimeContext,
1227
+ requestContext,
947
1228
  threadId,
948
1229
  modelSettings,
949
1230
  signal,
@@ -981,7 +1262,7 @@ const useChat = ({ agentId, initializeMessages }) => {
981
1262
  topP
982
1263
  },
983
1264
  instructions,
984
- runtimeContext,
1265
+ requestContext,
985
1266
  ...threadId ? { threadId, resourceId: agentId } : {},
986
1267
  providerOptions
987
1268
  });
@@ -997,7 +1278,7 @@ const useChat = ({ agentId, initializeMessages }) => {
997
1278
  setMessages((prev) => [...prev, ...mastraUIMessages]);
998
1279
  }
999
1280
  };
1000
- const stream = async ({ coreUserMessages, runtimeContext, threadId, onChunk, modelSettings, signal }) => {
1281
+ const stream = async ({ coreUserMessages, requestContext, threadId, onChunk, modelSettings, signal }) => {
1001
1282
  const {
1002
1283
  frequencyPenalty,
1003
1284
  presencePenalty,
@@ -1008,7 +1289,8 @@ const useChat = ({ agentId, initializeMessages }) => {
1008
1289
  topP,
1009
1290
  instructions,
1010
1291
  providerOptions,
1011
- maxSteps
1292
+ maxSteps,
1293
+ requireToolApproval
1012
1294
  } = modelSettings || {};
1013
1295
  setIsRunning(true);
1014
1296
  const clientWithAbort = new MastraClient({
@@ -1016,9 +1298,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1016
1298
  abortSignal: signal
1017
1299
  });
1018
1300
  const agent = clientWithAbort.getAgent(agentId);
1301
+ const runId = agentId;
1019
1302
  const response = await agent.stream({
1020
1303
  messages: coreUserMessages,
1021
- runId: agentId,
1304
+ runId,
1022
1305
  maxSteps,
1023
1306
  modelSettings: {
1024
1307
  frequencyPenalty,
@@ -1030,19 +1313,16 @@ const useChat = ({ agentId, initializeMessages }) => {
1030
1313
  topP
1031
1314
  },
1032
1315
  instructions,
1033
- runtimeContext,
1316
+ requestContext,
1034
1317
  ...threadId ? { threadId, resourceId: agentId } : {},
1035
- providerOptions
1318
+ providerOptions,
1319
+ requireToolApproval
1036
1320
  });
1037
- if (!response.body) {
1038
- setIsRunning(false);
1039
- throw new Error("[Stream] No response body");
1040
- }
1321
+ _onChunk.current = onChunk;
1322
+ _currentRunId.current = runId;
1041
1323
  await response.processDataStream({
1042
1324
  onChunk: async (chunk) => {
1043
- flushSync(() => {
1044
- setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1045
- });
1325
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1046
1326
  onChunk?.(chunk);
1047
1327
  }
1048
1328
  });
@@ -1050,7 +1330,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1050
1330
  };
1051
1331
  const network = async ({
1052
1332
  coreUserMessages,
1053
- runtimeContext,
1333
+ requestContext,
1054
1334
  threadId,
1055
1335
  onNetworkChunk,
1056
1336
  modelSettings,
@@ -1076,30 +1356,71 @@ const useChat = ({ agentId, initializeMessages }) => {
1076
1356
  topP
1077
1357
  },
1078
1358
  runId: agentId,
1079
- runtimeContext,
1359
+ requestContext,
1080
1360
  ...threadId ? { thread: threadId, resourceId: agentId } : {}
1081
1361
  });
1082
1362
  const transformer = new AISdkNetworkTransformer();
1083
1363
  await response.processDataStream({
1084
1364
  onChunk: async (chunk) => {
1085
- flushSync(() => {
1086
- setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1087
- });
1365
+ setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1088
1366
  onNetworkChunk?.(chunk);
1089
1367
  }
1090
1368
  });
1091
1369
  setIsRunning(false);
1092
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
+ };
1093
1410
  const sendMessage = async ({ mode = "stream", ...args }) => {
1094
1411
  const nextMessage = { role: "user", content: [{ type: "text", text: args.message }] };
1095
- const messages2 = args.coreUserMessages ? [nextMessage, ...args.coreUserMessages] : [nextMessage];
1096
- setMessages((s) => [...s, { role: "user", parts: [{ type: "text", text: args.message }] }]);
1412
+ const coreUserMessages = [nextMessage];
1413
+ if (args.coreUserMessages) {
1414
+ coreUserMessages.push(...args.coreUserMessages);
1415
+ }
1416
+ const uiMessages = coreUserMessages.map(fromCoreUserMessageToUIMessage);
1417
+ setMessages((s) => [...s, ...uiMessages]);
1097
1418
  if (mode === "generate") {
1098
- await generate({ ...args, coreUserMessages: messages2 });
1419
+ await generate({ ...args, coreUserMessages });
1099
1420
  } else if (mode === "stream") {
1100
- await stream({ ...args, coreUserMessages: messages2 });
1421
+ await stream({ ...args, coreUserMessages });
1101
1422
  } else if (mode === "network") {
1102
- await network({ ...args, coreUserMessages: messages2 });
1423
+ await network({ ...args, coreUserMessages });
1103
1424
  }
1104
1425
  };
1105
1426
  return {
@@ -1107,7 +1428,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1107
1428
  sendMessage,
1108
1429
  isRunning,
1109
1430
  messages,
1110
- cancelRun: () => setIsRunning(false)
1431
+ approveToolCall,
1432
+ declineToolCall,
1433
+ cancelRun: handleCancelRun,
1434
+ toolCallApprovals
1111
1435
  };
1112
1436
  };
1113
1437
 
@@ -1426,5 +1750,5 @@ const MessageStreaming = ({ className, ...props }) => {
1426
1750
  return /* @__PURE__ */ jsx("span", { className: className || MessageStreamingClass, ...props });
1427
1751
  };
1428
1752
 
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 };
1753
+ 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
1754
  //# sourceMappingURL=index.js.map