@mastra/react 0.0.0-model-router-unknown-provider-20251017212006 → 0.0.0-netlify-no-bundle-20251127120354

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,15 +415,37 @@ 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;
395
444
  const parts = lastMessage.parts.map((part) => {
396
- if (part.type === "text" && part.state === "streaming") {
397
- return { ...part, state: "done" };
398
- }
399
- if (part.type === "reasoning" && part.state === "streaming") {
400
- return { ...part, state: "done" };
445
+ if (typeof part === "object" && part !== null && "type" in part && "state" in part && part.state === "streaming") {
446
+ if (part.type === "text" || part.type === "reasoning") {
447
+ return { ...part, state: "done" };
448
+ }
401
449
  }
402
450
  return part;
403
451
  });
@@ -431,6 +479,105 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
431
479
  return result;
432
480
  }
433
481
  };
482
+ const toUIMessageFromAgent = (chunk, conversation, metadata) => {
483
+ const lastMessage = conversation[conversation.length - 1];
484
+ if (!lastMessage || lastMessage.role !== "assistant") return conversation;
485
+ const parts = [...lastMessage.parts];
486
+ if (chunk.type === "text-delta") {
487
+ const agentChunk = chunk.payload;
488
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
489
+ if (toolPartIndex === -1) return conversation;
490
+ const toolPart = parts[toolPartIndex];
491
+ const childMessages = toolPart?.output?.childMessages || [];
492
+ const lastChildMessage = childMessages[childMessages.length - 1];
493
+ const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
494
+ const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
495
+ parts[toolPartIndex] = {
496
+ ...toolPart,
497
+ output: {
498
+ childMessages: nextMessages
499
+ }
500
+ };
501
+ } else if (chunk.type === "tool-call") {
502
+ const agentChunk = chunk.payload;
503
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
504
+ if (toolPartIndex === -1) return conversation;
505
+ const toolPart = parts[toolPartIndex];
506
+ const childMessages = toolPart?.output?.childMessages || [];
507
+ parts[toolPartIndex] = {
508
+ ...toolPart,
509
+ output: {
510
+ ...toolPart?.output,
511
+ childMessages: [
512
+ ...childMessages,
513
+ {
514
+ type: "tool",
515
+ toolCallId: agentChunk.toolCallId,
516
+ toolName: agentChunk.toolName,
517
+ args: agentChunk.args
518
+ }
519
+ ]
520
+ }
521
+ };
522
+ } else if (chunk.type === "tool-output") {
523
+ const agentChunk = chunk.payload;
524
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
525
+ if (toolPartIndex === -1) return conversation;
526
+ const toolPart = parts[toolPartIndex];
527
+ if (agentChunk?.output?.type?.startsWith("workflow-")) {
528
+ const childMessages = toolPart?.output?.childMessages || [];
529
+ const lastToolIndex = childMessages.length - 1;
530
+ const currentMessage = childMessages[lastToolIndex];
531
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
532
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
533
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
534
+ parts[toolPartIndex] = {
535
+ ...toolPart,
536
+ output: {
537
+ ...toolPart?.output,
538
+ childMessages: [
539
+ ...childMessages.slice(0, -1),
540
+ {
541
+ ...currentMessage,
542
+ toolOutput: { ...updatedWorkflowState, runId: agentChunk.output.runId }
543
+ }
544
+ ]
545
+ }
546
+ };
547
+ }
548
+ }
549
+ } else if (chunk.type === "tool-result") {
550
+ const agentChunk = chunk.payload;
551
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
552
+ if (toolPartIndex === -1) return conversation;
553
+ const toolPart = parts[toolPartIndex];
554
+ const childMessages = toolPart?.output?.childMessages || [];
555
+ const lastToolIndex = childMessages.length - 1;
556
+ const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
557
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
558
+ parts[toolPartIndex] = {
559
+ ...toolPart,
560
+ output: {
561
+ ...toolPart?.output,
562
+ childMessages: [
563
+ ...childMessages.slice(0, -1),
564
+ {
565
+ ...childMessages[lastToolIndex],
566
+ toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
567
+ }
568
+ ]
569
+ }
570
+ };
571
+ }
572
+ }
573
+ return [
574
+ ...conversation.slice(0, -1),
575
+ {
576
+ ...lastMessage,
577
+ parts
578
+ }
579
+ ];
580
+ };
434
581
 
435
582
  const toAssistantUIMessage = (message) => {
436
583
  const extendedMessage = message;
@@ -470,13 +617,23 @@ const toAssistantUIMessage = (message) => {
470
617
  };
471
618
  }
472
619
  if (part.type === "file") {
473
- return {
474
- type: "file",
475
- mimeType: part.mediaType,
476
- data: part.url,
477
- // Use URL as data source
478
- metadata: message.metadata
479
- };
620
+ const type = part.mediaType.includes("image/") ? "image" : "file";
621
+ if (type === "file") {
622
+ return {
623
+ type,
624
+ mimeType: part.mediaType,
625
+ data: part.url,
626
+ // Use URL as data source
627
+ metadata: message.metadata
628
+ };
629
+ }
630
+ if (type === "image") {
631
+ return {
632
+ type,
633
+ image: part.url,
634
+ metadata: message.metadata
635
+ };
636
+ }
480
637
  }
481
638
  if (part.type === "dynamic-tool") {
482
639
  const baseToolCall = {
@@ -512,6 +669,20 @@ const toAssistantUIMessage = (message) => {
512
669
  }
513
670
  return baseToolCall;
514
671
  }
672
+ const requireApprovalMetadata = extendedMessage.metadata?.requireApprovalMetadata;
673
+ const partToolCallId = "toolCallId" in part && typeof part.toolCallId === "string" ? part.toolCallId : void 0;
674
+ const suspensionData = partToolCallId ? requireApprovalMetadata?.[partToolCallId] : void 0;
675
+ if (suspensionData) {
676
+ const toolName = "toolName" in part && typeof part.toolName === "string" ? part.toolName : part.type.startsWith("tool-") ? part.type.substring(5) : "";
677
+ return {
678
+ type: "tool-call",
679
+ toolCallId: partToolCallId,
680
+ toolName,
681
+ argsText: "input" in part ? JSON.stringify(part.input) : "{}",
682
+ args: "input" in part ? part.input : {},
683
+ metadata: extendedMessage.metadata
684
+ };
685
+ }
515
686
  return {
516
687
  type: "text",
517
688
  text: "",
@@ -551,6 +722,123 @@ const toAssistantUIMessage = (message) => {
551
722
  return threadMessage;
552
723
  };
553
724
 
725
+ const resolveInitialMessages = (messages) => {
726
+ return messages.map((message) => {
727
+ const networkPart = message.parts.find(
728
+ (part) => typeof part === "object" && part !== null && "type" in part && part.type === "text" && "text" in part && typeof part.text === "string" && part.text.includes('"isNetwork":true')
729
+ );
730
+ if (networkPart && networkPart.type === "text") {
731
+ try {
732
+ const json = JSON.parse(networkPart.text);
733
+ if (json.isNetwork === true) {
734
+ const selectionReason = json.selectionReason || "";
735
+ const primitiveType = json.primitiveType || "";
736
+ const primitiveId = json.primitiveId || "";
737
+ const finalResult = json.finalResult;
738
+ const toolCalls = finalResult?.toolCalls || [];
739
+ const childMessages = [];
740
+ for (const toolCall of toolCalls) {
741
+ if (toolCall.type === "tool-call" && toolCall.payload) {
742
+ const toolCallId = toolCall.payload.toolCallId;
743
+ let toolResult;
744
+ for (const message2 of finalResult?.messages || []) {
745
+ for (const part of message2.content || []) {
746
+ if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
747
+ toolResult = part;
748
+ break;
749
+ }
750
+ }
751
+ }
752
+ const isWorkflow = Boolean(toolResult?.result?.result?.steps);
753
+ childMessages.push({
754
+ type: "tool",
755
+ toolCallId: toolCall.payload.toolCallId,
756
+ toolName: toolCall.payload.toolName,
757
+ args: toolCall.payload.args,
758
+ toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
759
+ });
760
+ }
761
+ }
762
+ if (finalResult && finalResult.text) {
763
+ childMessages.push({
764
+ type: "text",
765
+ content: finalResult.text
766
+ });
767
+ }
768
+ const result = {
769
+ childMessages,
770
+ result: finalResult?.text || ""
771
+ };
772
+ const nextMessage = {
773
+ role: "assistant",
774
+ parts: [
775
+ {
776
+ type: "dynamic-tool",
777
+ toolCallId: primitiveId,
778
+ toolName: primitiveId,
779
+ state: "output-available",
780
+ input: json.input,
781
+ output: result
782
+ }
783
+ ],
784
+ id: message.id,
785
+ metadata: {
786
+ ...message.metadata,
787
+ mode: "network",
788
+ selectionReason,
789
+ agentInput: json.input,
790
+ from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
791
+ }
792
+ };
793
+ return nextMessage;
794
+ }
795
+ } catch (error) {
796
+ return message;
797
+ }
798
+ }
799
+ const extendedMessage = message;
800
+ const pendingToolApprovals = extendedMessage.metadata?.pendingToolApprovals;
801
+ if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
802
+ return {
803
+ ...message,
804
+ metadata: {
805
+ ...message.metadata,
806
+ mode: "stream",
807
+ requireApprovalMetadata: pendingToolApprovals
808
+ }
809
+ };
810
+ }
811
+ return message;
812
+ });
813
+ };
814
+ const resolveToChildMessages = (messages) => {
815
+ const assistantMessage = messages.find((message) => message.role === "assistant");
816
+ if (!assistantMessage) return [];
817
+ const parts = assistantMessage.parts;
818
+ let childMessages = [];
819
+ for (const part of parts) {
820
+ const toolPart = part;
821
+ if (part.type.startsWith("tool-")) {
822
+ const toolName = part.type.substring("tool-".length);
823
+ const isWorkflow = toolName.startsWith("workflow-");
824
+ childMessages.push({
825
+ type: "tool",
826
+ toolCallId: toolPart.toolCallId,
827
+ toolName,
828
+ args: toolPart.input,
829
+ toolOutput: isWorkflow ? { ...toolPart.output?.result, runId: toolPart.output?.runId } : toolPart.output
830
+ });
831
+ }
832
+ if (part.type === "text") {
833
+ childMessages.push({
834
+ type: "text",
835
+ content: toolPart.text
836
+ });
837
+ }
838
+ }
839
+ return childMessages;
840
+ };
841
+
554
842
  class AISdkNetworkTransformer {
555
843
  transform({ chunk, conversation, metadata }) {
556
844
  const newConversation = [...conversation];
@@ -923,92 +1211,75 @@ class AISdkNetworkTransformer {
923
1211
  };
924
1212
  }
925
1213
 
926
- const resolveInitialMessages = (messages) => {
927
- return messages.map((message) => {
928
- const networkPart = message.parts.find((part) => part.type === "text" && part.text.includes('"isNetwork":true'));
929
- if (networkPart && networkPart.type === "text") {
930
- try {
931
- const json = JSON.parse(networkPart.text);
932
- if (json.isNetwork === true) {
933
- const selectionReason = json.selectionReason || "";
934
- const primitiveType = json.primitiveType || "";
935
- const primitiveId = json.primitiveId || "";
936
- const finalResult = json.finalResult;
937
- const toolCalls = finalResult?.toolCalls || [];
938
- const childMessages = [];
939
- for (const toolCall of toolCalls) {
940
- if (toolCall.type === "tool-call" && toolCall.payload) {
941
- const toolCallId = toolCall.payload.toolCallId;
942
- let toolResult;
943
- for (const message2 of finalResult?.messages || []) {
944
- for (const part of message2.content || []) {
945
- if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
946
- toolResult = part;
947
- break;
948
- }
949
- }
950
- }
951
- const isWorkflow = Boolean(toolResult?.result?.result?.steps);
952
- childMessages.push({
953
- type: "tool",
954
- toolCallId: toolCall.payload.toolCallId,
955
- toolName: toolCall.payload.toolName,
956
- args: toolCall.payload.args,
957
- toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
958
- });
959
- }
960
- }
961
- if (finalResult && finalResult.text) {
962
- childMessages.push({
963
- type: "text",
964
- content: finalResult.text
965
- });
966
- }
967
- const result = {
968
- childMessages,
969
- result: finalResult?.text || ""
970
- };
971
- console.log("json", json);
972
- const nextMessage = {
973
- role: "assistant",
974
- parts: [
975
- {
976
- type: "dynamic-tool",
977
- toolCallId: primitiveId,
978
- toolName: primitiveId,
979
- state: "output-available",
980
- input: json.input,
981
- output: result
982
- }
983
- ],
984
- id: message.id,
985
- metadata: {
986
- ...message.metadata,
987
- mode: "network",
988
- selectionReason,
989
- agentInput: json.input,
990
- from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
991
- }
992
- };
993
- return nextMessage;
994
- }
995
- } catch (error) {
996
- return message;
1214
+ const fromCoreUserMessageToUIMessage = (coreUserMessage) => {
1215
+ const id = `user-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1216
+ const parts = typeof coreUserMessage.content === "string" ? [
1217
+ {
1218
+ type: "text",
1219
+ text: coreUserMessage.content
1220
+ }
1221
+ ] : coreUserMessage.content.map((part) => {
1222
+ switch (part.type) {
1223
+ case "text": {
1224
+ return {
1225
+ type: "text",
1226
+ text: part.text
1227
+ };
1228
+ }
1229
+ case "image": {
1230
+ const url = typeof part.image === "string" ? part.image : part.image instanceof URL ? part.image.toString() : "";
1231
+ return {
1232
+ type: "file",
1233
+ mediaType: part.mimeType ?? "image/*",
1234
+ url
1235
+ };
1236
+ }
1237
+ case "file": {
1238
+ const url = typeof part.data === "string" ? part.data : part.data instanceof URL ? part.data.toString() : "";
1239
+ return {
1240
+ type: "file",
1241
+ mediaType: part.mimeType,
1242
+ url,
1243
+ ...part.filename !== void 0 ? { filename: part.filename } : {}
1244
+ };
1245
+ }
1246
+ default: {
1247
+ const exhaustiveCheck = part;
1248
+ throw new Error(`Unhandled content part type: ${exhaustiveCheck.type}`);
997
1249
  }
998
1250
  }
999
- return message;
1000
1251
  });
1252
+ return {
1253
+ id,
1254
+ role: "user",
1255
+ parts
1256
+ };
1001
1257
  };
1002
1258
 
1003
- const useChat = ({ agentId, initializeMessages }) => {
1004
- const [messages, setMessages] = react.useState(
1005
- () => resolveInitialMessages(initializeMessages?.() || [])
1006
- );
1259
+ const useChat = ({ agentId, resourceId, initializeMessages }) => {
1260
+ const extractRunIdFromMessages = (messages2) => {
1261
+ for (const message of messages2) {
1262
+ const pendingToolApprovals = message.metadata?.pendingToolApprovals;
1263
+ if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
1264
+ const suspensionData = Object.values(pendingToolApprovals)[0];
1265
+ if (suspensionData?.runId) {
1266
+ return suspensionData.runId;
1267
+ }
1268
+ }
1269
+ }
1270
+ return void 0;
1271
+ };
1272
+ const initialMessages = initializeMessages?.() || [];
1273
+ const initialRunId = extractRunIdFromMessages(initialMessages);
1274
+ const _currentRunId = react.useRef(initialRunId);
1275
+ const _onChunk = react.useRef(void 0);
1276
+ const [messages, setMessages] = react.useState(() => resolveInitialMessages(initialMessages));
1277
+ const [toolCallApprovals, setToolCallApprovals] = react.useState({});
1007
1278
  const baseClient = useMastraClient();
1008
1279
  const [isRunning, setIsRunning] = react.useState(false);
1009
1280
  const generate = async ({
1010
1281
  coreUserMessages,
1011
- runtimeContext,
1282
+ requestContext,
1012
1283
  threadId,
1013
1284
  modelSettings,
1014
1285
  signal,
@@ -1034,7 +1305,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1034
1305
  const agent = clientWithAbort.getAgent(agentId);
1035
1306
  const response = await agent.generate({
1036
1307
  messages: coreUserMessages,
1037
- runId: agentId,
1308
+ runId: uuid.v4(),
1038
1309
  maxSteps,
1039
1310
  modelSettings: {
1040
1311
  frequencyPenalty,
@@ -1046,8 +1317,8 @@ const useChat = ({ agentId, initializeMessages }) => {
1046
1317
  topP
1047
1318
  },
1048
1319
  instructions,
1049
- runtimeContext,
1050
- ...threadId ? { threadId, resourceId: agentId } : {},
1320
+ requestContext,
1321
+ ...threadId ? { threadId, resourceId: resourceId || agentId } : {},
1051
1322
  providerOptions
1052
1323
  });
1053
1324
  setIsRunning(false);
@@ -1062,7 +1333,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1062
1333
  setMessages((prev) => [...prev, ...mastraUIMessages]);
1063
1334
  }
1064
1335
  };
1065
- const stream = async ({ coreUserMessages, runtimeContext, threadId, onChunk, modelSettings, signal }) => {
1336
+ const stream = async ({ coreUserMessages, requestContext, threadId, onChunk, modelSettings, signal }) => {
1066
1337
  const {
1067
1338
  frequencyPenalty,
1068
1339
  presencePenalty,
@@ -1073,7 +1344,8 @@ const useChat = ({ agentId, initializeMessages }) => {
1073
1344
  topP,
1074
1345
  instructions,
1075
1346
  providerOptions,
1076
- maxSteps
1347
+ maxSteps,
1348
+ requireToolApproval
1077
1349
  } = modelSettings || {};
1078
1350
  setIsRunning(true);
1079
1351
  const clientWithAbort = new clientJs.MastraClient({
@@ -1081,9 +1353,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1081
1353
  abortSignal: signal
1082
1354
  });
1083
1355
  const agent = clientWithAbort.getAgent(agentId);
1356
+ const runId = uuid.v4();
1084
1357
  const response = await agent.stream({
1085
1358
  messages: coreUserMessages,
1086
- runId: agentId,
1359
+ runId,
1087
1360
  maxSteps,
1088
1361
  modelSettings: {
1089
1362
  frequencyPenalty,
@@ -1095,19 +1368,16 @@ const useChat = ({ agentId, initializeMessages }) => {
1095
1368
  topP
1096
1369
  },
1097
1370
  instructions,
1098
- runtimeContext,
1099
- ...threadId ? { threadId, resourceId: agentId } : {},
1100
- providerOptions
1371
+ requestContext,
1372
+ ...threadId ? { threadId, resourceId: resourceId || agentId } : {},
1373
+ providerOptions,
1374
+ requireToolApproval
1101
1375
  });
1102
- if (!response.body) {
1103
- setIsRunning(false);
1104
- throw new Error("[Stream] No response body");
1105
- }
1376
+ _onChunk.current = onChunk;
1377
+ _currentRunId.current = runId;
1106
1378
  await response.processDataStream({
1107
1379
  onChunk: async (chunk) => {
1108
- reactDom.flushSync(() => {
1109
- setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1110
- });
1380
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1111
1381
  onChunk?.(chunk);
1112
1382
  }
1113
1383
  });
@@ -1115,7 +1385,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1115
1385
  };
1116
1386
  const network = async ({
1117
1387
  coreUserMessages,
1118
- runtimeContext,
1388
+ requestContext,
1119
1389
  threadId,
1120
1390
  onNetworkChunk,
1121
1391
  modelSettings,
@@ -1128,6 +1398,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1128
1398
  abortSignal: signal
1129
1399
  });
1130
1400
  const agent = clientWithAbort.getAgent(agentId);
1401
+ const runId = uuid.v4();
1131
1402
  const response = await agent.network({
1132
1403
  messages: coreUserMessages,
1133
1404
  maxSteps,
@@ -1140,31 +1411,72 @@ const useChat = ({ agentId, initializeMessages }) => {
1140
1411
  topK,
1141
1412
  topP
1142
1413
  },
1143
- runId: agentId,
1144
- runtimeContext,
1145
- ...threadId ? { thread: threadId, resourceId: agentId } : {}
1414
+ runId,
1415
+ requestContext,
1416
+ ...threadId ? { thread: threadId, resourceId: resourceId || agentId } : {}
1146
1417
  });
1147
1418
  const transformer = new AISdkNetworkTransformer();
1148
1419
  await response.processDataStream({
1149
1420
  onChunk: async (chunk) => {
1150
- reactDom.flushSync(() => {
1151
- setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1152
- });
1421
+ setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1153
1422
  onNetworkChunk?.(chunk);
1154
1423
  }
1155
1424
  });
1156
1425
  setIsRunning(false);
1157
1426
  };
1427
+ const handleCancelRun = () => {
1428
+ setIsRunning(false);
1429
+ _currentRunId.current = void 0;
1430
+ _onChunk.current = void 0;
1431
+ };
1432
+ const approveToolCall = async (toolCallId) => {
1433
+ const onChunk = _onChunk.current;
1434
+ const currentRunId = _currentRunId.current;
1435
+ if (!currentRunId)
1436
+ return console.info("[approveToolCall] approveToolCall can only be called after a stream has started");
1437
+ setIsRunning(true);
1438
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "approved" } }));
1439
+ const agent = baseClient.getAgent(agentId);
1440
+ const response = await agent.approveToolCall({ runId: currentRunId, toolCallId });
1441
+ await response.processDataStream({
1442
+ onChunk: async (chunk) => {
1443
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1444
+ onChunk?.(chunk);
1445
+ }
1446
+ });
1447
+ setIsRunning(false);
1448
+ };
1449
+ const declineToolCall = async (toolCallId) => {
1450
+ const onChunk = _onChunk.current;
1451
+ const currentRunId = _currentRunId.current;
1452
+ if (!currentRunId)
1453
+ return console.info("[declineToolCall] declineToolCall can only be called after a stream has started");
1454
+ setIsRunning(true);
1455
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "declined" } }));
1456
+ const agent = baseClient.getAgent(agentId);
1457
+ const response = await agent.declineToolCall({ runId: currentRunId, toolCallId });
1458
+ await response.processDataStream({
1459
+ onChunk: async (chunk) => {
1460
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1461
+ onChunk?.(chunk);
1462
+ }
1463
+ });
1464
+ setIsRunning(false);
1465
+ };
1158
1466
  const sendMessage = async ({ mode = "stream", ...args }) => {
1159
1467
  const nextMessage = { role: "user", content: [{ type: "text", text: args.message }] };
1160
- const messages2 = args.coreUserMessages ? [nextMessage, ...args.coreUserMessages] : [nextMessage];
1161
- setMessages((s) => [...s, { role: "user", parts: [{ type: "text", text: args.message }] }]);
1468
+ const coreUserMessages = [nextMessage];
1469
+ if (args.coreUserMessages) {
1470
+ coreUserMessages.push(...args.coreUserMessages);
1471
+ }
1472
+ const uiMessages = coreUserMessages.map(fromCoreUserMessageToUIMessage);
1473
+ setMessages((s) => [...s, ...uiMessages]);
1162
1474
  if (mode === "generate") {
1163
- await generate({ ...args, coreUserMessages: messages2 });
1475
+ await generate({ ...args, coreUserMessages });
1164
1476
  } else if (mode === "stream") {
1165
- await stream({ ...args, coreUserMessages: messages2 });
1477
+ await stream({ ...args, coreUserMessages });
1166
1478
  } else if (mode === "network") {
1167
- await network({ ...args, coreUserMessages: messages2 });
1479
+ await network({ ...args, coreUserMessages });
1168
1480
  }
1169
1481
  };
1170
1482
  return {
@@ -1172,7 +1484,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1172
1484
  sendMessage,
1173
1485
  isRunning,
1174
1486
  messages,
1175
- cancelRun: () => setIsRunning(false)
1487
+ approveToolCall,
1488
+ declineToolCall,
1489
+ cancelRun: handleCancelRun,
1490
+ toolCallApprovals
1176
1491
  };
1177
1492
  };
1178
1493
 
@@ -1546,6 +1861,7 @@ exports.TooltipContentClass = TooltipContentClass;
1546
1861
  exports.TooltipTrigger = TooltipTrigger;
1547
1862
  exports.WorkflowIcon = WorkflowIcon;
1548
1863
  exports.mapWorkflowStreamChunkToWatchResult = mapWorkflowStreamChunkToWatchResult;
1864
+ exports.resolveToChildMessages = resolveToChildMessages;
1549
1865
  exports.toAssistantUIMessage = toAssistantUIMessage;
1550
1866
  exports.toUIMessage = toUIMessage;
1551
1867
  exports.useChat = useChat;