@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.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,15 +411,37 @@ 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;
391
440
  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" };
441
+ if (typeof part === "object" && part !== null && "type" in part && "state" in part && part.state === "streaming") {
442
+ if (part.type === "text" || part.type === "reasoning") {
443
+ return { ...part, state: "done" };
444
+ }
397
445
  }
398
446
  return part;
399
447
  });
@@ -427,6 +475,105 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
427
475
  return result;
428
476
  }
429
477
  };
478
+ const toUIMessageFromAgent = (chunk, conversation, metadata) => {
479
+ const lastMessage = conversation[conversation.length - 1];
480
+ if (!lastMessage || lastMessage.role !== "assistant") return conversation;
481
+ const parts = [...lastMessage.parts];
482
+ if (chunk.type === "text-delta") {
483
+ const agentChunk = chunk.payload;
484
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
485
+ if (toolPartIndex === -1) return conversation;
486
+ const toolPart = parts[toolPartIndex];
487
+ const childMessages = toolPart?.output?.childMessages || [];
488
+ const lastChildMessage = childMessages[childMessages.length - 1];
489
+ const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
490
+ const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
491
+ parts[toolPartIndex] = {
492
+ ...toolPart,
493
+ output: {
494
+ childMessages: nextMessages
495
+ }
496
+ };
497
+ } else if (chunk.type === "tool-call") {
498
+ const agentChunk = chunk.payload;
499
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
500
+ if (toolPartIndex === -1) return conversation;
501
+ const toolPart = parts[toolPartIndex];
502
+ const childMessages = toolPart?.output?.childMessages || [];
503
+ parts[toolPartIndex] = {
504
+ ...toolPart,
505
+ output: {
506
+ ...toolPart?.output,
507
+ childMessages: [
508
+ ...childMessages,
509
+ {
510
+ type: "tool",
511
+ toolCallId: agentChunk.toolCallId,
512
+ toolName: agentChunk.toolName,
513
+ args: agentChunk.args
514
+ }
515
+ ]
516
+ }
517
+ };
518
+ } else if (chunk.type === "tool-output") {
519
+ const agentChunk = chunk.payload;
520
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
521
+ if (toolPartIndex === -1) return conversation;
522
+ const toolPart = parts[toolPartIndex];
523
+ if (agentChunk?.output?.type?.startsWith("workflow-")) {
524
+ const childMessages = toolPart?.output?.childMessages || [];
525
+ const lastToolIndex = childMessages.length - 1;
526
+ const currentMessage = childMessages[lastToolIndex];
527
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
528
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
529
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
530
+ parts[toolPartIndex] = {
531
+ ...toolPart,
532
+ output: {
533
+ ...toolPart?.output,
534
+ childMessages: [
535
+ ...childMessages.slice(0, -1),
536
+ {
537
+ ...currentMessage,
538
+ toolOutput: { ...updatedWorkflowState, runId: agentChunk.output.runId }
539
+ }
540
+ ]
541
+ }
542
+ };
543
+ }
544
+ }
545
+ } else if (chunk.type === "tool-result") {
546
+ const agentChunk = chunk.payload;
547
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
548
+ if (toolPartIndex === -1) return conversation;
549
+ const toolPart = parts[toolPartIndex];
550
+ const childMessages = toolPart?.output?.childMessages || [];
551
+ const lastToolIndex = childMessages.length - 1;
552
+ const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
553
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
554
+ parts[toolPartIndex] = {
555
+ ...toolPart,
556
+ output: {
557
+ ...toolPart?.output,
558
+ childMessages: [
559
+ ...childMessages.slice(0, -1),
560
+ {
561
+ ...childMessages[lastToolIndex],
562
+ toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
563
+ }
564
+ ]
565
+ }
566
+ };
567
+ }
568
+ }
569
+ return [
570
+ ...conversation.slice(0, -1),
571
+ {
572
+ ...lastMessage,
573
+ parts
574
+ }
575
+ ];
576
+ };
430
577
 
431
578
  const toAssistantUIMessage = (message) => {
432
579
  const extendedMessage = message;
@@ -466,13 +613,23 @@ const toAssistantUIMessage = (message) => {
466
613
  };
467
614
  }
468
615
  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
- };
616
+ const type = part.mediaType.includes("image/") ? "image" : "file";
617
+ if (type === "file") {
618
+ return {
619
+ type,
620
+ mimeType: part.mediaType,
621
+ data: part.url,
622
+ // Use URL as data source
623
+ metadata: message.metadata
624
+ };
625
+ }
626
+ if (type === "image") {
627
+ return {
628
+ type,
629
+ image: part.url,
630
+ metadata: message.metadata
631
+ };
632
+ }
476
633
  }
477
634
  if (part.type === "dynamic-tool") {
478
635
  const baseToolCall = {
@@ -508,6 +665,20 @@ const toAssistantUIMessage = (message) => {
508
665
  }
509
666
  return baseToolCall;
510
667
  }
668
+ const requireApprovalMetadata = extendedMessage.metadata?.requireApprovalMetadata;
669
+ const partToolCallId = "toolCallId" in part && typeof part.toolCallId === "string" ? part.toolCallId : void 0;
670
+ const suspensionData = partToolCallId ? requireApprovalMetadata?.[partToolCallId] : void 0;
671
+ if (suspensionData) {
672
+ const toolName = "toolName" in part && typeof part.toolName === "string" ? part.toolName : part.type.startsWith("tool-") ? part.type.substring(5) : "";
673
+ return {
674
+ type: "tool-call",
675
+ toolCallId: partToolCallId,
676
+ toolName,
677
+ argsText: "input" in part ? JSON.stringify(part.input) : "{}",
678
+ args: "input" in part ? part.input : {},
679
+ metadata: extendedMessage.metadata
680
+ };
681
+ }
511
682
  return {
512
683
  type: "text",
513
684
  text: "",
@@ -547,6 +718,123 @@ const toAssistantUIMessage = (message) => {
547
718
  return threadMessage;
548
719
  };
549
720
 
721
+ const resolveInitialMessages = (messages) => {
722
+ return messages.map((message) => {
723
+ const networkPart = message.parts.find(
724
+ (part) => typeof part === "object" && part !== null && "type" in part && part.type === "text" && "text" in part && typeof part.text === "string" && part.text.includes('"isNetwork":true')
725
+ );
726
+ if (networkPart && networkPart.type === "text") {
727
+ try {
728
+ const json = JSON.parse(networkPart.text);
729
+ if (json.isNetwork === true) {
730
+ const selectionReason = json.selectionReason || "";
731
+ const primitiveType = json.primitiveType || "";
732
+ const primitiveId = json.primitiveId || "";
733
+ const finalResult = json.finalResult;
734
+ const toolCalls = finalResult?.toolCalls || [];
735
+ const childMessages = [];
736
+ for (const toolCall of toolCalls) {
737
+ if (toolCall.type === "tool-call" && toolCall.payload) {
738
+ const toolCallId = toolCall.payload.toolCallId;
739
+ let toolResult;
740
+ for (const message2 of finalResult?.messages || []) {
741
+ for (const part of message2.content || []) {
742
+ if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
743
+ toolResult = part;
744
+ break;
745
+ }
746
+ }
747
+ }
748
+ const isWorkflow = Boolean(toolResult?.result?.result?.steps);
749
+ childMessages.push({
750
+ type: "tool",
751
+ toolCallId: toolCall.payload.toolCallId,
752
+ toolName: toolCall.payload.toolName,
753
+ args: toolCall.payload.args,
754
+ toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
755
+ });
756
+ }
757
+ }
758
+ if (finalResult && finalResult.text) {
759
+ childMessages.push({
760
+ type: "text",
761
+ content: finalResult.text
762
+ });
763
+ }
764
+ const result = {
765
+ childMessages,
766
+ result: finalResult?.text || ""
767
+ };
768
+ const nextMessage = {
769
+ role: "assistant",
770
+ parts: [
771
+ {
772
+ type: "dynamic-tool",
773
+ toolCallId: primitiveId,
774
+ toolName: primitiveId,
775
+ state: "output-available",
776
+ input: json.input,
777
+ output: result
778
+ }
779
+ ],
780
+ id: message.id,
781
+ metadata: {
782
+ ...message.metadata,
783
+ mode: "network",
784
+ selectionReason,
785
+ agentInput: json.input,
786
+ from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
787
+ }
788
+ };
789
+ return nextMessage;
790
+ }
791
+ } catch (error) {
792
+ return message;
793
+ }
794
+ }
795
+ const extendedMessage = message;
796
+ const pendingToolApprovals = extendedMessage.metadata?.pendingToolApprovals;
797
+ if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
798
+ return {
799
+ ...message,
800
+ metadata: {
801
+ ...message.metadata,
802
+ mode: "stream",
803
+ requireApprovalMetadata: pendingToolApprovals
804
+ }
805
+ };
806
+ }
807
+ return message;
808
+ });
809
+ };
810
+ const resolveToChildMessages = (messages) => {
811
+ const assistantMessage = messages.find((message) => message.role === "assistant");
812
+ if (!assistantMessage) return [];
813
+ const parts = assistantMessage.parts;
814
+ let childMessages = [];
815
+ for (const part of parts) {
816
+ const toolPart = part;
817
+ if (part.type.startsWith("tool-")) {
818
+ const toolName = part.type.substring("tool-".length);
819
+ const isWorkflow = toolName.startsWith("workflow-");
820
+ childMessages.push({
821
+ type: "tool",
822
+ toolCallId: toolPart.toolCallId,
823
+ toolName,
824
+ args: toolPart.input,
825
+ toolOutput: isWorkflow ? { ...toolPart.output?.result, runId: toolPart.output?.runId } : toolPart.output
826
+ });
827
+ }
828
+ if (part.type === "text") {
829
+ childMessages.push({
830
+ type: "text",
831
+ content: toolPart.text
832
+ });
833
+ }
834
+ }
835
+ return childMessages;
836
+ };
837
+
550
838
  class AISdkNetworkTransformer {
551
839
  transform({ chunk, conversation, metadata }) {
552
840
  const newConversation = [...conversation];
@@ -919,92 +1207,75 @@ class AISdkNetworkTransformer {
919
1207
  };
920
1208
  }
921
1209
 
922
- const resolveInitialMessages = (messages) => {
923
- return messages.map((message) => {
924
- const networkPart = message.parts.find((part) => part.type === "text" && part.text.includes('"isNetwork":true'));
925
- if (networkPart && networkPart.type === "text") {
926
- try {
927
- const json = JSON.parse(networkPart.text);
928
- if (json.isNetwork === true) {
929
- const selectionReason = json.selectionReason || "";
930
- const primitiveType = json.primitiveType || "";
931
- const primitiveId = json.primitiveId || "";
932
- const finalResult = json.finalResult;
933
- const toolCalls = finalResult?.toolCalls || [];
934
- const childMessages = [];
935
- for (const toolCall of toolCalls) {
936
- if (toolCall.type === "tool-call" && toolCall.payload) {
937
- const toolCallId = toolCall.payload.toolCallId;
938
- let toolResult;
939
- for (const message2 of finalResult?.messages || []) {
940
- for (const part of message2.content || []) {
941
- if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
942
- toolResult = part;
943
- break;
944
- }
945
- }
946
- }
947
- const isWorkflow = Boolean(toolResult?.result?.result?.steps);
948
- childMessages.push({
949
- type: "tool",
950
- toolCallId: toolCall.payload.toolCallId,
951
- toolName: toolCall.payload.toolName,
952
- args: toolCall.payload.args,
953
- toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
954
- });
955
- }
956
- }
957
- if (finalResult && finalResult.text) {
958
- childMessages.push({
959
- type: "text",
960
- content: finalResult.text
961
- });
962
- }
963
- const result = {
964
- childMessages,
965
- result: finalResult?.text || ""
966
- };
967
- console.log("json", json);
968
- const nextMessage = {
969
- role: "assistant",
970
- parts: [
971
- {
972
- type: "dynamic-tool",
973
- toolCallId: primitiveId,
974
- toolName: primitiveId,
975
- state: "output-available",
976
- input: json.input,
977
- output: result
978
- }
979
- ],
980
- id: message.id,
981
- metadata: {
982
- ...message.metadata,
983
- mode: "network",
984
- selectionReason,
985
- agentInput: json.input,
986
- from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
987
- }
988
- };
989
- return nextMessage;
990
- }
991
- } catch (error) {
992
- return message;
1210
+ const fromCoreUserMessageToUIMessage = (coreUserMessage) => {
1211
+ const id = `user-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1212
+ const parts = typeof coreUserMessage.content === "string" ? [
1213
+ {
1214
+ type: "text",
1215
+ text: coreUserMessage.content
1216
+ }
1217
+ ] : coreUserMessage.content.map((part) => {
1218
+ switch (part.type) {
1219
+ case "text": {
1220
+ return {
1221
+ type: "text",
1222
+ text: part.text
1223
+ };
1224
+ }
1225
+ case "image": {
1226
+ const url = typeof part.image === "string" ? part.image : part.image instanceof URL ? part.image.toString() : "";
1227
+ return {
1228
+ type: "file",
1229
+ mediaType: part.mimeType ?? "image/*",
1230
+ url
1231
+ };
1232
+ }
1233
+ case "file": {
1234
+ const url = typeof part.data === "string" ? part.data : part.data instanceof URL ? part.data.toString() : "";
1235
+ return {
1236
+ type: "file",
1237
+ mediaType: part.mimeType,
1238
+ url,
1239
+ ...part.filename !== void 0 ? { filename: part.filename } : {}
1240
+ };
1241
+ }
1242
+ default: {
1243
+ const exhaustiveCheck = part;
1244
+ throw new Error(`Unhandled content part type: ${exhaustiveCheck.type}`);
993
1245
  }
994
1246
  }
995
- return message;
996
1247
  });
1248
+ return {
1249
+ id,
1250
+ role: "user",
1251
+ parts
1252
+ };
997
1253
  };
998
1254
 
999
- const useChat = ({ agentId, initializeMessages }) => {
1000
- const [messages, setMessages] = useState(
1001
- () => resolveInitialMessages(initializeMessages?.() || [])
1002
- );
1255
+ const useChat = ({ agentId, resourceId, initializeMessages }) => {
1256
+ const extractRunIdFromMessages = (messages2) => {
1257
+ for (const message of messages2) {
1258
+ const pendingToolApprovals = message.metadata?.pendingToolApprovals;
1259
+ if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
1260
+ const suspensionData = Object.values(pendingToolApprovals)[0];
1261
+ if (suspensionData?.runId) {
1262
+ return suspensionData.runId;
1263
+ }
1264
+ }
1265
+ }
1266
+ return void 0;
1267
+ };
1268
+ const initialMessages = initializeMessages?.() || [];
1269
+ const initialRunId = extractRunIdFromMessages(initialMessages);
1270
+ const _currentRunId = useRef(initialRunId);
1271
+ const _onChunk = useRef(void 0);
1272
+ const [messages, setMessages] = useState(() => resolveInitialMessages(initialMessages));
1273
+ const [toolCallApprovals, setToolCallApprovals] = useState({});
1003
1274
  const baseClient = useMastraClient();
1004
1275
  const [isRunning, setIsRunning] = useState(false);
1005
1276
  const generate = async ({
1006
1277
  coreUserMessages,
1007
- runtimeContext,
1278
+ requestContext,
1008
1279
  threadId,
1009
1280
  modelSettings,
1010
1281
  signal,
@@ -1030,7 +1301,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1030
1301
  const agent = clientWithAbort.getAgent(agentId);
1031
1302
  const response = await agent.generate({
1032
1303
  messages: coreUserMessages,
1033
- runId: agentId,
1304
+ runId: v4(),
1034
1305
  maxSteps,
1035
1306
  modelSettings: {
1036
1307
  frequencyPenalty,
@@ -1042,8 +1313,8 @@ const useChat = ({ agentId, initializeMessages }) => {
1042
1313
  topP
1043
1314
  },
1044
1315
  instructions,
1045
- runtimeContext,
1046
- ...threadId ? { threadId, resourceId: agentId } : {},
1316
+ requestContext,
1317
+ ...threadId ? { threadId, resourceId: resourceId || agentId } : {},
1047
1318
  providerOptions
1048
1319
  });
1049
1320
  setIsRunning(false);
@@ -1058,7 +1329,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1058
1329
  setMessages((prev) => [...prev, ...mastraUIMessages]);
1059
1330
  }
1060
1331
  };
1061
- const stream = async ({ coreUserMessages, runtimeContext, threadId, onChunk, modelSettings, signal }) => {
1332
+ const stream = async ({ coreUserMessages, requestContext, threadId, onChunk, modelSettings, signal }) => {
1062
1333
  const {
1063
1334
  frequencyPenalty,
1064
1335
  presencePenalty,
@@ -1069,7 +1340,8 @@ const useChat = ({ agentId, initializeMessages }) => {
1069
1340
  topP,
1070
1341
  instructions,
1071
1342
  providerOptions,
1072
- maxSteps
1343
+ maxSteps,
1344
+ requireToolApproval
1073
1345
  } = modelSettings || {};
1074
1346
  setIsRunning(true);
1075
1347
  const clientWithAbort = new MastraClient({
@@ -1077,9 +1349,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1077
1349
  abortSignal: signal
1078
1350
  });
1079
1351
  const agent = clientWithAbort.getAgent(agentId);
1352
+ const runId = v4();
1080
1353
  const response = await agent.stream({
1081
1354
  messages: coreUserMessages,
1082
- runId: agentId,
1355
+ runId,
1083
1356
  maxSteps,
1084
1357
  modelSettings: {
1085
1358
  frequencyPenalty,
@@ -1091,19 +1364,16 @@ const useChat = ({ agentId, initializeMessages }) => {
1091
1364
  topP
1092
1365
  },
1093
1366
  instructions,
1094
- runtimeContext,
1095
- ...threadId ? { threadId, resourceId: agentId } : {},
1096
- providerOptions
1367
+ requestContext,
1368
+ ...threadId ? { threadId, resourceId: resourceId || agentId } : {},
1369
+ providerOptions,
1370
+ requireToolApproval
1097
1371
  });
1098
- if (!response.body) {
1099
- setIsRunning(false);
1100
- throw new Error("[Stream] No response body");
1101
- }
1372
+ _onChunk.current = onChunk;
1373
+ _currentRunId.current = runId;
1102
1374
  await response.processDataStream({
1103
1375
  onChunk: async (chunk) => {
1104
- flushSync(() => {
1105
- setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1106
- });
1376
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1107
1377
  onChunk?.(chunk);
1108
1378
  }
1109
1379
  });
@@ -1111,7 +1381,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1111
1381
  };
1112
1382
  const network = async ({
1113
1383
  coreUserMessages,
1114
- runtimeContext,
1384
+ requestContext,
1115
1385
  threadId,
1116
1386
  onNetworkChunk,
1117
1387
  modelSettings,
@@ -1124,6 +1394,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1124
1394
  abortSignal: signal
1125
1395
  });
1126
1396
  const agent = clientWithAbort.getAgent(agentId);
1397
+ const runId = v4();
1127
1398
  const response = await agent.network({
1128
1399
  messages: coreUserMessages,
1129
1400
  maxSteps,
@@ -1136,31 +1407,72 @@ const useChat = ({ agentId, initializeMessages }) => {
1136
1407
  topK,
1137
1408
  topP
1138
1409
  },
1139
- runId: agentId,
1140
- runtimeContext,
1141
- ...threadId ? { thread: threadId, resourceId: agentId } : {}
1410
+ runId,
1411
+ requestContext,
1412
+ ...threadId ? { thread: threadId, resourceId: resourceId || agentId } : {}
1142
1413
  });
1143
1414
  const transformer = new AISdkNetworkTransformer();
1144
1415
  await response.processDataStream({
1145
1416
  onChunk: async (chunk) => {
1146
- flushSync(() => {
1147
- setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1148
- });
1417
+ setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1149
1418
  onNetworkChunk?.(chunk);
1150
1419
  }
1151
1420
  });
1152
1421
  setIsRunning(false);
1153
1422
  };
1423
+ const handleCancelRun = () => {
1424
+ setIsRunning(false);
1425
+ _currentRunId.current = void 0;
1426
+ _onChunk.current = void 0;
1427
+ };
1428
+ const approveToolCall = async (toolCallId) => {
1429
+ const onChunk = _onChunk.current;
1430
+ const currentRunId = _currentRunId.current;
1431
+ if (!currentRunId)
1432
+ return console.info("[approveToolCall] approveToolCall can only be called after a stream has started");
1433
+ setIsRunning(true);
1434
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "approved" } }));
1435
+ const agent = baseClient.getAgent(agentId);
1436
+ const response = await agent.approveToolCall({ runId: currentRunId, toolCallId });
1437
+ await response.processDataStream({
1438
+ onChunk: async (chunk) => {
1439
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1440
+ onChunk?.(chunk);
1441
+ }
1442
+ });
1443
+ setIsRunning(false);
1444
+ };
1445
+ const declineToolCall = async (toolCallId) => {
1446
+ const onChunk = _onChunk.current;
1447
+ const currentRunId = _currentRunId.current;
1448
+ if (!currentRunId)
1449
+ return console.info("[declineToolCall] declineToolCall can only be called after a stream has started");
1450
+ setIsRunning(true);
1451
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "declined" } }));
1452
+ const agent = baseClient.getAgent(agentId);
1453
+ const response = await agent.declineToolCall({ runId: currentRunId, toolCallId });
1454
+ await response.processDataStream({
1455
+ onChunk: async (chunk) => {
1456
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1457
+ onChunk?.(chunk);
1458
+ }
1459
+ });
1460
+ setIsRunning(false);
1461
+ };
1154
1462
  const sendMessage = async ({ mode = "stream", ...args }) => {
1155
1463
  const nextMessage = { role: "user", content: [{ type: "text", text: args.message }] };
1156
- const messages2 = args.coreUserMessages ? [nextMessage, ...args.coreUserMessages] : [nextMessage];
1157
- setMessages((s) => [...s, { role: "user", parts: [{ type: "text", text: args.message }] }]);
1464
+ const coreUserMessages = [nextMessage];
1465
+ if (args.coreUserMessages) {
1466
+ coreUserMessages.push(...args.coreUserMessages);
1467
+ }
1468
+ const uiMessages = coreUserMessages.map(fromCoreUserMessageToUIMessage);
1469
+ setMessages((s) => [...s, ...uiMessages]);
1158
1470
  if (mode === "generate") {
1159
- await generate({ ...args, coreUserMessages: messages2 });
1471
+ await generate({ ...args, coreUserMessages });
1160
1472
  } else if (mode === "stream") {
1161
- await stream({ ...args, coreUserMessages: messages2 });
1473
+ await stream({ ...args, coreUserMessages });
1162
1474
  } else if (mode === "network") {
1163
- await network({ ...args, coreUserMessages: messages2 });
1475
+ await network({ ...args, coreUserMessages });
1164
1476
  }
1165
1477
  };
1166
1478
  return {
@@ -1168,7 +1480,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1168
1480
  sendMessage,
1169
1481
  isRunning,
1170
1482
  messages,
1171
- cancelRun: () => setIsRunning(false)
1483
+ approveToolCall,
1484
+ declineToolCall,
1485
+ cancelRun: handleCancelRun,
1486
+ toolCallApprovals
1172
1487
  };
1173
1488
  };
1174
1489
 
@@ -1487,5 +1802,5 @@ const MessageStreaming = ({ className, ...props }) => {
1487
1802
  return /* @__PURE__ */ jsx("span", { className: className || MessageStreamingClass, ...props });
1488
1803
  };
1489
1804
 
1490
- 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 };
1805
+ 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 };
1491
1806
  //# sourceMappingURL=index.js.map