@mastra/react 0.0.0-model-router-unknown-provider-20251017212006 → 0.0.0-remove-unused-model-providers-api-20251030210744

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,6 +397,29 @@ 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;
@@ -427,6 +462,105 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
427
462
  return result;
428
463
  }
429
464
  };
465
+ const toUIMessageFromAgent = (chunk, conversation, metadata) => {
466
+ const lastMessage = conversation[conversation.length - 1];
467
+ if (!lastMessage || lastMessage.role !== "assistant") return conversation;
468
+ const parts = [...lastMessage.parts];
469
+ if (chunk.type === "text-delta") {
470
+ const agentChunk = chunk.payload;
471
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
472
+ if (toolPartIndex === -1) return conversation;
473
+ const toolPart = parts[toolPartIndex];
474
+ const childMessages = toolPart?.output?.childMessages || [];
475
+ const lastChildMessage = childMessages[childMessages.length - 1];
476
+ const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
477
+ const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
478
+ parts[toolPartIndex] = {
479
+ ...toolPart,
480
+ output: {
481
+ childMessages: nextMessages
482
+ }
483
+ };
484
+ } else if (chunk.type === "tool-call") {
485
+ const agentChunk = chunk.payload;
486
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
487
+ if (toolPartIndex === -1) return conversation;
488
+ const toolPart = parts[toolPartIndex];
489
+ const childMessages = toolPart?.output?.childMessages || [];
490
+ parts[toolPartIndex] = {
491
+ ...toolPart,
492
+ output: {
493
+ ...toolPart?.output,
494
+ childMessages: [
495
+ ...childMessages,
496
+ {
497
+ type: "tool",
498
+ toolCallId: agentChunk.toolCallId,
499
+ toolName: agentChunk.toolName,
500
+ args: agentChunk.args
501
+ }
502
+ ]
503
+ }
504
+ };
505
+ } else if (chunk.type === "tool-output") {
506
+ const agentChunk = chunk.payload;
507
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
508
+ if (toolPartIndex === -1) return conversation;
509
+ const toolPart = parts[toolPartIndex];
510
+ if (agentChunk?.output?.type?.startsWith("workflow-")) {
511
+ const childMessages = toolPart?.output?.childMessages || [];
512
+ const lastToolIndex = childMessages.length - 1;
513
+ const currentMessage = childMessages[lastToolIndex];
514
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
515
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
516
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
517
+ parts[toolPartIndex] = {
518
+ ...toolPart,
519
+ output: {
520
+ ...toolPart?.output,
521
+ childMessages: [
522
+ ...childMessages.slice(0, -1),
523
+ {
524
+ ...currentMessage,
525
+ toolOutput: { ...updatedWorkflowState, runId: agentChunk.output.runId }
526
+ }
527
+ ]
528
+ }
529
+ };
530
+ }
531
+ }
532
+ } else if (chunk.type === "tool-result") {
533
+ const agentChunk = chunk.payload;
534
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
535
+ if (toolPartIndex === -1) return conversation;
536
+ const toolPart = parts[toolPartIndex];
537
+ const childMessages = toolPart?.output?.childMessages || [];
538
+ const lastToolIndex = childMessages.length - 1;
539
+ const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
540
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
541
+ parts[toolPartIndex] = {
542
+ ...toolPart,
543
+ output: {
544
+ ...toolPart?.output,
545
+ childMessages: [
546
+ ...childMessages.slice(0, -1),
547
+ {
548
+ ...childMessages[lastToolIndex],
549
+ toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
550
+ }
551
+ ]
552
+ }
553
+ };
554
+ }
555
+ }
556
+ return [
557
+ ...conversation.slice(0, -1),
558
+ {
559
+ ...lastMessage,
560
+ parts
561
+ }
562
+ ];
563
+ };
430
564
 
431
565
  const toAssistantUIMessage = (message) => {
432
566
  const extendedMessage = message;
@@ -466,13 +600,23 @@ const toAssistantUIMessage = (message) => {
466
600
  };
467
601
  }
468
602
  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
- };
603
+ const type = part.mediaType.includes("image/") ? "image" : "file";
604
+ if (type === "file") {
605
+ return {
606
+ type,
607
+ mimeType: part.mediaType,
608
+ data: part.url,
609
+ // Use URL as data source
610
+ metadata: message.metadata
611
+ };
612
+ }
613
+ if (type === "image") {
614
+ return {
615
+ type,
616
+ image: part.url,
617
+ metadata: message.metadata
618
+ };
619
+ }
476
620
  }
477
621
  if (part.type === "dynamic-tool") {
478
622
  const baseToolCall = {
@@ -547,6 +691,110 @@ const toAssistantUIMessage = (message) => {
547
691
  return threadMessage;
548
692
  };
549
693
 
694
+ const resolveInitialMessages = (messages) => {
695
+ return messages.map((message) => {
696
+ const networkPart = message.parts.find((part) => part.type === "text" && part.text.includes('"isNetwork":true'));
697
+ if (networkPart && networkPart.type === "text") {
698
+ try {
699
+ const json = JSON.parse(networkPart.text);
700
+ if (json.isNetwork === true) {
701
+ const selectionReason = json.selectionReason || "";
702
+ const primitiveType = json.primitiveType || "";
703
+ const primitiveId = json.primitiveId || "";
704
+ const finalResult = json.finalResult;
705
+ const toolCalls = finalResult?.toolCalls || [];
706
+ const childMessages = [];
707
+ for (const toolCall of toolCalls) {
708
+ if (toolCall.type === "tool-call" && toolCall.payload) {
709
+ const toolCallId = toolCall.payload.toolCallId;
710
+ let toolResult;
711
+ for (const message2 of finalResult?.messages || []) {
712
+ for (const part of message2.content || []) {
713
+ if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
714
+ toolResult = part;
715
+ break;
716
+ }
717
+ }
718
+ }
719
+ const isWorkflow = Boolean(toolResult?.result?.result?.steps);
720
+ childMessages.push({
721
+ type: "tool",
722
+ toolCallId: toolCall.payload.toolCallId,
723
+ toolName: toolCall.payload.toolName,
724
+ args: toolCall.payload.args,
725
+ toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
726
+ });
727
+ }
728
+ }
729
+ if (finalResult && finalResult.text) {
730
+ childMessages.push({
731
+ type: "text",
732
+ content: finalResult.text
733
+ });
734
+ }
735
+ const result = {
736
+ childMessages,
737
+ result: finalResult?.text || ""
738
+ };
739
+ console.log("json", json);
740
+ const nextMessage = {
741
+ role: "assistant",
742
+ parts: [
743
+ {
744
+ type: "dynamic-tool",
745
+ toolCallId: primitiveId,
746
+ toolName: primitiveId,
747
+ state: "output-available",
748
+ input: json.input,
749
+ output: result
750
+ }
751
+ ],
752
+ id: message.id,
753
+ metadata: {
754
+ ...message.metadata,
755
+ mode: "network",
756
+ selectionReason,
757
+ agentInput: json.input,
758
+ from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
759
+ }
760
+ };
761
+ return nextMessage;
762
+ }
763
+ } catch (error) {
764
+ return message;
765
+ }
766
+ }
767
+ return message;
768
+ });
769
+ };
770
+ const resolveToChildMessages = (messages) => {
771
+ const assistantMessage = messages.find((message) => message.role === "assistant");
772
+ if (!assistantMessage) return [];
773
+ const parts = assistantMessage.parts;
774
+ let childMessages = [];
775
+ for (const part of parts) {
776
+ const toolPart = part;
777
+ if (part.type.startsWith("tool-")) {
778
+ const toolName = part.type.substring("tool-".length);
779
+ const isWorkflow = toolName.startsWith("workflow-");
780
+ childMessages.push({
781
+ type: "tool",
782
+ toolCallId: toolPart.toolCallId,
783
+ toolName,
784
+ args: toolPart.input,
785
+ toolOutput: isWorkflow ? { ...toolPart.output?.result, runId: toolPart.output?.runId } : toolPart.output
786
+ });
787
+ }
788
+ if (part.type === "text") {
789
+ childMessages.push({
790
+ type: "text",
791
+ content: toolPart.text
792
+ });
793
+ }
794
+ }
795
+ return childMessages;
796
+ };
797
+
550
798
  class AISdkNetworkTransformer {
551
799
  transform({ chunk, conversation, metadata }) {
552
800
  const newConversation = [...conversation];
@@ -919,92 +1167,63 @@ class AISdkNetworkTransformer {
919
1167
  };
920
1168
  }
921
1169
 
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;
1170
+ const fromCoreUserMessageToUIMessage = (coreUserMessage) => {
1171
+ const id = `user-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1172
+ const parts = typeof coreUserMessage.content === "string" ? [
1173
+ {
1174
+ type: "text",
1175
+ text: coreUserMessage.content
1176
+ }
1177
+ ] : coreUserMessage.content.map((part) => {
1178
+ switch (part.type) {
1179
+ case "text": {
1180
+ return {
1181
+ type: "text",
1182
+ text: part.text
1183
+ };
1184
+ }
1185
+ case "image": {
1186
+ const url = typeof part.image === "string" ? part.image : part.image instanceof URL ? part.image.toString() : "";
1187
+ return {
1188
+ type: "file",
1189
+ mediaType: part.mimeType ?? "image/*",
1190
+ url
1191
+ };
1192
+ }
1193
+ case "file": {
1194
+ const url = typeof part.data === "string" ? part.data : part.data instanceof URL ? part.data.toString() : "";
1195
+ return {
1196
+ type: "file",
1197
+ mediaType: part.mimeType,
1198
+ url,
1199
+ ...part.filename !== void 0 ? { filename: part.filename } : {}
1200
+ };
1201
+ }
1202
+ default: {
1203
+ const exhaustiveCheck = part;
1204
+ throw new Error(`Unhandled content part type: ${exhaustiveCheck.type}`);
993
1205
  }
994
1206
  }
995
- return message;
996
1207
  });
1208
+ return {
1209
+ id,
1210
+ role: "user",
1211
+ parts
1212
+ };
997
1213
  };
998
1214
 
999
1215
  const useChat = ({ agentId, initializeMessages }) => {
1216
+ const _currentRunId = useRef(void 0);
1217
+ const _onChunk = useRef(void 0);
1000
1218
  const [messages, setMessages] = useState(
1001
1219
  () => resolveInitialMessages(initializeMessages?.() || [])
1002
1220
  );
1221
+ const [toolCallApprovals, setToolCallApprovals] = useState({});
1003
1222
  const baseClient = useMastraClient();
1004
1223
  const [isRunning, setIsRunning] = useState(false);
1005
1224
  const generate = async ({
1006
1225
  coreUserMessages,
1007
- runtimeContext,
1226
+ requestContext,
1008
1227
  threadId,
1009
1228
  modelSettings,
1010
1229
  signal,
@@ -1042,7 +1261,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1042
1261
  topP
1043
1262
  },
1044
1263
  instructions,
1045
- runtimeContext,
1264
+ requestContext,
1046
1265
  ...threadId ? { threadId, resourceId: agentId } : {},
1047
1266
  providerOptions
1048
1267
  });
@@ -1058,7 +1277,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1058
1277
  setMessages((prev) => [...prev, ...mastraUIMessages]);
1059
1278
  }
1060
1279
  };
1061
- const stream = async ({ coreUserMessages, runtimeContext, threadId, onChunk, modelSettings, signal }) => {
1280
+ const stream = async ({ coreUserMessages, requestContext, threadId, onChunk, modelSettings, signal }) => {
1062
1281
  const {
1063
1282
  frequencyPenalty,
1064
1283
  presencePenalty,
@@ -1069,7 +1288,8 @@ const useChat = ({ agentId, initializeMessages }) => {
1069
1288
  topP,
1070
1289
  instructions,
1071
1290
  providerOptions,
1072
- maxSteps
1291
+ maxSteps,
1292
+ requireToolApproval
1073
1293
  } = modelSettings || {};
1074
1294
  setIsRunning(true);
1075
1295
  const clientWithAbort = new MastraClient({
@@ -1077,9 +1297,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1077
1297
  abortSignal: signal
1078
1298
  });
1079
1299
  const agent = clientWithAbort.getAgent(agentId);
1300
+ const runId = agentId;
1080
1301
  const response = await agent.stream({
1081
1302
  messages: coreUserMessages,
1082
- runId: agentId,
1303
+ runId,
1083
1304
  maxSteps,
1084
1305
  modelSettings: {
1085
1306
  frequencyPenalty,
@@ -1091,19 +1312,16 @@ const useChat = ({ agentId, initializeMessages }) => {
1091
1312
  topP
1092
1313
  },
1093
1314
  instructions,
1094
- runtimeContext,
1315
+ requestContext,
1095
1316
  ...threadId ? { threadId, resourceId: agentId } : {},
1096
- providerOptions
1317
+ providerOptions,
1318
+ requireToolApproval
1097
1319
  });
1098
- if (!response.body) {
1099
- setIsRunning(false);
1100
- throw new Error("[Stream] No response body");
1101
- }
1320
+ _onChunk.current = onChunk;
1321
+ _currentRunId.current = runId;
1102
1322
  await response.processDataStream({
1103
1323
  onChunk: async (chunk) => {
1104
- flushSync(() => {
1105
- setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1106
- });
1324
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1107
1325
  onChunk?.(chunk);
1108
1326
  }
1109
1327
  });
@@ -1111,7 +1329,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1111
1329
  };
1112
1330
  const network = async ({
1113
1331
  coreUserMessages,
1114
- runtimeContext,
1332
+ requestContext,
1115
1333
  threadId,
1116
1334
  onNetworkChunk,
1117
1335
  modelSettings,
@@ -1137,30 +1355,71 @@ const useChat = ({ agentId, initializeMessages }) => {
1137
1355
  topP
1138
1356
  },
1139
1357
  runId: agentId,
1140
- runtimeContext,
1358
+ requestContext,
1141
1359
  ...threadId ? { thread: threadId, resourceId: agentId } : {}
1142
1360
  });
1143
1361
  const transformer = new AISdkNetworkTransformer();
1144
1362
  await response.processDataStream({
1145
1363
  onChunk: async (chunk) => {
1146
- flushSync(() => {
1147
- setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1148
- });
1364
+ setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1149
1365
  onNetworkChunk?.(chunk);
1150
1366
  }
1151
1367
  });
1152
1368
  setIsRunning(false);
1153
1369
  };
1370
+ const handleCancelRun = () => {
1371
+ setIsRunning(false);
1372
+ _currentRunId.current = void 0;
1373
+ _onChunk.current = void 0;
1374
+ };
1375
+ const approveToolCall = async (toolCallId) => {
1376
+ const onChunk = _onChunk.current;
1377
+ const currentRunId = _currentRunId.current;
1378
+ if (!currentRunId)
1379
+ return console.info("[approveToolCall] approveToolCall can only be called after a stream has started");
1380
+ setIsRunning(true);
1381
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "approved" } }));
1382
+ const agent = baseClient.getAgent(agentId);
1383
+ const response = await agent.approveToolCall({ runId: currentRunId, toolCallId });
1384
+ await response.processDataStream({
1385
+ onChunk: async (chunk) => {
1386
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1387
+ onChunk?.(chunk);
1388
+ }
1389
+ });
1390
+ setIsRunning(false);
1391
+ };
1392
+ const declineToolCall = async (toolCallId) => {
1393
+ const onChunk = _onChunk.current;
1394
+ const currentRunId = _currentRunId.current;
1395
+ if (!currentRunId)
1396
+ return console.info("[declineToolCall] declineToolCall can only be called after a stream has started");
1397
+ setIsRunning(true);
1398
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "declined" } }));
1399
+ const agent = baseClient.getAgent(agentId);
1400
+ const response = await agent.declineToolCall({ runId: currentRunId, toolCallId });
1401
+ await response.processDataStream({
1402
+ onChunk: async (chunk) => {
1403
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1404
+ onChunk?.(chunk);
1405
+ }
1406
+ });
1407
+ setIsRunning(false);
1408
+ };
1154
1409
  const sendMessage = async ({ mode = "stream", ...args }) => {
1155
1410
  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 }] }]);
1411
+ const coreUserMessages = [nextMessage];
1412
+ if (args.coreUserMessages) {
1413
+ coreUserMessages.push(...args.coreUserMessages);
1414
+ }
1415
+ const uiMessages = coreUserMessages.map(fromCoreUserMessageToUIMessage);
1416
+ setMessages((s) => [...s, ...uiMessages]);
1158
1417
  if (mode === "generate") {
1159
- await generate({ ...args, coreUserMessages: messages2 });
1418
+ await generate({ ...args, coreUserMessages });
1160
1419
  } else if (mode === "stream") {
1161
- await stream({ ...args, coreUserMessages: messages2 });
1420
+ await stream({ ...args, coreUserMessages });
1162
1421
  } else if (mode === "network") {
1163
- await network({ ...args, coreUserMessages: messages2 });
1422
+ await network({ ...args, coreUserMessages });
1164
1423
  }
1165
1424
  };
1166
1425
  return {
@@ -1168,7 +1427,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1168
1427
  sendMessage,
1169
1428
  isRunning,
1170
1429
  messages,
1171
- cancelRun: () => setIsRunning(false)
1430
+ approveToolCall,
1431
+ declineToolCall,
1432
+ cancelRun: handleCancelRun,
1433
+ toolCallApprovals
1172
1434
  };
1173
1435
  };
1174
1436
 
@@ -1487,5 +1749,5 @@ const MessageStreaming = ({ className, ...props }) => {
1487
1749
  return /* @__PURE__ */ jsx("span", { className: className || MessageStreamingClass, ...props });
1488
1750
  };
1489
1751
 
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 };
1752
+ 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
1753
  //# sourceMappingURL=index.js.map